/**
 * Copyright (c) 2009-2012 EBM WebSourcing, 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.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.clapper.util.classutil.AbstractClassFilter;
import org.clapper.util.classutil.AndClassFilter;
import org.clapper.util.classutil.ClassFilter;
import org.clapper.util.classutil.ClassFinder;
import org.clapper.util.classutil.ClassInfo;
import org.clapper.util.classutil.ClassModifiersClassFilter;
import org.clapper.util.classutil.NotClassFilter;
import org.clapper.util.classutil.SubclassClassFilter;
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.WSDL4ComplexWsdlReader;
import org.ow2.petals.component.framework.api.Interceptor;
import org.ow2.petals.component.framework.jbidescriptor.CDKJBIDescriptorBuilder;
import org.ow2.petals.component.framework.jbidescriptor.generated.Accept;
import org.ow2.petals.component.framework.jbidescriptor.generated.AcceptResponse;
import org.ow2.petals.component.framework.jbidescriptor.generated.ComponentInterceptor;
import org.ow2.petals.component.framework.jbidescriptor.generated.ComponentInterceptors;
import org.ow2.petals.component.framework.jbidescriptor.generated.Consumes;
import org.ow2.petals.component.framework.jbidescriptor.generated.Provides;
import org.ow2.petals.component.framework.jbidescriptor.generated.SUInterceptor;
import org.ow2.petals.component.framework.jbidescriptor.generated.SUInterceptors;
import org.ow2.petals.component.framework.jbidescriptor.generated.Send;
import org.ow2.petals.component.framework.jbidescriptor.generated.SendResponse;
import org.ow2.petals.jbi.descriptor.JBIDescriptorException;
import org.ow2.petals.jbi.descriptor.original.JBIDescriptorBuilder;
import org.ow2.petals.jbi.descriptor.original.generated.Component.SharedLibrary;
import org.ow2.petals.jbi.descriptor.original.generated.Identification;
import org.ow2.petals.jbi.descriptor.original.generated.Jbi;
import org.ow2.petals.jbi.descriptor.original.generated.ServiceAssembly;
import org.ow2.petals.jbi.descriptor.original.generated.ServiceUnit;
import org.ow2.petals.plugin.jbiplugin.util.ByteArrayOutputStreamEntry;
import org.ow2.petals.plugin.jbiplugin.util.ZipUtil;
import org.ow2.petals.plugin.jbiplugin.util.ZipUtil.ZipEntryCallback;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import com.ebmwebsourcing.easycommons.xml.DOMHelper;

/**
 * Configure a deliverable JBI Artifact (Component / Service Assembly).
 * 
 * @since 2.0.0
 * 
 * @author Christophe Deneux - Capgemini Sud
 */
@Mojo(name = "jbi-configure", requiresProject = false)
public class JBIConfigureMojo extends JBIAbstractConfigurableMojo {

    /**
     * GroupId of the deliverable JBI artifact to configure.
     */
    @Parameter(required = true, property = "groupId")
    protected String groupId;

    /**
     * ArtifactId of the deliverable JBI artifact to configure.
     */
    @Parameter(required = true, property = "artifactId")
    protected String artifactId;

    /**
     * Version of the deliverable JBI artifact to configure.
     */
    @Parameter(required = true, property = "version")
    protected String version;

    /**
     * Target name of the deliverable JBI artifact to configure.
     */
    @Parameter(property = "targetName")
    protected String targetName;

    /**
     * MavenProject of the provided artifact
     */
    private MavenProject providedProject;

    /**
     * the goal "jbi-configure" is designed to be run on command line. So we
     * need to override this method to avoid a check on packaging.
     * 
     * @see org.ow2.petals.plugin.jbiplugin.JBIAbstractMojo#packagingIsOkForGoal()
     */
    @Override
    protected boolean packagingIsOkForGoal() {
        return true;
    }

    @Override
    public void executeMojo() throws MojoExecutionException, MojoFailureException {

        this.readConfigurationFiles();

        try {
            if (!this.outputDirectory.exists()) {
                this.outputDirectory.mkdirs();
            }

            // We are looking for POM file of the provided artifact
            Artifact artifact = this.artifactFactory.createProjectArtifact(this.groupId,
                    this.artifactId, this.version);
            this.providedProject = this.mavenProjectBuilder.buildFromRepository(artifact,
                    this.project.getRemoteArtifactRepositories(), this.localRepository);

            // We update with the correct packaging
            artifact = this.artifactFactory.createArtifact(this.groupId, this.artifactId,
                    this.version, null, this.providedProject.getPackaging());

            this.artifactResolver.resolve(artifact, this.project.getRemoteArtifactRepositories(),
                    this.localRepository);

            final String artifactType = this.providedProject.getPackaging();
            if (JBIAbstractMojo.PACKAGING_COMPONENT.equals(artifactType)) {
                this.configureComponent(artifact);
            } else if (JBIAbstractMojo.PACKAGING_SA.equals(artifactType)) {
                this.configureServiceAssembly(artifact);
            } else if (JBIAbstractMojo.PACKAGING_SL.equals(artifactType)) {
                this.configureSharedLibrary(artifact);
            } else if (JBIAbstractMojo.PACKAGING_SU.equals(artifactType)) {
                this.configureServiceUnit(artifact);
            } else {
                throw new MojoExecutionException("Unsupported artifact type: " + artifactType);
            }
        } catch (final ArtifactResolutionException e) {
            throw new MojoExecutionException("A problem occurs during configuration.", e);
        } catch (final ArtifactNotFoundException e) {
            throw new MojoExecutionException("A problem occurs during configuration.", e);
        } catch (final ProjectBuildingException e) {
            throw new MojoExecutionException("A problem occurs during configuration.", e);
        }
    }

    private void configureComponent(final Artifact artifact) throws MojoExecutionException {

        try {
            final File artifactFile = artifact.getFile();
            this.info("The following file is used as artifact source: "
                    + artifactFile.getAbsolutePath());
            final ZipInputStream zipArtifactFile = new ZipInputStream(new FileInputStream(artifactFile));
            final String targetComponentName = this.targetName != null ? this.targetName + ".zip" : artifact.getFile()
                    .getName();
            final File configuredArtifactFile = new File(this.outputDirectory, targetComponentName);
            this.debug("Output JBI archive file: " + configuredArtifactFile.getAbsolutePath());
            final ZipOutputStream zipConfiguredArtifactFile = new ZipOutputStream(
                    new FileOutputStream(configuredArtifactFile));

            ZipUtil.copyAndUpdateZipFile(zipArtifactFile, zipConfiguredArtifactFile,
                    new ZipEntryCallback() {
                        private final List<Artifact> artifactToAdd = new LinkedList<Artifact>();

                        @Override
                        public List<Artifact> getExtraArtifactsToAdd() {
                            return this.artifactToAdd;
                        }

						@Override
						public List<ByteArrayOutputStreamEntry> getExtraFilesToAdd() {
							return null;
						}
                
                        public InputStream onZipEntry(final ZipEntry zipEntry,
                                final InputStream zipEntryInputStream) throws IOException,
                                MojoExecutionException {
                    if (JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE.equals(zipEntry.getName())) {
                                // The ZIP entry is the JBI descriptor, we update it
                                try {
                                	final org.ow2.petals.component.framework.jbidescriptor.generated.Jbi jbiDescriptor;
                                	{
	                                	final ByteArrayOutputStream baos = new ByteArrayOutputStream();
	                                	IOUtils.copy(zipEntryInputStream, baos);
                                        jbiDescriptor = CDKJBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(
                                                new ByteArrayInputStream(baos.toByteArray()));
                                	}

                                    final org.ow2.petals.component.framework.jbidescriptor.generated.Component component = jbiDescriptor.getComponent();

                                    // We update the JBI component identifier
                                    // according to the configuration
                                    final org.ow2.petals.component.framework.jbidescriptor.generated.Identification ident = component.getIdentification();
                                    ident.setName(
                                            JBIConfigureMojo.this.evaluateJBIIdentifier(ident.getName(), artifact));

                                    // We update the shared-libraries list
                                    // according to the configuration
                                    final List<SharedLibrary> sharedLibraries = JBIConfigureMojo.this
                                            .evaluateSharedLibraries(artifact);
                                    component.getSharedLibraryList().clear();
                                    for (final SharedLibrary sharedLibrary : sharedLibraries) {
                                    	final org.ow2.petals.component.framework.jbidescriptor.generated.Component.SharedLibrary cdkSharedLibrary = new org.ow2.petals.component.framework.jbidescriptor.generated.Component.SharedLibrary();
                                    	cdkSharedLibrary.setContent(sharedLibrary.getContent());
                                    	cdkSharedLibrary.setVersion(sharedLibrary.getVersion());
                                        component.getSharedLibraryList().add(cdkSharedLibrary);
                                    }

                                    // We update the bootstrap classpath elements list
                                    // according to the configuration
                                    {
                                        // To prevent error on algorithm
                                        // calculating extra classpath, just add
                                        // extra classpath elements instead of
                                        // clearing the original list.
                                        final List<Artifact> classpathElts = JBIConfigureMojo.this
                                                .evaluateBootstrapClasspathElts(artifact);
                                        final List<String> existingClasspathElts = jbiDescriptor
                                                .getComponent().getBootstrapClassPath()
                                                .getPathElement();
                                        for (final Artifact classpathElt : classpathElts) {
                                            String classpathFileName = classpathElt.getFile().getName();
                                            if (!existingClasspathElts.contains(classpathFileName)) {
                                                existingClasspathElts.add(classpathFileName);
                                                this.artifactToAdd.add(classpathElt);
                                                JBIConfigureMojo.this.debug("Extra file added: "
                                                        + classpathFileName
                                                        + " to the boostrap classpath");
                                            }
                                        }
                                    }

                                    // We update the component classpath elements list
                                    // according to the configuration
                                    {
                                        // To prevent error on algorithm
                                        // calculating extra classpath, just add
                                        // extra classpath elements instead of
                                        // clearing the original list.
                                        final List<Artifact> classpathElts = JBIConfigureMojo.this
                                                .evaluateComponentClasspathElts(artifact);
                                        final List<String> existingClasspathElts = jbiDescriptor
                                                .getComponent().getComponentClassPath()
                                                .getPathElement();
                                        for (final Artifact classpathElt : classpathElts) {
                                            if (!existingClasspathElts.contains(classpathElt
                                                    .getFile().getName())) {
                                                existingClasspathElts.add(classpathElt.getFile()
                                                        .getName());
                                                this.artifactToAdd.add(classpathElt);
                                                JBIConfigureMojo.this.debug("Extra file added: "
                                                        + classpathElt.getFile().getName()
                                                        + " to the component classpath");
                                            }
                                        }
                                    }

                                    // For each extra artifact, we check if it contains interceptors
                                    {
                                    	for (final Artifact oneArtifactToAdd : artifactToAdd) {
                                    		final File artifactFileToAdd = oneArtifactToAdd.getFile();
	                                    	// Introspect the artifact to find interceptors
	                    					// Note: the class finder must be initialized with all JARs
	                    					// needed to retrieve interceptor classes, including the CDL
	                    					// API itself
	                    		        	final ClassFinder finder = new ClassFinder();
	                    		            finder.add(artifactFileToAdd);
	                    		            try {
	                    						finder.add(new File(Interceptor.class.getProtectionDomain().getCodeSource().getLocation().toURI()));
	                    					} catch (final URISyntaxException e) {
	                    						throw new MojoExecutionException("Error finding from which JAR the class interceptor is provided");
	                    					}
	                    		            
	                    		            final ClassFilter subclassInterceptorFilter = new AndClassFilter(
	                    		            		new ClassModifiersClassFilter(Modifier.PUBLIC),
	                    		            		new SubclassClassFilter(Interceptor.class),
	                    		            		new NotClassFilter(
	                    		            				new AbstractClassFilter()));
	                    		            final List<ClassInfo> interceptors = new ArrayList<ClassInfo>();
	                    		            if (finder.findClasses(interceptors, subclassInterceptorFilter) > 0) {
	                    		            	final ComponentInterceptors componentInterceptors;
	                    		            	if (jbiDescriptor.getComponent().getComponentInterceptors() != null) {
	                    		            		componentInterceptors = jbiDescriptor.getComponent().getComponentInterceptors();
	                    		            	}
	                    		            	else {
	                    		            		componentInterceptors = new ComponentInterceptors();
	                    		            	}
	                    		            	for (final ClassInfo interceptorClassInfo : interceptors) {
	                    		            		final String interceptorClazz = interceptorClassInfo.getClassName();
	                    		            		final String interceptorName = interceptorClazz.substring(interceptorClazz.lastIndexOf('.') + 1);
	                    		            		final ComponentInterceptor componentInterceptor = new ComponentInterceptor();
	                    		            		componentInterceptor.setActive(false);
	                    		            		componentInterceptor.setClazz(interceptorClazz);
	                    		            		componentInterceptor.setName(interceptorName);
	                    		            		JBIConfigureMojo.this.evaluateComponentInterceptor(artifact, componentInterceptor);
	                    		            		JBIConfigureMojo.this.info("Interceptor found in " + artifactFileToAdd.getName() + ": " + componentInterceptor.getClazz() + "(" + componentInterceptor.getName() + "|" + componentInterceptor.isActive() + ")");
	                    		            		
	                    		            		componentInterceptors.getInterceptor().add(componentInterceptor);
	                    		            	}
	                    		            	jbiDescriptor.getComponent().setComponentInterceptors(componentInterceptors);
	                    		            }
	                    		            else {
	                    		            	JBIConfigureMojo.this.info("No interceptor found in the extra artifact: "+ artifactFileToAdd.getName());
	                    		            }
                                    	}
                                    }

                                    final ByteArrayOutputStream baosUpdatedJbiDesc = new ByteArrayOutputStream();
                                    CDKJBIDescriptorBuilder.getInstance().writeXMLJBIdescriptor(jbiDescriptor,
                                    baosUpdatedJbiDesc);
                                    // Reset of the JBI descriptor file time
                                    zipEntry.setTime(System.currentTimeMillis());
                                    return new ByteArrayInputStream(baosUpdatedJbiDesc
                                            .toByteArray());
                                } catch (final JBIDescriptorException | InterpolationException e) {
                                    throw new MojoExecutionException("Error reading JBI descriptor.", e);
                                }
                            } else {
                            	JBIConfigureMojo.this.debug("Copy a file of the Component: " + zipEntry.getName());
                                return zipEntryInputStream;
                            }
                        }
                    },
                    this.getLog());

            zipConfiguredArtifactFile.flush();
            zipConfiguredArtifactFile.close();

            this.info("The configured JBI archive is available here: "
                    + configuredArtifactFile.getAbsolutePath());
        } catch (final IOException e) {
            throw new MojoExecutionException("A problem occurs during configuration.", e);
        }
    }

    private void configureSharedLibrary(final Artifact artifact) throws MojoExecutionException {
        try {
            final File artifactFile = artifact.getFile();
            this.info("The following file is used as artifact source: "
                    + artifactFile.getAbsolutePath());
            final ZipInputStream zipArtifactFile = new ZipInputStream(new FileInputStream(artifactFile));
            final String targetComponentName = this.targetName != null ? this.targetName + ".zip" : artifact.getFile()
                    .getName();
            final File configuredArtifactFile = new File(this.outputDirectory, targetComponentName);
            this.debug("Output JBI archive file: " + configuredArtifactFile.getAbsolutePath());
            final ZipOutputStream zipConfiguredArtifactFile = new ZipOutputStream(
                    new FileOutputStream(configuredArtifactFile));

            ZipUtil.copyAndUpdateZipFile(zipArtifactFile, zipConfiguredArtifactFile,
                    new ZipEntryCallback() {
                        public InputStream onZipEntry(final ZipEntry zipEntry,
                                final InputStream zipEntryInputStream) throws IOException,
                                MojoExecutionException {
                            if (JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE.equals(zipEntry.getName())) {
                                // The ZIP entry is the JBI descriptor, we update it
                                try {
                                    final Jbi jbiDescriptor = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(zipEntryInputStream);

                                    final org.ow2.petals.jbi.descriptor.original.generated.Jbi.SharedLibrary sharedLibrary = jbiDescriptor
                                            .getSharedLibrary();

                                    // We update the JBI shared library
                                    // identifier according to the
                                    // configuration
                                    final Identification ident = sharedLibrary.getIdentification();
                                    ident.setName(JBIConfigureMojo.this.evaluateJBIIdentifier(
                                            ident.getName(), artifact));

                                    // We update the JBI shared library version
                                    // according to the
                                    // configuration
                                    sharedLibrary.setVersion(JBIConfigureMojo.this
                                            .evaluateJBIVersion(sharedLibrary.getVersion(),
                                                    artifact));

                                    final ByteArrayOutputStream baosUpdatedJbiDesc = new ByteArrayOutputStream();
                                    JBIDescriptorBuilder.getInstance().writeXMLJBIdescriptor(jbiDescriptor, baosUpdatedJbiDesc);
                                    // Reset of the JBI descriptor file time
                                    zipEntry.setTime(System.currentTimeMillis());
                                    return new ByteArrayInputStream(baosUpdatedJbiDesc.toByteArray());
                                } catch (final JBIDescriptorException | InterpolationException e) {
                                    throw new MojoExecutionException("Error reading JBI descriptor.", e);
                                }
                            } else {
                            	JBIConfigureMojo.this.debug("Copy a file of the SL: " + zipEntry.getName());
                                return zipEntryInputStream;
                            }
                        }

                        @Override
                        public List<Artifact> getExtraArtifactsToAdd() {
                            return null;
                        }

						@Override
						public List<ByteArrayOutputStreamEntry> getExtraFilesToAdd() {
                            return null;
                        }
                    },
                    this.getLog());

            zipConfiguredArtifactFile.flush();
            zipConfiguredArtifactFile.close();

        } catch (final IOException e) {
            throw new MojoExecutionException("A problem occurs during configuration.", e);
        }
    }

    private void configureServiceAssembly(final Artifact artifact) throws MojoExecutionException {

        try {
            final File artifactFile = artifact.getFile();
            this.info("The following file is used as artifact source: "
                    + artifactFile.getAbsolutePath());
            final ZipInputStream zipArtifactFile = new ZipInputStream(new FileInputStream(artifactFile));
            try {
                String targetComponentName = artifact.getFile().getName();
                if (this.targetName != null) {
                    targetComponentName = this.targetName + ".zip";
                }
                final File configuredArtifactFile = new File(this.outputDirectory, targetComponentName);
                this.debug("Output JBI archive file: " + configuredArtifactFile.getAbsolutePath());

                // First we extract the current JBI descriptor to get the content of the SA
                final Jbi saJbiDescr = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptorFromArchive(
                        artifactFile);

                final ServiceAssembly serviceAssemblyContent = saJbiDescr.getServiceAssembly();
                if (serviceAssemblyContent == null) {
                    throw new MojoExecutionException(
                            "Missing section 'service-assembly' into the JBI descriptor of the archive: "
                                    + artifactFile.getName());
                }
                
                // Next we process the SA archive
                final ZipOutputStream zipConfiguredArtifactFile = new ZipOutputStream(new FileOutputStream(
                        configuredArtifactFile));

                ZipUtil.copyAndUpdateZipFile(zipArtifactFile, zipConfiguredArtifactFile, new ZipEntryCallback() {

                    @Override
                    public List<Artifact> getExtraArtifactsToAdd() {
                        return null;
                    }

                    @Override
                    public List<ByteArrayOutputStreamEntry> getExtraFilesToAdd() {
                        return null;
                    }

                    public InputStream onZipEntry(final ZipEntry zipEntry, final InputStream zipEntryInputStream)
                            throws IOException, MojoExecutionException {

                        if (zipEntry.getName().endsWith(".zip")) {

                            for (final ServiceUnit serviceUnitContent : serviceAssemblyContent.getServiceUnit()) {
                                if (zipEntry.getName().equals(serviceUnitContent.getTarget().getArtifactsZip())) {
                                    JBIConfigureMojo.this.debug("Configuring SU: "
                                            + serviceUnitContent.getIdentification().getName() + "("
                                            + zipEntry.getName() + ")");

                                    final ByteArrayOutputStream baosSu = new ByteArrayOutputStream();
                                    final ZipOutputStream zipSuOutputStream = new ZipOutputStream(baosSu);
                                    final ZipInputStream zipSuInputStream = new ZipInputStream(zipEntryInputStream);

                                    JBIConfigureMojo.this.configureServiceUnit(zipSuInputStream, zipSuOutputStream,
                                            serviceUnitContent.getIdentification().getName());

                                    zipSuOutputStream.close();
                                    return new ByteArrayInputStream(baosSu.toByteArray());
                                }
                            }

                            // The ZIP entry is not associated to a declared service unit.
                            throw new MojoExecutionException("No service-unit is associated to the zip entry '"
                                    + zipEntry.getName() + "'");

                        } else {
                            JBIConfigureMojo.this.debug("Copy a file of the SA: " + zipEntry.getName());
                            return zipEntryInputStream;
                        }
                            }
                }, this.getLog());

                zipConfiguredArtifactFile.flush();
                zipConfiguredArtifactFile.close();

                this.info("The configured JBI archive is available here: " + configuredArtifactFile.getAbsolutePath());
            } finally {
                zipArtifactFile.close();
            }
        } catch (final IOException e) {
            throw new MojoExecutionException("A problem occurs during configuration.", e);
        } catch (final JBIDescriptorException e) {
        	throw new MojoExecutionException("A problem occurs during configuration.", e);
        }
    }

    private void configureServiceUnit(final Artifact artifact) throws MojoExecutionException {

        try {
            final File artifactFile = artifact.getFile();
            this.info("The following file is used as artifact source: "
                    + artifactFile.getAbsolutePath());
            final ZipInputStream zipArtifactFile = new ZipInputStream(new FileInputStream(artifactFile));
            String targetComponentName = artifact.getFile().getName();
            if (this.targetName != null) {
                targetComponentName = this.targetName + ".zip";
            }
            final File configuredArtifactFile = new File(this.outputDirectory,
                    targetComponentName);
            this.debug("Output JBI archive file: " + configuredArtifactFile.getAbsolutePath());
            final ZipOutputStream zipConfiguredArtifactFile = new ZipOutputStream(
                    new FileOutputStream(configuredArtifactFile));
            
            this.configureServiceUnit(zipArtifactFile, zipConfiguredArtifactFile, null);
            
            zipConfiguredArtifactFile.flush();
            zipConfiguredArtifactFile.close();

            this.info("The configured JBI archive is available here: "
                    + configuredArtifactFile.getAbsolutePath());
        } catch (final IOException e) {
            throw new MojoExecutionException("A problem occurs during configuration.", e);
        }
            
    }
    
    private void configureServiceUnit(final ZipInputStream zipArtifactFile, final ZipOutputStream zipConfiguredArtifactFile, final String serviceUnitId) throws MojoExecutionException, IOException {
        	
        ZipUtil.copyAndUpdateZipFile(zipArtifactFile, zipConfiguredArtifactFile,
                new ZipEntryCallback() {
                    			
        			private final List<ByteArrayOutputStreamEntry> filesToAdd = new LinkedList<ByteArrayOutputStreamEntry>();
                    
                    @Override
                    public List<Artifact> getExtraArtifactsToAdd() {
                        return null;
                    }

					@Override
					public List<ByteArrayOutputStreamEntry> getExtraFilesToAdd() {
						return this.filesToAdd;
					}
					
					public InputStream onZipEntry(final ZipEntry zipEntry,
                            final InputStream zipEntryInputStream) throws IOException,
                            MojoExecutionException {
					
						if (zipEntry.getName().endsWith(".wsdl") && JBIConfigureMojo.this.downloadAndPackageWsdlResources) {
							
                            JBIConfigureMojo.this
                                    .info("Downloading & Packaging resources of WSDL: " + zipEntry.getName());
								
							try {
								final WSDL4ComplexWsdlReader reader = WSDL4ComplexWsdlFactory.newInstance().newWSDLReader();
								
								// It is needed to duplicate 'zipEntryInputStream', because the stream is closed during WSDL parsing and the input stream must not be closed
								final ByteArrayOutputStream baosTmp = new ByteArrayOutputStream();
								IOUtils.copy(zipEntryInputStream, baosTmp);
								final Description desc = reader.read(new InputSource(new ByteArrayInputStream(baosTmp.toByteArray())));
								desc.setDocumentBaseURI(URI.create("/"));
								
								
								return JBIConfigureMojo.this.configureWSDLServiceUnit(desc, new OnWsdlImport() {
									
									@Override
									public void onWsdlImport(final URI importURI, final Document importContent) throws IOException {
										
										final ByteArrayOutputStream baos = new ByteArrayOutputStream();
										DOMHelper.prettyPrint(importContent, baos);
										baos.close();
										
										filesToAdd.add(new ByteArrayOutputStreamEntry(baos, importURI.toString()));
									}
								});
								
							} catch (final Exception e) {
								throw new MojoExecutionException("Error packaging WSDL resources", e);
							}
							
                } else if (JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE.equals(zipEntry.getName())) {
                            // The ZIP entry is the JBI descriptor, we update it
                            try {
                            	final org.ow2.petals.component.framework.jbidescriptor.generated.Jbi jbiDescriptor;
                            	{
                                	final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                	IOUtils.copy(zipEntryInputStream, baos);
                                    jbiDescriptor = CDKJBIDescriptorBuilder.getInstance().buildJavaJBIDescriptor(
                                            new ByteArrayInputStream(baos.toByteArray()));
                            	}

                                final org.ow2.petals.component.framework.jbidescriptor.generated.Services services = jbiDescriptor.getServices();

                                if (serviceUnitId != null) {
	                                // We update the interception configuration (service unit identifier is required to
                                	// be able to exclude a service unit from an interception configuration)
	                                	
                                	for (final Consumes consume : services.getConsumes()) {
                                		
                                		final Map<String, List<SUInterceptor>> interceptionCfg = getInterceptionConfiguration(JBIConfigureMojo.this.serviceInterceptionConfigurationName, "consumer", consume.getInterfaceName(), consume.getServiceName(), consume.getEndpointName());
                                		if (consume.getSuInterceptors() == null) {
                                			consume.setSuInterceptors(new SUInterceptors());
    	                        		}
    	                        		
                                		if (interceptionCfg.containsKey("accept")) {
                                			final Accept accept = new Accept();
                                			accept.getInterceptor().clear();
                                			accept.getInterceptor().addAll(interceptionCfg.get("accept"));
                                			consume.getSuInterceptors().setAccept(accept);
                                		}
                                		if (interceptionCfg.containsKey("accept-response")) {
                                			final AcceptResponse acceptResponse = new AcceptResponse();
                                			acceptResponse.getInterceptor().clear();
                                			acceptResponse.getInterceptor().addAll(interceptionCfg.get("accept-response"));
                                			consume.getSuInterceptors().setAcceptResponse(acceptResponse);
                                		}
                                		if (interceptionCfg.containsKey("send")) {
                                			final Send send = new Send();
                                			send.getInterceptor().clear();
                                			send.getInterceptor().addAll(interceptionCfg.get("send"));
                                			consume.getSuInterceptors().setSend(send);
                                		}
                                		if (interceptionCfg.containsKey("send-response")) {
                                			final SendResponse sendResponse = new SendResponse();
                                			sendResponse.getInterceptor().clear();
                                			sendResponse.getInterceptor().addAll(interceptionCfg.get("send-response"));
                                			consume.getSuInterceptors().setSendResponse(sendResponse);
                                		}
                                		
                                	}
                                }
                            	
	                        	for (final Provides provide : services.getProvides()) {
	                        		
	                        		final Map<String, List<SUInterceptor>> interceptionCfg = getInterceptionConfiguration(JBIConfigureMojo.this.serviceInterceptionConfigurationName, "provider", provide.getInterfaceName(), provide.getServiceName(), provide.getEndpointName());
	                        		if (provide.getSuInterceptors() == null) {
	                        			provide.setSuInterceptors(new SUInterceptors());
	                        		}
	                        		if (interceptionCfg.containsKey("accept")) {
	                        			final Accept accept = new Accept();
	                        			accept.getInterceptor().clear();
	                        			accept.getInterceptor().addAll(interceptionCfg.get("accept"));
	                        			provide.getSuInterceptors().setAccept(accept);
	                        		}
	                        		if (interceptionCfg.containsKey("accept-response")) {
	                        			final AcceptResponse acceptResponse = new AcceptResponse();
	                        			acceptResponse.getInterceptor().clear();
	                        			acceptResponse.getInterceptor().addAll(interceptionCfg.get("accept-response"));
	                        			provide.getSuInterceptors().setAcceptResponse(acceptResponse);
	                        		}
	                        		if (interceptionCfg.containsKey("send")) {
	                        			final Send send = new Send();
	                        			send.getInterceptor().clear();
	                        			send.getInterceptor().addAll(interceptionCfg.get("send"));
	                        			provide.getSuInterceptors().setSend(send);
	                        		}
	                        		if (interceptionCfg.containsKey("send-response")) {
	                        			final SendResponse sendResponse = new SendResponse();
	                        			sendResponse.getInterceptor().clear();
	                        			sendResponse.getInterceptor().addAll(interceptionCfg.get("send-response"));
	                        			provide.getSuInterceptors().setSendResponse(sendResponse);
	                        		}
	                        		
	                        	}
                                
                                final ByteArrayOutputStream baosUpdatedJbiDesc = new ByteArrayOutputStream();
                                CDKJBIDescriptorBuilder.getInstance().writeXMLJBIdescriptor(jbiDescriptor, baosUpdatedJbiDesc);
                                // Reset of the JBI descriptor file time
                                zipEntry.setTime(System.currentTimeMillis());
                                return new ByteArrayInputStream(baosUpdatedJbiDesc.toByteArray());
                            } catch (final JBIDescriptorException e) {
                                throw new MojoExecutionException(
                                        "Error reading JBI descriptor.", e);
                            }
						}
						else {
							JBIConfigureMojo.this.debug("Copy a file of the SU: " + zipEntry.getName());
                            return zipEntryInputStream;
                        }
					}
        		},
                this.getLog());
    }

    @Override
    protected MavenProject getMavenProject() {
        return this.providedProject;
    }
}
