/**
 * Copyright (c) 2005-2012 EBM WebSourcing, 2007-2009 Capgemini Sud, 2012-2022 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.plugin.jbiplugin;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.xml.namespace.QName;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.ow2.easywsdl.extensions.wsdl4complexwsdl.WSDL4ComplexWsdlFactory;
import org.ow2.easywsdl.extensions.wsdl4complexwsdl.api.Description;
import org.ow2.easywsdl.extensions.wsdl4complexwsdl.api.ImportedDocuments;
import org.ow2.easywsdl.extensions.wsdl4complexwsdl.api.WSDL4ComplexWsdlWriter;
import org.ow2.easywsdl.schema.api.absItf.AbsItfSchema;
import org.ow2.easywsdl.wsdl.api.WSDLException;
import org.ow2.easywsdl.wsdl.api.abstractItf.AbsItfDescription;
import org.ow2.petals.component.framework.jbidescriptor.generated.ComponentInterceptor;
import org.ow2.petals.component.framework.jbidescriptor.generated.Param;
import org.ow2.petals.component.framework.jbidescriptor.generated.SUInterceptor;
import org.ow2.petals.jbi.descriptor.JBIDescriptorException;
import org.ow2.petals.jbi.descriptor.extension.JBIDescriptorExtensionBuilder;
import org.ow2.petals.jbi.descriptor.extension.exception.NoComponentNameDeployableServiceUnitException;
import org.ow2.petals.jbi.descriptor.extension.exception.NotServiceUnitException;
import org.ow2.petals.jbi.descriptor.original.generated.Component.SharedLibrary;
import org.ow2.petals.jbi.descriptor.original.generated.Jbi;
import org.w3c.dom.Document;

import com.ebmwebsourcing.easycommons.xml.Transformers;

/**
 * This class is used to give the main configuration parameters of all JBI goals needing artifact configuration.
 * @author Christophe Deneux - Capgemini Sud
 */
public abstract class JBIAbstractConfigurableMojo extends JBIAbstractMojo {

    protected static final String VERSION_MINOR = "version.minor";

    protected static final String VERSION_MAJOR = "version.major";

    /**
     * Flag to activate JBI archive configuration when packaging it. If JBI
     * identifiers mapping configuration file is not found, no configuration is
     * applied.
     */
    @Parameter(required = true, property = "includeConfiguration", defaultValue = "true")
    protected boolean includeConfiguration;

    /**
     * <p>
     * If the JBI identifier of a shared library inside a JBI component must be computed, sets the mapping pattern of
     * the all shared library identifiers to used inside the JBI descriptor of a component.
     * </p>
     * <p>
     * Example of usage (caution to the usage of "$" and "$$"):
     * <code>&lt;sharedLibraryNameMappingInComponent&gt;$${artifactId}&lt;/sharedLibraryNameMappingInComponent&gt;</code>
     * </p>
     * <p>
     * Some extra pattern are defined for a version expressed as "major.minor.maintenance":
     * </p>
     * <ul>
     * <li>"version.major" is the major part of the version,</li>
     * <li>"version.minor" is the minor part of the version.</li>
     * </ul>
     */
    @Parameter(required = true, defaultValue = "$${artifactId}")
    protected String sharedLibraryNameMappingInComponent;

    /**
     * <p>
     * JBI identifiers mapping configuration file. Must be available through the plugin classpath.
     * </p>
     * <p>
     * Each file line contains a key and a value. The value is used as expression defining the JBI identifier of the
     * artifact matching the key.
     * </p>
     * <p>
     * The key is composed of 4 mandatory fields separated by ":" (caution to use the escape character), each field can
     * contain the value "*" to match any value:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version,</li>
     * <li>packaging: one of jbi-component, jbi-shared-library, jbi-service-unit, jbi-service-assembly.</li>
     * </ol>
     * <p>
     * Example, the following mapping rules define that all component identifiers contain the major version part except
     * for the BC Soap:
     * </p>
     * <ul>
     * <li><code>org.ow2.petals\:petals-bc-soap\:*\:jbi-component = ${artifactId}</code> ,</li>
     * <li><code>*\:*\:*\:jbi-component = ${artifactId}-${version.major}</code></li>
     * </ul>
     */
    @Parameter(property = "jbiIdentifiersMappingFile", defaultValue = "jbi-identifiers-mapping-file.properties")
    protected String jbiIdentifiersMappingFile;

    /**
     * JBI identifiers mapping configuration file. If it does not exist through the classpath, the file is look for
     * according to this URL.
     * 
     * @see #jbiIdentifiersMappingFile
     */
    @Parameter(property = "jbiIdentifiersMappingFileURL")
    protected URL jbiIdentifiersMappingFileURL;

    /**
     * Content of the JBI identifiers mapping configuration file as properties.
     */
    final private Properties jbiIdentifiersMappingExpressions = new Properties();

    /**
     * JBI shared library list mapping configuration file.
     */
    @Parameter(property = "jbiSharedLibrariesMappingFile", defaultValue = "jbi-shared-libraries-list-mapping-file.properties")
    protected String jbiSharedLibrariesMappingFile;

    /**
     * JBI shared library list mapping configuration file. If it does not exist through the classpath, the file is look
     * for according to this URL.
     * 
     * @see #jbiSharedLibrariesMappingFile
     */
    @Parameter(property = "jbiSharedLibrariesMappingFileURL")
    protected URL jbiSharedLibrariesMappingFileURL;

    /**
     * Content of the JBI shared libraries mapping configuration file as properties.
     */
    final private Properties jbiSharedLibrariesMappingExpressions = new Properties();

    /**
     * <p>
     * JBI shared library list mapping configuration file. Must be available through the plugin classpath.
     * </p>
     * <p>
     * Each file line contains a key and a value. The value is used as a Maven artifact to use as shared library by the
     * artifact matching the key. Use one line per shared library.
     * </p>
     * <p>
     * The key is composed of 4 mandatory fields separated by ":" (caution to use the escape character), each field
     * (except the fourth) can contain the value "*" to match any value:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version,</li>
     * <li>ordering number: in case of several shared library this field will define the declaration order of shared
     * libraries. In case of only one sahred library use the value "1".</li>
     * </ol>
     * <p>
     * The value is composed of 3 mandatory fields separated by ":" defining a Maven artifact to use as shared library:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version.</li>
     * </ol>
     * <p>
     * Example, the following mapping rules define that all versions of the BC JMS will use the shared library including
     * the ActiveMQ JMS client and an other one:
     * </p>
     * <ul>
     * <li><code>org.ow2.petals\:petals-bc-jms\:*\:1 = org.ow2.petals:petals-sl-jms-activemq:5.2.0</code></li>
     * <li><code>org.ow2.petals\:petals-bc-jms\:*\:2 = org.ow2.petals:petals-sl-jms-otherjmsprovider:1.0.0</code></li>
     * </ul>
     * 
     */
    @Parameter(property = "jbiVersionsMappingFile", defaultValue = "jbi-versions-mapping-file.properties")
    protected String jbiVersionsMappingFile;

    /**
     * JBI versions mapping configuration file. If it does not exist through the
     * classpath, the file is look for according to this URL.
     * 
     * @see #jbiIdentifiersMappingFile
     */
    @Parameter(property = "jbiVersionsMappingFileURL")
    protected URL jbiVersionsMappingFileURL;

    /**
     * Content of the JBI versions mapping configuration file as properties.
     */
    final private Properties jbiVersionsMappingExpressions = new Properties();

    /**
     * 
     * <p>
     * Extra component classpath elements list mapping configuration file. If interceptor exists in this extra component
     * classpath elements, it is added to the component configuration.
     * </p>
     * <p>
     * See {@link #componentInterceptorCustomizationFile} to customize the interceptor configuration in the component.
     * </p>
     * <p>
     * Each file line contains a key and a value. The value is used as a Maven artifact to use as extra classpath
     * elements by the artifact matching the key. Use one line per extra classpath element.
     * </p>
     * <p>
     * The key is composed of 4 mandatory fields separated by ":" (caution to use the escape character), each field
     * (except the fourth) can contain the value "*" to match any value:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version,</li>
     * <li>ordering number: in case of several artifacts completing the classpath elements, this field will define the
     * declaration order of artifact. In case of only one artifact use the value "1".</li>
     * </ol>
     * <p>
     * The value is composed of 3 mandatory fields separated by ":" defining a Maven artifact to use as extra classpath
     * elements:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version.</li>
     * </ol>
     * <p>
     * Example, the following mapping rules define that all versions of the BC SOAP will use the extra classpath
     * elements provided by all dependencies of the artifact com.foo.bar:foo-bar:1.2.0:
     * </p>
     * <ul>
     * <li><code>org.ow2.petals\:petals-bc-soap\:*\:1 = com.foo.bar:foo-bar:1.2.0</code></li>
     * <li><code>org.ow2.petals\:petals-bc-jms\:*\:2 = org.ow2.petals:petals-sl-jms-otherjmsprovider:1.0.0</code></li>
     * </ul>
     * 
     */
    @Parameter(property = "jbiExtraComponentClasspathMappingFile", defaultValue = "jbi-extra-component-classpath-mapping-file.properties")
    protected String jbiExtraComponentClasspathMappingFile;

    /**
     * Extra component classpath elements list mapping configuration file. If it does not exist through the classpath,
     * the file is looked for according to this URL.
     *
     * @see #jbiExtraComponentClasspathMappingFile
     */
    @Parameter(property = "jbiExtraComponentClasspathMappingURL")
    protected URL jbiExtraComponentClasspathMappingFileURL;

    /**
     * Content of the extra component classpath elements list mapping configuration file.
     */
    final private Properties jbiExtraComponentClasspathMappingExpressions = new Properties();

    /**
     * <p>
     * Extra bootstrap classpath elements list mapping configuration file. Must be available through the plugin
     * classpath.
     * </p>
     * <p>
     * Each file line contains a key and a value. The value is used as a Maven artifact to use as extra classpath
     * elements by the artifact matching the key. Use one line per extra classpath element.
     * </p>
     * <p>
     * The key is composed of 4 mandatory fields separated by ":" (caution to use the escape character), each field
     * (except the fourth) can contain the value "*" to match any value:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version,</li>
     * <li>ordering number: in case of several artifacts completing the classpath elements, this field will define the
     * declaration order of artifact. In case of only one artifact use the value "1".</li>
     * </ol>
     * <p>
     * The value is composed of 3 mandatory fields and 1 optional field separated by ":" defining a Maven artifact to
     * use as extra classpath elements:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version,</li>
     * <li>packaging (optional, default is 'jar').</li>
     * </ol>
     * <p>
     * Example, the following mapping rules define that all versions of the BC SOAP will use the extra classpath
     * elements provided by all dependencies of the artifact com.foo.bar:foo-bar:1.2.0 and artifact
     * com.foo.bar:foo-resources:1.2.0:zip :
     * </p>
     * <ul>
     * <li><code>org.ow2.petals\:petals-bc-soap\:*\:1 = com.foo.bar:foo-bar:1.2.0</code></li>
     * <li><code>org.ow2.petals\:petals-bc-soap\:*\:2 = com.foo.bar:foo-resources:1.2.0:zip</code></li>
     * </ul>
     * 
     */
    @Parameter(property = "jbiExtraBootstrapClasspathMappingFile", defaultValue = "jbi-extra-bootstrap-classpath-mapping-file.properties")
    protected String jbiExtraBootstrapClasspathMappingFile;

    /**
     * Extra bootstrap classpath elements list mapping configuration file. If it does not exist through the classpath,
     * the file is looked for according to this URL.
     * 
     * @see #jbiExtraBootstrapClasspathMappingFile
     */
    @Parameter(property = "jbiExtraBootstrapClasspathMappingURL")
    protected URL jbiExtraBootstrapClasspathMappingFileURL;

    /**
     * <p>
     * Component interceptor customization file containing customization of interceptors to package into JBI components.
     * </p>
     * <p>
     * Note: All jars embedded into the JBI component are intropected to discover available interceptors, and each
     * interceptor are automaticaly declared in the JBI component.
     * </p>
     * <p>
     * The default interceptor declaration is:
     * </p>
     * <ul>
     * <li>interceptor name: interceptor class name without package</li>
     * <li>activation state: <code>false</code></li>
     * </ul>
     * <p>
     * Each file line contains a key and a value. The value is used as a Maven artifact to identify the interceptor to
     * packaged in JBI components. Use one line per interceptor to declare in a JBI component.
     * </p>
     * <p>
     * The key is composed of 4 mandatory fields separated by ":" (caution to use the escape character) to identify th
     * JBI component in which interceptors will be packaged, each field (except the fourth) can contain the value "*" to
     * match any value:
     * </p>
     * <ol>
     * <li>groupId,</li>
     * <li>artifactId,</li>
     * <li>version,</li>
     * <li>ordering number: in case of several artifacts completing the classpath elements, this field will define the
     * declaration order of artifact. In case of only one artifact use the value "1".</li>
     * </ol>
     * <p>
     * The value is composed of 3 mandatory fields following by optional fields separated by ":" customizing the
     * interceptor:
     * </p>
     * <ol>
     * <li>interceptor class: it's the full class name of the interceptor, used as key to associate the following
     * customization,</li>
     * <li>interceptor name: name of the interceptor,</li>
     * <li>activation: <code>true</code> activates the interceptor at component level.</li>
     * <li>
     * <li>interceptor parameters list as: param-name-1:param-value-1:param-name-2:param-value-2:...</li>
     * </ol>
     * <p>
     * Example, the following declaration rules customize the interceptor configuration with specific interceptor name
     * and activation states :
     * </p>
     * <ul>
     * <li>
     * <code>org.ow2.petals\:petals-bc-soap\:1 = foo.bar.MyInterceptor:MyCustomInterceptorNameNotActivated:false:paramName1:paramValue1:paramName2:paramValue2:...</code>
     * </li>
     * <li>
     * <code>org.ow2.petals\:petals-bc-soap\:2 = foo.bar.My2ndInterceptor:MyCustomInterceptorNameActivated:true:paramName1:paramValue1</code>
     * </li>
     * </ul>
     * 
     */
    @Parameter(property = "componentInterceptorCustomizationFile", defaultValue = "component-interceptors-customization.properties")
    protected String componentInterceptorCustomizationFile;

    /**
     * Component interceptor customization file. If it does not exist through
     * the classpath, the file is look for according to this URL.
     * 
     * @see #componentInterceptorCustomizationFile
     */
    @Parameter(property = "componentInterceptorCustomizationFileURL")
    protected URL componentInterceptorCustomizationFileURL;

    /**
     * Content of the component interceptors customization file.
     */
    final private Properties componentInterceptorCustomizationExpressions = new Properties();

    /**
     * <p>
     * Service interceptor customization file containing customization of interceptors to set into service-unit.
     * </p>
     * <p>
     * Each file line contains a key and a value. The value is used to defined the interceptor configuration to apply on
     * phase identified by the key.
     * </p>
     * <p>
     * The key is composed of 7 mandatory fields separated by ":" (caution to use the escape character) to identify the
     * phase on which the interception occurs:
     * </p>
     * <ol>
     * <li>configuration name</li>
     * <li>service unit type: possible values are: <code>provider</code>, <code>consumer</code>,</li>
     * <li>interface name: interface name of the provider or consumer</li>
     * <li>service name: service name of the provider or consumer</li>
     * <li>endpoint name: endpoint name of the provider or consumer</li>
     * <li>phase name: possible values are: <code>accept</code>, <code>accept-response</code>, <code>send</code> and
     * <code>send-response</code>,</li>
     * <li>ordering number: in case of several interceptor to define on one phase, this field will define the
     * declaration order of interceptor. In case of only one, use the value "1".</li>
     * </ol>
     * <p>
     * The value is composed of 1 mandatory field following by optional fields separated by ":" customizing the
     * interceptor:
     * </p>
     * <ol>
     * <li>interceptor name: name of the interceptor defined at component level,</li>
     * <li>interceptor parameters list as: param-name-1:param-value-1:param-name-2:param-value-2:...</li>
     * </ol>
     * <p>
     * Example, the following declaration rules customize the interceptor configuration with specific interceptor name
     * and activation states :
     * </p>
     * <ul>
     * <li>
     * <code>configNameA\:provider\:*\:*\:*\:accept\:1 = MyCustomInterceptorNameNotActivated:paramName1:paramValue1:paramName2:paramValue2:...</code>
     * </li>
     * <li>
     * <code>configNameA\:provider\:*\:*\:*\:accept\:2 = MyCustomInterceptorNameActivated:paramName1:paramValue1</code>
     * </li>
     * <li>
     * <code>configNameA\:provider\:*\:*\:*\:accept-response\:1 = MyCustomInterceptorNameNotActivated:paramName1:paramValue1:paramName2:paramValue2:...</code>
     * </li>
     * <li>
     * <code>configNameA\:provider\:*\:*\:*\:accept-response\:2 = MyCustomInterceptorNameActivated:paramName1:paramValue1</code>
     * </li>
     * <li><code>configNameA\:provider\:*\:*\:*\:send\:1 = ...</code></li>
     * <li><code>configNameA\:provider\:*\:*\:*\:send-response\:1 = ...</code></li>
     * </ul>
     * 
     */
    @Parameter(property = "servcieInterceptorCustomizationFile", defaultValue = "service-interceptors-customization.properties")
    protected String serviceInterceptorCustomizationFile;
    
    /**
     * Service interceptor customization file. If it does not exist through
     * the classpath, the file is look for according to this URL.
     * 
     * @see #serviceInterceptorCustomizationFile
     */
    @Parameter(property = "serviceInterceptorCustomizationFileURL")
    protected URL serviceInterceptorCustomizationFileURL;
    
    
    /**
     * Service interceptor configuration name to use to configure interceptors of service units.
     * 
     * @see #serviceInterceptorCustomizationFile
     */
    @Parameter(property = "serviceInterceptionConfigurationName")
    protected String serviceInterceptionConfigurationName;

    /**
     * Content of the servcie interceptors customization file.
     */
    final private Properties serviceInterceptorCustomizationExpressions = new Properties();


    /**
     * Content of the extra bootstrap classpath elements list mapping configuration file.
     */
    final private Properties jbiExtraBootstrapClasspathMappingExpressions = new Properties();
    
    /**
     * If true, imports used in the WSDL of an SU will be resolved and packaged.
     */
    @Parameter(property = "downloadAndPackageWsdlResources", defaultValue = "false")
    protected boolean downloadAndPackageWsdlResources;

    /***
     * <p>
     * Compute the JBI identifier of the artifact according to:
     * </p>
     * <ul>
     * <li>the artifact match a pattern according to:
     * <ul>
     * <li>the configuration mode (<code>includeConfiguration</code>)</li>
     * <li>the artifact matches a pattern in the JBI identifiers mapping configuration file (
     * <code>jbiIdentifiersMappingFile</code>)</li>
     * </ul>
     * </li>
     * <li>a default expression (<code>expression</code>)</li>
     * </ul>
     * 
     * @param expression
     *            The default expression defining the JBI identifier of the artifact
     * @param artifact
     *            Artifact for which a JBI identifier must be defined
     * @return The computed JBI identifier
     * @throws InterpolationException
     */
    protected String evaluateJBIIdentifier(final String expression, final Artifact artifact)
            throws InterpolationException {

        String artifactJBIIdentifier = null;
        if (this.includeConfiguration) {
            artifactJBIIdentifier = this.getJbiDescriptorValue(artifact,
                    this.jbiIdentifiersMappingExpressions);
        }
        if (artifactJBIIdentifier == null) {
            artifactJBIIdentifier = this.evaluateFileNameMapping(expression, artifact);
        }

        return artifactJBIIdentifier;
    }

    /***
     * <p>
     * Compute the JBI version of the artifact according to:
     * </p>
     * <ul>
     * <li>the artifact match a pattern according to:
     * <ul>
     * <li>the configuration mode (<code>includeConfiguration</code>)</li>
     * <li>the artifact matches a pattern in the JBI versions mapping configuration file (
     * <code>jbiVersionsMappingFile</code>)</li>
     * </ul>
     * </li>
     * <li>a default expression (<code>expression</code>)</li>
     * </ul>
     * 
     * @param expression
     *            The default expression defining the JBI version of the artifact
     * @param artifact
     *            Artifact for which a JBI version must be defined
     * @return The computed JBI version
     * @throws InterpolationException
     */
    protected String evaluateJBIVersion(final String expression, final Artifact artifact)
            throws InterpolationException {

        String artifactJBIIdentifier = null;
        if (this.includeConfiguration) {
            artifactJBIIdentifier = this.getJbiDescriptorValue(artifact, this.jbiVersionsMappingExpressions);
        }
        if (artifactJBIIdentifier == null) {
            artifactJBIIdentifier = this.evaluateFileNameMapping(expression, artifact);
        }

        return artifactJBIIdentifier;
    }

    /***
     * <p>
     * Compute the JBI shared libraries list of a component according to:
     * </p>
     * <ul>
     * <li>
     * the artifact match a pattern according to:
     * <ul>
     * <li>the configuration mode (<code>includeConfiguration</code>)</li>
     * <li>the artifact matches a pattern in the JBI shared libraries list
     * mapping configuration file (<code>jbiSharedLibrariesMappingFile</code>)</li>
     * </ul>
     * </li>
     * <li>the default shared library list provided by the original POM file, if
     * existing, on which the mapping defined by the parameter
     * <code>sharedLibraryNameMappingInComponent</code> is applied.</li>
     * </ul>
     * 
     * @param artifact
     *            Artifact for which a JBI shared libraries list must be defined
     * @return The computed JBI shared libraries list
     */
    protected List<SharedLibrary> evaluateSharedLibraries(final Artifact artifact)
            throws MojoExecutionException {

        List<SharedLibrary> sharedLibraries = null;
        if (this.includeConfiguration) {
            this.debug("Use shared libraries defined at configuration level.");
            sharedLibraries = this.getSharedLibraries(artifact);
        }

        if (sharedLibraries == null) {
            this.debug("Use shared libraries defined at project level.");
            sharedLibraries = this.getSharedLibrariesFromProject();
        }

        return sharedLibraries;
    }

    /**
     * <p>
     * Compute the extra bootstrap classpath elements of a component according to:
     * </p>
     * <ul>
     * <li>
     * the artifact match a pattern according to:
     * <ul>
     * <li>the configuration mode (<code>includeConfiguration</code>)</li>
     * <li>the artifact matches a pattern in the JBI extra bootstrap classpath elements mapping configuration file (
     * <code>jbiExtraBootstrapClasspathMappingFile</code>, <code>jbiExtraBootstrapClasspathMappingFileURL</code>)</li>
     * </ul>
     * </li>
     * </ul>
     * 
     * @param artifact
     *            Artifact for which extra bootstrap classpath elements must be added
     * @return The computed bootstrap classpath elements list (full list, not only extra elements). List element is an
     *         {@link Artifact}.
     * @throws MojoExecutionException
     *             An error occurs during resolution of the extra bootstap class path elements.
     */
    protected final List<Artifact> evaluateBootstrapClasspathElts(final Artifact artifact)
            throws MojoExecutionException {
    	
        return this.evaluateClasspathElts(artifact, this.jbiExtraBootstrapClasspathMappingExpressions);
    }

    /**
     * <p>
     * Compute the extra component classpath elements of a component according to:
     * </p>
     * <ul>
     * <li>
     * the artifact match a pattern according to:
     * <ul>
     * <li>the configuration mode (<code>includeConfiguration</code>)</li>
     * <li>the artifact matches a pattern in the extra component classpath elements mapping configuration file (
     * <code>jbiExtraComponentClasspathMappingFile</code>, <code>jbiExtraComponentClasspathMappingFileURL</code>)</li>
     * </ul>
     * </li>
     * </ul>
     * 
     * @param artifact
     *            Artifact for which extra component classpath elements must be added
     * @return The computed component classpath elements list (full list, not only extra elements). List element is an
     *         {@link Artifact}.
     * @throws MojoExecutionException
     *             An error occurs during resolution of the extra bootstap class path elements.
     */
    protected final List<Artifact> evaluateComponentClasspathElts(final Artifact artifact)
            throws MojoExecutionException {
    	
        return this.evaluateClasspathElts(artifact, this.jbiExtraComponentClasspathMappingExpressions);
    }
    
    private List<Artifact> evaluateClasspathElts(final Artifact artifact,
            final Properties extraClasspathMappingExpression) throws MojoExecutionException {
    	
        try {
            final List<Artifact> extraClasspathEltsAsArtifact = new LinkedList<Artifact>();

            if (this.includeConfiguration) {
                final List<String> extraClasspathElts = JBIAbstractConfigurableMojo.getClasspathMappingExpression(
                        artifact,
                        extraClasspathMappingExpression);
                for (final String extraClasspathElt : extraClasspathElts) {

                    final StringTokenizer st = new StringTokenizer(extraClasspathElt, ":");
                    if (st.countTokens() < 3) {
                        throw new MojoExecutionException(
                                "Missing field in the extra classpath element definition, 3 fields are mandatory: "
                                        + extraClasspathElt);
                    }
                    final String groupId = st.nextToken();
                    final String artifactId = st.nextToken();
                    final String version = st.nextToken();
                    String packaging = "jar";
                    try {
                        packaging = st.nextToken();
                    } catch (final NoSuchElementException e) {
                        // NOP, we use the defautl value
                    }

                    final Artifact extraClasspathEltArtifact = this.artifactFactory.createDependencyArtifact(groupId,
                            artifactId, VersionRange.createFromVersionSpec(version), packaging, null, null);
                    this.artifactResolver.resolve(extraClasspathEltArtifact,
                            this.project.getRemoteArtifactRepositories(), this.localRepository);
                    extraClasspathEltsAsArtifact.add(extraClasspathEltArtifact);

                    this.addClasspathEltDependencies(extraClasspathEltArtifact, extraClasspathEltsAsArtifact);
                }
            }

            return extraClasspathEltsAsArtifact;
        } catch (final InvalidVersionSpecificationException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        } catch (final ArtifactResolutionException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        } catch (final ArtifactNotFoundException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        } catch (final ProjectBuildingException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    private void addClasspathEltDependencies(final Artifact extraClasspathEltArtifact,
            final List<Artifact> extraClasspathEltsAsArtifact) throws ProjectBuildingException,
            ArtifactResolutionException, ArtifactNotFoundException, InvalidVersionSpecificationException {

        // find all the dependencies of this artifact
        // (create a mavenproject from the artifact )
        final MavenProject dependencyProject = this.buildProjectFromArtifact(extraClasspathEltArtifact);
        final List<Dependency> subDependencies = dependencyProject.getDependencies();
        for (final Dependency dependencyDependency : subDependencies) {

            // Check if the dependency should be included
            final String scope = dependencyDependency.getScope();
            if (scope == null || (!Artifact.SCOPE_TEST.equals(scope) && !Artifact.SCOPE_PROVIDED.equals(scope))) {
                this.debug("Required     : " + dependencyDependency.getGroupId() + ":"
                        + dependencyDependency.getArtifactId() + ":" + dependencyDependency.getVersion()
                        + " (transitive dependency of " + extraClasspathEltArtifact.getArtifactId() + ":"
                        + extraClasspathEltArtifact.getVersion() + ")");

                final Artifact dependencyArtifact = this.createDependencyArtifact(dependencyDependency);
                this.artifactResolver.resolve(dependencyArtifact, this.project.getRemoteArtifactRepositories(),
                        this.localRepository);
                extraClasspathEltsAsArtifact.add(dependencyArtifact);
                this.addClasspathEltDependencies(dependencyArtifact, extraClasspathEltsAsArtifact);

            } else {
                this.debug("Not required : " + dependencyDependency.getGroupId() + ":"
                        + dependencyDependency.getArtifactId() + ":" + dependencyDependency.getVersion()
                        + " (transitive dependency of " + extraClasspathEltArtifact.getArtifactId() + ":"
                        + extraClasspathEltArtifact.getVersion() + ")");
            }
        }

    }

    /**
     * <p>
     * Compute the customization of a component interceptor according to:
     * </p>
     * <ul>
     * <li>the configuration mode (<code>includeConfiguration</code>)</li>
     * <li>the component artifact matches a pattern in the interceptor customization file (
     * <code>interceptorCustomizationFile</code>, <code>interceptorCustomizationFileURL</code>)</li>
     * <li>the interceptor matches a pattern in the interceptor customization file (
     * <code>interceptorCustomizationFile</code>, <code>interceptorCustomizationFileURL</code>)</li>
     * </ul>
     * 
     * @param artifact
     *            Component artifact for which the interceptor configuration is to be customized.
     * @param componentInterceptor
     *            Interceptor for which the interceptor configuration is to be customized.
     * @throws MojoExecutionException
     *             An error occurs during resolution of the interceptor customization.
     */
    protected final void evaluateComponentInterceptor(final Artifact artifact, final ComponentInterceptor componentInterceptor)
            throws MojoExecutionException {
    	
        this.evaluateComponentInterceptor(artifact, componentInterceptor, this.componentInterceptorCustomizationExpressions);
    }
    
    private void evaluateComponentInterceptor(final Artifact artifact, final ComponentInterceptor componentInterceptor,
            final Properties interceptorCustomizationExpressions) throws MojoExecutionException {
	
    	if (this.includeConfiguration) {
            final String interceptorCustomizationExpr = JBIAbstractConfigurableMojo.getInterceptorCustomization(
                    artifact,
                    componentInterceptor,
                    interceptorCustomizationExpressions);
            
            if (interceptorCustomizationExpr != null) {
                final StringTokenizer st = new StringTokenizer(interceptorCustomizationExpr, ":");
                if (st.countTokens() < 3) {
                    throw new MojoExecutionException(
                            "Missing field in the interceptor customization definition, 3 fields are mandatory: "
                                    + interceptorCustomizationExpr);
                }
                st.nextToken(); // We skip the interceptor class name because it's the key to find the interceptor customization
                final String interceptorName = st.nextToken();
                final String interceptorState = st.nextToken();
                
                componentInterceptor.setActive(Boolean.parseBoolean(interceptorState));
                componentInterceptor.setName(interceptorName);
                
                if (st.hasMoreTokens()) {
                	final List<Param> params = componentInterceptor.getParam();
                	while (st.hasMoreTokens()) {
                		final String paramName = st.nextToken();
                		Param param = null;
                		for (final Param existingParam : params) {
                			if (existingParam.getName().equals(paramName)) {
                				param = existingParam;
                				break;
                			}
                		}
                		if (param == null) {
                			param = new Param();
                			param.setName(paramName);
                			params.add(param);
                		}

                		try {
                            final String paramValue = st.nextToken();
                            param.setValue(paramValue);
                        } catch (final NoSuchElementException e) {
                            // NOP, we use the default value
                        }
                	}
                }
            }
        }
    }

    /**
     * Find expressions defining an interceptor customization.
     * 
     * @return The interceptor customization as String, or <code>null</code> if not found.
     */
    private final static String getInterceptorCustomization(final Artifact artifact, final ComponentInterceptor componentInterceptor,
            final Properties interceptorCustomizationExpressions) throws MojoExecutionException {

        final String artifactKeys[] = JBIAbstractConfigurableMojo.getArtifactPatternWithoutPackaging(artifact);
        final List<String> interceptorCustomizationExprList = new ArrayList<String>();
        final Properties localInterceptorCustomizationExpressions = new Properties();
        localInterceptorCustomizationExpressions.putAll(interceptorCustomizationExpressions);

        for (final String artifactKey : artifactKeys) {
            // Loop over patterns generated from the artifact
            List<String> removedKeys = new ArrayList<String>();
            for (final Map.Entry<Object, Object> entry : localInterceptorCustomizationExpressions.entrySet()) {
                final String key = (String) entry.getKey();

                // We must remove the field "ordering number" before to compare
                // with an artifact pattern
                if (key.substring(0, key.lastIndexOf(':')).equals(artifactKey)) {
                    // We have found a component mapping line
                	interceptorCustomizationExprList.add(localInterceptorCustomizationExpressions.getProperty(key));
                    removedKeys.add(key);
                }
            }
            for (String key : removedKeys) {
            	localInterceptorCustomizationExpressions.remove(key);
            }
            removedKeys.clear();
        }
        
        final String interceptorClazz = componentInterceptor.getClazz();
    	for (final String interceptorCustomizationExpr : interceptorCustomizationExprList) {
        	// We compare the field "class name" to get the interceptor customization
            if (interceptorCustomizationExpr.substring(0, interceptorCustomizationExpr.indexOf(':')).equals(interceptorClazz)) {
                // We have found the customization of our interceptor
            	return interceptorCustomizationExpr;
            }
        }

        return null;
    }

    /**
     * Returns the MavenProject associated to the artifact to configure. In case of the goal "jbi-package", it's the
     * project itself. In case of the goal "jbi-configure", it's the project associated to the provided artifact.
     * 
     * @return
     */
    protected abstract MavenProject getMavenProject();

    /**
     * Evaluate an expression replacing artifact properties by their values.
     * 
     * @param expression
     *            Expression containing artifact property names
     * @param artifact
     *            Artifact containing property values
     * @return
     * @throws InterpolationException
     */
    private String evaluateFileNameMapping(final String expression, final Artifact artifact)
            throws InterpolationException {

        Properties props = new Properties();

        // Extact version parts of the artifact version
        setVersionElementInProperties(artifact, props);

        return evaluateFileNameMapping(expression, artifact, props);
    }

    private static final void setVersionElementInProperties(final Artifact artifact, final Properties props) {

        // We remove the substring '-SNAPSHOT' in the version
        final String artifactVersion;
        if (artifact.isSnapshot()) {
            final String baseVersion = artifact.getBaseVersion();
            artifactVersion = baseVersion.substring(0, baseVersion.length() - "-SNAPSHOT".length());
        } else {
            artifactVersion = artifact.getBaseVersion();
        }

        if (artifactVersion.contains(".")) {
            setVersionElementInPropertiesForSeparator(artifactVersion, props, "\\.");
        } else if (artifactVersion.contains("-")) {
            setVersionElementInPropertiesForSeparator(artifactVersion, props, "-");
        } else {
            props.put(VERSION_MAJOR, artifactVersion);
            props.put(VERSION_MINOR, "");
        }
    }

    /**
     * Split {@code artifactVersion} with separator and set minor and major version in properties
     *
     * @param artifactVersion
     *            Non-snapshot base version of the artifact to split. <b>The version MUST contain at least one instance
     *            of the separator.</b>
     * @param props
     *            properties to append versions
     * @param separatorRegexp
     *            Regexp string element who separates each element version.
     */
    private static final void setVersionElementInPropertiesForSeparator(final String artifactVersion,
            final Properties props, final String separatorRegexp) {

        assert !artifactVersion.contains(DefaultArtifact.SNAPSHOT_VERSION);

        final String[] versions = artifactVersion.split(separatorRegexp);
        assert versions.length > 1;

        props.put(VERSION_MAJOR, versions[0]);
        props.put(VERSION_MINOR, versions[1]);
    }

    /**
     * Compute a JBI descriptor value according to a mapping pattern associated to the MAven artifact in mapping
     * configuration files.
     * 
     * @return JBI descriptor value of the artifact, <code>null</code> if not match found.
     * @throws InterpolationException
     */
    private String getJbiDescriptorValue(final Artifact artifact, final Properties jbiMappingExpressions)
            throws InterpolationException {

        String res = null;

        final String mappingExpr = getMappingExpression(artifact, jbiMappingExpressions);
        if (mappingExpr != null) {
            res = this.evaluateFileNameMapping(mappingExpr, artifact);
        }

        return res;
    }

    /**
     * <p>
     * Compute the JBI shared libraries of the artifact according the JBI shared
     * libraries mapping configuration file.
     * </p>
     * <p>
     * Note: The JBI shared library identifiers are also computed according to
     * the following priority order:
     * </p>
     * <ol>
     * <li>if a JBI shared library identifier mapping exists, it is used,</li>
     * <li>otherwise the JBI identifier is defined according to the parameter
     * <code>sharedLibraryNameMappingInComponent</code>.</li>
     * </ol>
     * 
     * @return List of shared libraries (as JBI descriptor element) of the
     *         artifact, <code>null</code> if not match found.
     */
    private List<SharedLibrary> getSharedLibraries(final Artifact artifact)
            throws MojoExecutionException {

        try {
            final List<String> sharedLibrariesStr = this
                    .getSharedLibrariesMappingExpression(artifact);

            if (sharedLibrariesStr != null) {
                final List<SharedLibrary> sharedLibraries = new ArrayList<SharedLibrary>();

                for (final String sharedLibraryStr : sharedLibrariesStr) {

                    final StringTokenizer st = new StringTokenizer(sharedLibraryStr, ":");
                    if (st.countTokens() < 3) {
                        throw new MojoExecutionException(
                                "Missing field in the shared library definition, 3 fields are mandatory: "
                                        + sharedLibraryStr);
                    }
                    final String groupId = st.nextToken();
                    final String artifactId = st.nextToken();
                    final String version = st.nextToken();

                    final Artifact sharedLibraryArtifact = this.artifactFactory
                            .createDependencyArtifact(groupId, artifactId, VersionRange
                                    .createFromVersionSpec(version), JBIAbstractMojo.PACKAGING_SL,
                                    null, null);

                    sharedLibraries.add(this.artifactToSharedLibrary(sharedLibraryArtifact));
                }

                return sharedLibraries;
            } else {
                return null;
            }
        } catch (final InvalidVersionSpecificationException | InterpolationException e) {
            throw new MojoExecutionException("Error during the artifact resolution.", e);
        }
    }

    /**
     * <p>
     * Compute the JBI shared libraries of the artifact according the POM file.
     * </p>
     * <p>
     * Note: The JBI shared library identifiers are also computed according to
     * the following priority order:
     * </p>
     * <ol>
     * <li>if a JBI shared library identifier mapping exists, it is used,</li>
     * <li>otherwise the JBI identifier is defined according to the parameter
     * <code>sharedLibraryNameMappingInComponent</code>.</li>
     * </ol>
     * 
     * @return List of shared libraries (as JBI descriptor element) of the
     *         artifact.
     */
    private List<SharedLibrary> getSharedLibrariesFromProject() throws MojoExecutionException {

        try {
            final MavenProject artifactProject = this.getMavenProject();
            final List<Artifact> slDependencies = this.getSharedLibraries(artifactProject);
            final List<SharedLibrary> sharedLibraries = new ArrayList<SharedLibrary>();
            for (final Artifact slDependency : slDependencies) {

                final Artifact sharedLibraryArtifact = this.artifactFactory
                        .createDependencyArtifact(slDependency.getGroupId(), slDependency
                                .getArtifactId(), VersionRange.createFromVersionSpec(slDependency
                                .getVersion()), JBIAbstractMojo.PACKAGING_SL, null, null);

                sharedLibraries.add(this.artifactToSharedLibrary(sharedLibraryArtifact));
            }

            return sharedLibraries;
        } catch (final InvalidVersionSpecificationException | InterpolationException e) {
            throw new MojoExecutionException("Error during the artifact resolution.", e);
        }
    }

    /**
     * <p>
     * Compute the interception configuration of a service-unit according to:
     * </p>
     * <ul>
     * <li>configuration name,</li>
     * <li>service-unit type: 'provider' or 'consumer',</li>
     * <li>interface-name</li>
     * <li>service-name</li>
     * <li>endpoint-name</li>
     * </ul>
     * <p>
     * of the service interception configuration file.
     * </p>
     * 
     * @return The interception configuration of the SU.
     */
    protected Map<String, List<SUInterceptor>> getInterceptionConfiguration(final String interceptionConfigurationName, final String type, final QName interfaceName, final QName serviceName, final String endpointName)
            throws MojoExecutionException {

    	final Map<String, List<SUInterceptor>> interceptionCfg = new HashMap<String, List<SUInterceptor>>();
    	
    	final Map<String, String> interceptionCfgExprs = this
                .getInterceptionConfigurationExpression(interceptionConfigurationName, type, interfaceName, serviceName, endpointName);
    	System.out.println("interceptionCfgExprs: " + interceptionCfgExprs);

        if (interceptionCfgExprs != null) {
            
            for (final Map.Entry<String, String> interceptionCfgExpr : interceptionCfgExprs.entrySet()) {

                final StringTokenizer stKey = new StringTokenizer(interceptionCfgExpr.getKey(), ":");
                if (stKey.countTokens() < 7) {
                    throw new MojoExecutionException(
                            "Missing field in the service interception definition, 7 fields are mandatory at key level: "
                                    + interceptionCfgExpr);
                }
                final String configName = stKey.nextToken();
                final String suType = stKey.nextToken();
                final String itfName = stKey.nextToken();
                final String svcName = stKey.nextToken();
                final String edpName = stKey.nextToken();
                final String phase = stKey.nextToken();
                
                List<SUInterceptor> interceptorsByPhase = interceptionCfg.get(phase);
                if (interceptorsByPhase == null) {
                	interceptorsByPhase = new ArrayList<SUInterceptor>();
                	interceptionCfg.put(phase, interceptorsByPhase);
                }
                
                final StringTokenizer stValue = new StringTokenizer(interceptionCfgExpr.getValue(), ":");
                if (stValue.countTokens() < 1) {
                    throw new MojoExecutionException(
                            "Missing field in the service interception definition, 1 field is mandatory at value level: "
                                    + interceptionCfgExpr);
                }
                final String interceptorName = stValue.nextToken();
                
                final SUInterceptor interceptor = new SUInterceptor();
                interceptor.setName(interceptorName);
                interceptorsByPhase.add(interceptor);
                
                if (stValue.hasMoreTokens()) {
                	final List<Param> params = interceptor.getParam();
                	while (stValue.hasMoreTokens()) {
                		final String paramName = stValue.nextToken();
                		Param param = null;
                		for (final Param existingParam : params) {
                			if (existingParam.getName().equals(paramName)) {
                				param = existingParam;
                				break;
                			}
                		}
                		if (param == null) {
                			param = new Param();
                			param.setName(paramName);
                			params.add(param);
                		}

                		try {
                            final String paramValue = stValue.nextToken();
                            param.setValue(paramValue);
                        } catch (final NoSuchElementException e) {
                            // NOP, we use the default value
                        }
                	}
                }

            }
        }
        
        return interceptionCfg;
        
    }

    /**
     * Find expressions defining the interception configuration the service-unit in the service-unit interception
     * mapping configuration file.
     * 
     * @return The list of interception configuration as String list,
     *         <code>null</code> if not match found.
     */
    private Map<String, String> getInterceptionConfigurationExpression(final String interceptionConfigurationName, final String type, final QName interfaceName, final QName serviceName, final String endpointName)
            throws MojoExecutionException {

        final String interceptionCfgsPattern[] =
        		interceptionConfigurationName == null ?
        				JBIAbstractConfigurableMojo.getServiceInterceptionPatternWithoutInterceptionConfigName(type, interfaceName, serviceName, endpointName) : 
        				JBIAbstractConfigurableMojo.getServiceInterceptionPatternWithInterceptionConfigName(interceptionConfigurationName, type, interfaceName, serviceName, endpointName);
        System.out.println("interceptionCfgsPattern: " + interceptionCfgsPattern);
        final Map<String, String> interceptionCfgs = new HashMap<String, String>();
        
        final Properties localServiceInterceptorCustomizationExpressions = (Properties)this.serviceInterceptorCustomizationExpressions.clone();

        for (final String interceptionCfgPattern : interceptionCfgsPattern) {
        	System.out.println("interceptionCfgPattern: " + interceptionCfgPattern);
            List<String> removedKeys = new ArrayList<String>();
            for (final Object keyObj : localServiceInterceptorCustomizationExpressions.keySet()) {
                final String key = (String) keyObj;

                // We must remove the fields "interceptio-config-name" if null, "phase" and "ordering number" before to compare
                // with a pattern
                final String keyWithPhaseAndWithoutOrderingNumber = key.substring(interceptionConfigurationName == null ? key.indexOf(':') + 1 : 0, key.lastIndexOf(':'));
                System.out.println("keyWithPhaseAndWithoutOrderingNumber: " + keyWithPhaseAndWithoutOrderingNumber);
                if (keyWithPhaseAndWithoutOrderingNumber.substring(0, keyWithPhaseAndWithoutOrderingNumber.lastIndexOf(':')).equals(interceptionCfgPattern)) {
                    // We have found an interception expression
                    interceptionCfgs.put(key, localServiceInterceptorCustomizationExpressions.getProperty(key));
                    removedKeys.add(key);
                }
            }
            for (String key : removedKeys) {
            	localServiceInterceptorCustomizationExpressions.remove(key);
            }
            removedKeys.clear();
        }

        return interceptionCfgs.size() == 0 ? null : interceptionCfgs;
    }

    private static String[] getServiceInterceptionPatternWithInterceptionConfigName(final String interceptionConfigurationName, final String type, final QName interfaceName, final QName serviceName, final String endpointName) {
        // Array containing all keys corresponfing to a service interception pattern expression
        return new String[] {
        		interceptionConfigurationName + ":" + type + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + endpointName,
        		interceptionConfigurationName + ":" + type + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + "*",
        		interceptionConfigurationName + ":" + type + ":" + interfaceName.toString() + ":" + "*" + ":" + endpointName,
        		interceptionConfigurationName + ":" + type + ":" + interfaceName.toString() + ":" + "*" + ":" + "*",
        		interceptionConfigurationName + ":" + type + ":" + "*" + ":" + serviceName.toString() + ":" + endpointName,
        		interceptionConfigurationName + ":" + type + ":" + "*" + ":" + serviceName.toString() + ":" + "*",
        		interceptionConfigurationName + ":" + type + ":" + "*" + ":" + "*" + ":" + endpointName,
        		interceptionConfigurationName + ":" + type + ":" + "*" + ":" + "*" + ":" + "*",
        		interceptionConfigurationName + ":" + "*" + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + endpointName,
        		interceptionConfigurationName + ":" + "*" + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + "*",
        		interceptionConfigurationName + ":" + "*" + ":" + interfaceName.toString() + ":" + "*" + ":" + endpointName,
        		interceptionConfigurationName + ":" + "*" + ":" + interfaceName.toString() + ":" + "*" + ":" + "*",
        		interceptionConfigurationName + ":" + "*" + ":" + "*" + ":" + serviceName.toString() + ":" + endpointName,
        		interceptionConfigurationName + ":" + "*" + ":" + "*" + ":" + serviceName.toString() + ":" + "*",
        		interceptionConfigurationName + ":" + "*" + ":" + "*" + ":" + "*" + ":" + endpointName,
        		interceptionConfigurationName + ":" + "*" + ":" + "*" + ":" + "*" + ":" + "*" };
    }

    private static String[] getServiceInterceptionPatternWithoutInterceptionConfigName(final String type, final QName interfaceName, final QName serviceName, final String endpointName) {
        // Array containing all keys corresponfing to a service interception pattern expression
        return new String[] {
        		type + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + endpointName,
        		type + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + "*",
        		type + ":" + interfaceName.toString() + ":" + "*" + ":" + endpointName,
        		type + ":" + interfaceName.toString() + ":" + "*" + ":" + "*",
        		type + ":" + "*" + ":" + serviceName.toString() + ":" + endpointName,
        		type + ":" + "*" + ":" + serviceName.toString() + ":" + "*",
        		type + ":" + "*" + ":" + "*" + ":" + endpointName,
        		type + ":" + "*" + ":" + "*" + ":" + "*",
        		"*" + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + endpointName,
        		"*" + ":" + interfaceName.toString() + ":" + serviceName.toString() + ":" + "*",
        		"*" + ":" + interfaceName.toString() + ":" + "*" + ":" + endpointName,
        		"*" + ":" + interfaceName.toString() + ":" + "*" + ":" + "*",
        		"*" + ":" + "*" + ":" + serviceName.toString() + ":" + endpointName,
        		"*" + ":" + "*" + ":" + serviceName.toString() + ":" + "*",
        		"*" + ":" + "*" + ":" + "*" + ":" + endpointName,
        		"*" + ":" + "*" + ":" + "*" + ":" + "*" };
    }

    /**
     * Convert a shared library as a Maven artifact to the associated element of the component JBI descriptor. The
     * shared library identifier is computed according to the defined configuration and mapping rules.
     * 
     * @param artifact
     * @return
     * @throws InterpolationException
     */
    protected SharedLibrary artifactToSharedLibrary(final Artifact artifact) throws InterpolationException {
        final SharedLibrary sharedLibrary = new SharedLibrary();
        final String slContent = this.evaluateJBIIdentifier(                this.sharedLibraryNameMappingInComponent, artifact);
        sharedLibrary.setContent(slContent);
        sharedLibrary.setVersion(this.evaluateJBIVersion(artifact.getVersion(), artifact));

        return sharedLibrary;
    }

    /**
     * Find a mapping expression associated to the provided Maven artifact in a
     * mapping expression set (ie: mapping configuration file).
     * 
     * @return The mapping expression, <code>null</code> if not match found.
     */
    private static String getMappingExpression(final Artifact artifact, final Properties jbiMappingExpressions) {

        final String artifactKeys[] = JBIAbstractConfigurableMojo
                .getArtifactPatternWithPackaging(artifact);

        for (final String artifactKey : artifactKeys) {

            if (jbiMappingExpressions.containsKey(artifactKey)) {
                return jbiMappingExpressions.getProperty(artifactKey);
            }
        }

        return null;
    }

    /**
     * Find expressions defining the shared libraries of the JBI artifact in the
     * mapping configuration file.
     * 
     * @return The list of shared library Maven artifact as String list,
     *         <code>null</code> if not match found.
     */
    private List<String> getSharedLibrariesMappingExpression(final Artifact artifact)
            throws MojoExecutionException {

        final String artifactKeys[] = JBIAbstractConfigurableMojo
                .getArtifactPatternWithoutPackaging(artifact);
        final List<String> sharedLibraries = new ArrayList<String>();

        for (final String artifactKey : artifactKeys) {
            List<String> removedKeys = new ArrayList<String>();
            for (final Object keyObj : this.jbiSharedLibrariesMappingExpressions.keySet()) {
                final String key = (String) keyObj;

                // We must remove the field "ordering number" before to compare
                // with an artifact pattern
                if (key.substring(0, key.lastIndexOf(':')).equals(artifactKey)) {
                    // We have found a shared library mapping line
                    sharedLibraries.add(this.jbiSharedLibrariesMappingExpressions.getProperty(key));
                    removedKeys.add(key);
                }
            }
            for (String key : removedKeys) {
                this.jbiSharedLibrariesMappingExpressions.remove(key);
            }
            removedKeys.clear();
        }

        return sharedLibraries.size() == 0 ? null : sharedLibraries;
    }

    /**
     * Find expressions defining the extra classpath elements of the artifact in the mapping configuration file.
     * 
     * @return The list of extra classpath elements, or an empty list if not match found.
     */
    private final static List<String> getClasspathMappingExpression(final Artifact artifact,
            final Properties extraClasspathMappingExpression) throws MojoExecutionException {

        final String artifactKeys[] = JBIAbstractConfigurableMojo.getArtifactPatternWithoutPackaging(artifact);
        final List<String> classpathElts = new ArrayList<String>();
        final Properties localExtraClasspathMappingExpression = new Properties();
        localExtraClasspathMappingExpression.putAll(extraClasspathMappingExpression);

        for (final String artifactKey : artifactKeys) {
            // Loop over patterns generated from the artifact
            List<String> removedKeys = new ArrayList<String>();
            for (final Map.Entry<Object, Object> entry : localExtraClasspathMappingExpression.entrySet()) {
                final String key = (String) entry.getKey();

                // We must remove the field "ordering number" before to compare
                // with an artifact pattern
                if (key.substring(0, key.lastIndexOf(':')).equals(artifactKey)) {
                    // We have found a shared library mapping line
                    classpathElts.add(localExtraClasspathMappingExpression.getProperty(key));
                    removedKeys.add(key);
                }
            }
            for (String key : removedKeys) {
                localExtraClasspathMappingExpression.remove(key);
            }
            removedKeys.clear();
        }

        return classpathElts;
    }

    private static String[] getArtifactPatternWithPackaging(final Artifact artifact) {
        // Array containing all keys corresponfing to a artifact expression
        return new String[] {
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + ":"
                        + artifact.getType(),
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + ":" + "*",
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + "*" + ":" + artifact.getType(),
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + "*" + ":" + "*",
                artifact.getGroupId() + ":" + "*" + ":" + artifact.getVersion() + ":"
                        + artifact.getType(),
                artifact.getGroupId() + ":" + "*" + ":" + artifact.getVersion() + ":" + "*",
                artifact.getGroupId() + ":" + "*" + ":" + "*" + ":" + artifact.getType(),
                artifact.getGroupId() + ":" + "*" + ":" + "*" + ":" + "*",
                "*" + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + ":"
                        + artifact.getType(),
                "*" + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + ":" + "*",
                "*" + ":" + artifact.getArtifactId() + ":" + "*" + ":" + artifact.getType(),
                "*" + ":" + artifact.getArtifactId() + ":" + "*" + ":" + "*",
                "*" + ":" + "*" + ":" + artifact.getVersion() + ":" + artifact.getType(),
                "*" + ":" + "*" + ":" + artifact.getVersion() + ":" + "*",
                "*" + ":" + "*" + ":" + "*" + ":" + artifact.getType(),
                "*" + ":" + "*" + ":" + "*" + ":" + "*" };
    }

    private static String[] getArtifactPatternWithoutPackaging(final Artifact artifact) {
        // Array containing all keys corresponfing to a artifact expression
        return new String[] {
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(),
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(),
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + "*",
                artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + "*",
                artifact.getGroupId() + ":" + "*" + ":" + artifact.getVersion(),
                artifact.getGroupId() + ":" + "*" + ":" + artifact.getVersion(),
                artifact.getGroupId() + ":" + "*" + ":" + "*",
                artifact.getGroupId() + ":" + "*" + ":" + "*",
                "*" + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(),
                "*" + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(),
                "*" + ":" + artifact.getArtifactId() + ":" + "*",
                "*" + ":" + artifact.getArtifactId() + ":" + "*",
                "*" + ":" + "*" + ":" + artifact.getVersion(),
                "*" + ":" + "*" + ":" + artifact.getVersion(), "*" + ":" + "*" + ":" + "*",
                "*" + ":" + "*" + ":" + "*" };
    }

    /**
     * Read all configuration file needed by the goal "jbi-configure".
     * 
     * @throws MojoExecutionException
     */
    protected void readConfigurationFiles() throws MojoExecutionException {
        this.readJbiIdentifiersMappingFile();
        this.readJbiSharedLibrariesMappingFile();
        this.readJbiVersionsMappingFile();
        this.readJbiExtraComponentClasspathMappingFile();
        this.readJbiExtraBootstrapClasspathMappingFile();
        this.readComponentInterceptorDeclarationFile();
        this.readServiceInterceptorDeclarationFile();
    }

    /**
     * Read the JBI identifier mapping file.
     * 
     * @throws MojoExecutionException
     */
    private void readJbiIdentifiersMappingFile() throws MojoExecutionException {
        // We look for the mapping file through the classpath
        try {
            this.debug("JBI identifiers mapping configuration file: "
                    + this.jbiIdentifiersMappingFile);
            InputStream isJbiIdentifiersMappingFile = null;
            if (this.jbiIdentifiersMappingFile != null) {
                isJbiIdentifiersMappingFile = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(this.jbiIdentifiersMappingFile);
            }
            if (isJbiIdentifiersMappingFile == null) {
                this.debug("JBI identifiers mapping configuration URL: "
                        + this.jbiIdentifiersMappingFileURL);
                // We look for trough the URL
                if (this.jbiIdentifiersMappingFileURL != null) {
                    isJbiIdentifiersMappingFile = this.jbiIdentifiersMappingFileURL.openStream();
                }
            }

            if (isJbiIdentifiersMappingFile == null) {
                this.info("JBI identifiers mapping files not found: "
                        + this.jbiIdentifiersMappingFile + ", URL: "
                        + this.jbiIdentifiersMappingFileURL);
            } else {
                this.jbiIdentifiersMappingExpressions.load(isJbiIdentifiersMappingFile);
            }

        } catch (final IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    /**
     * Read the JBI shared libraries mapping file.
     * 
     * @throws MojoExecutionException
     */
    private void readJbiSharedLibrariesMappingFile() throws MojoExecutionException {
        // We look for the mapping file through the classpath
        try {
            this.debug("JBI shared libraries mapping configuration file: "
                    + this.jbiSharedLibrariesMappingFile);
            InputStream isJbiSharedLibrariesMappingFile = null;
            if (this.jbiSharedLibrariesMappingFile != null) {
                isJbiSharedLibrariesMappingFile = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(this.jbiSharedLibrariesMappingFile);
            }
            if (isJbiSharedLibrariesMappingFile == null) {
                // We look for trough the URL
                this.debug("JBI shared libraries mapping configuration URL: "
                        + this.jbiSharedLibrariesMappingFileURL);
                if (this.jbiSharedLibrariesMappingFileURL != null) {
                    isJbiSharedLibrariesMappingFile = this.jbiSharedLibrariesMappingFileURL
                            .openStream();
                }
            }

            if (isJbiSharedLibrariesMappingFile == null) {
                this.info("JBI shared libraries mapping files not found: "
                        + this.jbiIdentifiersMappingFile + ", URL: "
                        + this.jbiSharedLibrariesMappingFileURL);
            } else {
                this.jbiSharedLibrariesMappingExpressions.load(isJbiSharedLibrariesMappingFile);
            }

        } catch (final IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    /**
     * Read the file declaring component interceptor to package into JBI components.
     * 
     * @throws MojoExecutionException
     */
    private void readComponentInterceptorDeclarationFile() throws MojoExecutionException {
        // We look for the mapping file through the classpath
        try {
            this.debug("Component interceptors customization file: "
                    + this.componentInterceptorCustomizationFile);
            InputStream isInterceptorDeclarationFile = null;
            if (this.componentInterceptorCustomizationFile != null) {
                isInterceptorDeclarationFile = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(this.componentInterceptorCustomizationFile);
            }
            if (isInterceptorDeclarationFile == null) {
                // We look for trough the URL
                this.debug("Component interceptors customization URL: "
                        + this.componentInterceptorCustomizationFileURL);
                if (this.componentInterceptorCustomizationFileURL != null) {
                    isInterceptorDeclarationFile = this.componentInterceptorCustomizationFileURL
                            .openStream();
                }
            }

            if (isInterceptorDeclarationFile == null) {
                this.info("Component interceptors customization files not found: "
                        + this.componentInterceptorCustomizationFile + ", URL: "
                        + this.componentInterceptorCustomizationFileURL);
            } else {
                this.componentInterceptorCustomizationExpressions.load(isInterceptorDeclarationFile);
            }

        } catch (final IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    /**
     * Read the file declaring service interceptor configuration to set into service unit.
     * 
     * @throws MojoExecutionException
     */
    private void readServiceInterceptorDeclarationFile() throws MojoExecutionException {
        // We look for the mapping file through the classpath
        try {
            this.debug("Service interceptors customization file: "
                    + this.serviceInterceptorCustomizationFile);
            InputStream isInterceptorDeclarationFile = null;
            if (this.serviceInterceptorCustomizationFile != null) {
                isInterceptorDeclarationFile = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(this.serviceInterceptorCustomizationFile);
            }
            if (isInterceptorDeclarationFile == null) {
                // We look for trough the URL
                this.debug("Service interceptors customization URL: "
                        + this.serviceInterceptorCustomizationFileURL);
                if (this.serviceInterceptorCustomizationFileURL != null) {
                    isInterceptorDeclarationFile = this.serviceInterceptorCustomizationFileURL
                            .openStream();
                }
            }

            if (isInterceptorDeclarationFile == null) {
                this.info("Service interceptors customization files not found: "
                        + this.serviceInterceptorCustomizationFile + ", URL: "
                        + this.serviceInterceptorCustomizationFileURL);
            } else {
                this.serviceInterceptorCustomizationExpressions.load(isInterceptorDeclarationFile);
            }

        } catch (final IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    /**
     * Read the JBI versions mapping file.
     * 
     * @throws MojoExecutionException
     */
    private void readJbiVersionsMappingFile() throws MojoExecutionException {
        // We look for the mapping file through the classpath
        try {
            this.debug("JBI versions mapping configuration file: " + this.jbiVersionsMappingFile);
            InputStream isJbiVersionsMappingFile = null;
            if (this.jbiVersionsMappingFile != null) {
                isJbiVersionsMappingFile = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(this.jbiVersionsMappingFile);
            }
            if (isJbiVersionsMappingFile == null) {
                this.debug("JBI versions mapping configuration URL: "
                        + this.jbiVersionsMappingFileURL);
                // We look for trough the URL
                if (this.jbiVersionsMappingFileURL != null) {
                    isJbiVersionsMappingFile = this.jbiVersionsMappingFileURL.openStream();
                }
            }

            if (isJbiVersionsMappingFile == null) {
                this.info("JBI versions mapping files not found: " + this.jbiVersionsMappingFile
                        + ", URL: " + this.jbiVersionsMappingFileURL);
            } else {
                this.jbiVersionsMappingExpressions.load(isJbiVersionsMappingFile);
            }

        } catch (final IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    /**
     * Read the extra component classpath elements list mapping configuration file.
     * 
     * @throws MojoExecutionException
     */
    private void readJbiExtraComponentClasspathMappingFile() throws MojoExecutionException {
        // We look for the mapping file through the classpath
        try {
            this.debug("Extra component classpath elements list mapping configuration file: "
                    + this.jbiExtraComponentClasspathMappingFile);
            InputStream isExtraComponentClasspathMappingFile = null;
            if (this.jbiExtraComponentClasspathMappingFile != null) {
                isExtraComponentClasspathMappingFile = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(this.jbiExtraComponentClasspathMappingFile);
            }
            if (isExtraComponentClasspathMappingFile == null) {
                this.debug("Extra component classpath elements list mapping configuration URL: "
                        + this.jbiExtraComponentClasspathMappingFileURL);
                // We look for trough the URL
                if (this.jbiExtraComponentClasspathMappingFileURL != null) {
                    isExtraComponentClasspathMappingFile = this.jbiExtraComponentClasspathMappingFileURL.openStream();
                }
            }

            if (isExtraComponentClasspathMappingFile == null) {
                this.info("Extra component classpath elements list mapping configuration files not found: "
                        + this.jbiExtraComponentClasspathMappingFile + ", URL: "
                        + this.jbiExtraComponentClasspathMappingFileURL);
            } else {
                this.jbiExtraComponentClasspathMappingExpressions.load(isExtraComponentClasspathMappingFile);
                if (this.jbiExtraComponentClasspathMappingExpressions.size() > 0) {
                    this.debug("Extra component classpath: "
                            + this.jbiExtraComponentClasspathMappingExpressions.toString());

                    // We check the property values against the expected format:
                    // groupId:artifactId:version:orderingNumber
                    JBIAbstractConfigurableMojo
                            .checkExpressionKeysArtifactWithOrder(this.jbiExtraComponentClasspathMappingExpressions);
                } else {
                    this.warn("The extra component classpath elements list mapping configuration is empty.");
                }
            }

        } catch (final IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    /**
     * Read the extra bootstrap classpath elements list mapping configuration file.
     * 
     * @throws MojoExecutionException
     */
    private void readJbiExtraBootstrapClasspathMappingFile() throws MojoExecutionException {
        // We look for the mapping file through the classpath
        try {
            this.debug("Extra bootstrap classpath elements list mapping configuration file: "
                    + this.jbiExtraBootstrapClasspathMappingFile);
            InputStream isExtraBootstrapClasspathMappingFile = null;
            if (this.jbiExtraBootstrapClasspathMappingFile != null) {
                isExtraBootstrapClasspathMappingFile = Thread.currentThread().getContextClassLoader()
                        .getResourceAsStream(this.jbiExtraBootstrapClasspathMappingFile);
            }
            if (isExtraBootstrapClasspathMappingFile == null) {
                this.debug("Extra bootstrap classpath elements list mapping configuration URL: "
                        + this.jbiExtraBootstrapClasspathMappingFileURL);
                // We look for trough the URL
                if (this.jbiExtraBootstrapClasspathMappingFileURL != null) {
                    isExtraBootstrapClasspathMappingFile = this.jbiExtraBootstrapClasspathMappingFileURL.openStream();
                }
            }

            if (isExtraBootstrapClasspathMappingFile == null) {
                this.info("Extra bootstrap classpath elements list mapping configuration files not found: "
                        + this.jbiExtraBootstrapClasspathMappingFile + ", URL: "
                        + this.jbiExtraBootstrapClasspathMappingFileURL);
            } else {
                this.jbiExtraBootstrapClasspathMappingExpressions.load(isExtraBootstrapClasspathMappingFile);
                if (this.jbiExtraBootstrapClasspathMappingExpressions.size() > 0) {
                    this.debug("Extra bootstrap classpath: "
                            + this.jbiExtraBootstrapClasspathMappingExpressions.toString());

                    // We check the property values against the expected format:
                    // groupId:artifactId:version:orderingNumber
                    JBIAbstractConfigurableMojo
                            .checkExpressionKeysArtifactWithOrder(this.jbiExtraBootstrapClasspathMappingExpressions);
                } else {
                    this.warn("The extra bootstrap classpath elements list mapping configuration is empty.");
                }
            }

        } catch (final IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    private final static void checkExpressionKeysArtifactWithOrder(final Properties expressionValues)
            throws MojoExecutionException {

        for (final Map.Entry<Object, Object> entry : expressionValues.entrySet()) {
            final String key = (String) entry.getKey();

            final StringTokenizer st = new StringTokenizer(key, ":");
            if (st.countTokens() < 4) {
                throw new MojoExecutionException(
                        "Missing field in the extra classpath element key, 4 fields are mandatory for entry: " + key
                                + "=" + entry.getValue().toString());
            }
            // Extract groupId
            st.nextToken();
            // Extract artifactId
            st.nextToken();
            // Extract version
            st.nextToken();
            // Extract and check ordering number
            try {
                Integer.parseInt(st.nextToken());
            } catch (final NumberFormatException e) {
                throw new MojoExecutionException(
                        "Ordering number field of the extra classpath element key is not a number (entry: " + key + "="
                                + entry.getValue().toString() + ").");
            }

        }
    }
    
    protected interface OnWsdlImport {
    	
    	void onWsdlImport(final URI importURI, final Document importContent) throws IOException;
    }
    
    protected final InputStream configureWSDLServiceUnit(final Description wsdl, final OnWsdlImport onWsdlImport) throws Exception {
    	wsdl.addImportedDocumentsInWsdl();
    	final ImportedDocuments importedDocuments = wsdl.getImportedDocuments();
    	
        final List<String> localImportFiles = new ArrayList<>();
    	final String wsdlStr = wsdl.getDocumentBaseURI().toString();
    	final String wsdlDir = wsdlStr.substring(0, wsdlStr.lastIndexOf('/') + 1);
        this.debug("    WSDL root base: " + wsdlDir);

        // Processing imported XML Schemas
        final Map<URI, AbsItfSchema> schemas = importedDocuments.getAllSchemas();
    	for (final URI entryKey : schemas.keySet()) {
    		final String schema = entryKey.toString();
            this.debug("    Processing imported XML schema: " + schema);
    		if (schema.startsWith(wsdlDir)) {
    			final String localImportFile = schema.substring(wsdlDir.length());
                this.info("         Local import (" + localImportFile + "): " + schema);
    			localImportFiles.add(localImportFile);
    		}
		}
        // Processing Imported WSDL
        final Map<URI, AbsItfDescription> wsdls = importedDocuments.getAllDescriptions();
        for (final URI entryKey : wsdls.keySet()) {
            final String impWsdl = entryKey.toString();
            this.debug("    Processing imported WSDL: " + impWsdl);
            if (impWsdl.startsWith(wsdlDir)) {
                final String localImportFile = impWsdl.substring(wsdlDir.length());
                this.info("         Local import (" + localImportFile + "): " + impWsdl);
                localImportFiles.add(localImportFile);
            }
        }
    	
		final Map<URI, Document> imports = wsdl.deleteImportedDocumentsInWsdl(URI.create(""));
		for (final Map.Entry<URI, Document> importEntry : imports.entrySet()) {
			final URI entryKey = importEntry.getKey();
			if (localImportFiles.contains(entryKey.toString())) {
                this.info("         " + entryKey.toString()
                        + " is a local import already packaged or that will be packaged.");
			}
			else {
				this.info("     Downloading & Packaging resources of WSDL, add resource: " + entryKey.toString());
				onWsdlImport.onWsdlImport(entryKey, importEntry.getValue());
			}
		}
		
        this.debug("    Downloading & Packaging resources of WSDL, updating WSDL.");

        // TODO: Writing a Description into an OutputStream should be provided by WSDL4ComplexWsdlWriter
        // Because of encoding, it is not possible to use a temporary String
        final ByteArrayOutputStream baosWsdl = new ByteArrayOutputStream();
        this.writeDescription2OutputStream(wsdl, baosWsdl);
        baosWsdl.close();
        return new ByteArrayInputStream(baosWsdl.toByteArray());
    }

    /**
     * Writing a {@link Description} into an {@link OutputStream} should be provided by {@link WSDL4ComplexWsdlWriter}
     * 
     * @param description
     * @param osDescription
     * @throws WSDLException
     */
    // Writing a Description into an OutputStream should be provided by WSDL4ComplexWsdlWriter
    private void writeDescription2OutputStream(final Description description, final OutputStream osDescription)
            throws WSDLException {
        try {
            final WSDL4ComplexWsdlWriter writer = WSDL4ComplexWsdlFactory.newInstance().newWSDLWriter();
            final Document wsdlDocument = writer.getDocument(description);
            final Result result = new StreamResult(osDescription);
            final Transformer transformer = Transformers.takeTransformer();
            try {
                transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
                transformer.setOutputProperty(OutputKeys.METHOD, "xml");
                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                transformer.transform(new DOMSource(wsdlDocument), result);
            } finally {
                Transformers.releaseTransformer(transformer);
            }
        } catch (final TransformerException e) {
            throw new WSDLException("Failed to write the WSDL", e);
        }
    }

    protected String extractComponentToUseFromServiceUnitJbiDescr(final Artifact serviceUnitArtifact)
            throws MojoFailureException, MojoExecutionException {

        final Jbi jbiComponentDescriptor = this.readJbiDescriptor(serviceUnitArtifact);
        try {
            return JBIDescriptorExtensionBuilder.getInstance()
                    .getServiceUnitTargetComponentAsGA(jbiComponentDescriptor);
        } catch (final NotServiceUnitException e) {
            throw new MojoFailureException(
                    String.format("The JBI descriptor of the artifact '%s' is not a service unit JBI descriptor.",
                            serviceUnitArtifact.getArtifactId()),
                    e);
        } catch (final NoComponentNameDeployableServiceUnitException e) {
            return null;
        } catch (final JBIDescriptorException e) {
            throw new MojoFailureException(
                    String.format("Unable to extract the component to run the service unit '%s'.",
                            serviceUnitArtifact.getArtifactId()),
                    e);
        }

    }
}
