All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.petals.ant.task.ConfigureServiceAssemblyTask Maven / Gradle / Ivy

There is a newer version: 2.9.0
Show newest version
/**
 * Copyright (c) 2009-2012 EBM WebSourcing, 2012-2016 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.ant.task;

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.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.LogLevel;
import org.ow2.petals.ant.AbstractConfigureArchiveAntTask;
import org.ow2.petals.ant.util.NioUtil;
import org.ow2.petals.ant.util.ZipUtil;
import org.ow2.petals.ant.util.ZipUtil.ZipEntryCallback;
import org.ow2.petals.jbi.descriptor.JBIDescriptorException;
import org.ow2.petals.jbi.descriptor.original.JBIDescriptorBuilder;
import org.ow2.petals.jbi.descriptor.original.generated.Consumes;
import org.ow2.petals.jbi.descriptor.original.generated.Jbi;
import org.ow2.petals.jbi.descriptor.original.generated.Provides;
import org.w3c.dom.Element;

/**
 * @author Roland Naudin - EBM WebSourcing
 */
public class ConfigureServiceAssemblyTask extends AbstractConfigureArchiveAntTask {

    /**
     * The Service Unit class.
     * 
     * @author rnaudin
     * 
     */
    public static final class ServiceUnit {

        private String endpoint;

        private String identification;

        private String param;

        private String value;

        public ServiceUnit() {
            super();
        }

        public String getEndpoint() {
            return endpoint;
        }

        public String getIdentification() {
            return identification;
        }

        public String getParam() {
            return param;
        }

        public String getValue() {
            return value;
        }

        public void setEndpoint(final String endpoint) {
            this.endpoint = endpoint;
        }

        public void setIdentification(final String identification) {
            this.identification = identification;
        }

        public void setParam(final String param) {
            this.param = param;
        }

        public void setValue(final String value) {
            this.value = value;
        }
    }

    /**
     * Inner structure.
     * 
     * @author rnaudin
     * 
     */
    private static final class _ServiceUnit {

        public String endpoint;

        public String param;

        public String suName;

        public String suZipName;

        public String value;

        public _ServiceUnit(final String endpoint, final String param, final String value) {
            super();
            this.endpoint = endpoint;
            this.param = param;
            this.value = value;
        }
    }

    private static final String CDK_NAMESPACE_PREFIX = "http://petals.ow2.org/components/extensions";

    private static final String COMPONENT_NAMESPACE_PREFIX = "http://petals.ow2.org/components/";

    /**
     * The aimed identification of the Service Assembly.
     */
    private String identification;

    private final List serviceUnits = new ArrayList();

    /**
     * Location of the file that contains ServiceUnit properties. The keys must
     * in the form mySUName.myParam or mySUName.muEndpoint.myParam
     */
    private String suProperties;

    public ServiceUnit createServiceUnit() {
        final ServiceUnit serviceUnit = new ServiceUnit();
        this.serviceUnits.add(serviceUnit);
        return serviceUnit;
    }

    @Override
    public void execute() throws BuildException {
        super.execute();

        try {
            this.loadServiceUnitProperties();

            // load the SA JBI descriptor
            final URL saUrl = validateFileParameter(this.file, "file");
            final File saFile = downloadURL(saUrl);
            try {
                final ZipFile saZip = new ZipFile(saFile);
                try {
                    final Jbi saJbi = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptorFromArchive(saZip);

                    // set the identification
                    if (this.identification != null) {
                        saJbi.getServiceAssembly().getIdentification().setName(this.identification);
                    }

                    // build the Service Unit structure
                    final Map> _serviceUnits = new HashMap>();
                    for (final ServiceUnit serviceUnit : this.serviceUnits) {
                        if (serviceUnit.identification == null) {
                            throw new BuildException("Missing attribute 'identification' in a Service Unit element");
                        }
                        if (serviceUnit.param == null) {
                            throw new BuildException("Missing attribute 'param' in a Service Unit element");
                        }
                        if (serviceUnit.value == null) {
                            throw new BuildException("Missing attribute 'value' in a Service Unit element");
                        }

                        List<_ServiceUnit> _serviceUnitList = _serviceUnits.get(serviceUnit.identification);
                        if (_serviceUnitList == null) {
                            _serviceUnitList = new ArrayList<_ServiceUnit>();
                            _serviceUnits.put(serviceUnit.identification, _serviceUnitList);
                        }

                        _serviceUnitList.add(new _ServiceUnit(serviceUnit.endpoint, serviceUnit.param,
                                serviceUnit.value));
                    }

                    // get the list of Service Units ZIPs
                    for (final org.ow2.petals.jbi.descriptor.original.generated.ServiceUnit extractServiceUnit : saJbi
                            .getServiceAssembly().getServiceUnit()) {
                        List<_ServiceUnit> _serviceUnitList = _serviceUnits.get(extractServiceUnit.getIdentification()
                                .getName());
                        if (_serviceUnitList != null) {
                            _serviceUnitList.get(0).suZipName = extractServiceUnit.getTarget().getArtifactsZip();
                            _serviceUnitList.get(0).suName = extractServiceUnit.getIdentification().getName();
                        }
                    }

                    // update the selected Service Units
                    final Map udpatedSuFiles = new HashMap();
                    for (final Entry> _serviceUnitEntry : _serviceUnits.entrySet()) {
                        if (_serviceUnitEntry.getValue().get(0).suZipName != null) {
                            this.updateServiceUnit(_serviceUnitEntry.getValue(), udpatedSuFiles, saZip);
                        } else {
                            this.log("The Service Unit with identification '" + _serviceUnitEntry.getKey()
                                    + "' do not exist in the target Service Assembly", LogLevel.WARN.getLevel());
                        }
                    }

                    // /build the target Service Assembly
                    final ZipOutputStream zipOutputFile = new ZipOutputStream(new FileOutputStream(this.outputFile));

                    ZipUtil.copyAndUpdateZipFile(saZip, zipOutputFile, new ZipEntryCallback() {
                        public InputStream onZipEntry(final ZipEntry zipEntry, final InputStream zipEntryInputStream)
                                throws IOException, JBIDescriptorException {
                            if (udpatedSuFiles.containsKey(zipEntry.getName())) {
                                return udpatedSuFiles.get(zipEntry.getName());
                            } else if (JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE.equals(zipEntry
                                    .getName())) {
                                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                JBIDescriptorBuilder.getInstance().writeXMLJBIdescriptor(saJbi, baos);
                                return new ByteArrayInputStream(baos.toByteArray());
                            } else {
                                return zipEntryInputStream;
                            }
                        }
                    });
                    zipOutputFile.flush();
                    zipOutputFile.close();
                } finally {
                    saZip.close();
                }
            } finally {
                if (!saFile.delete()) {
                    this.log("Unable to delete intermediate downloaded file '" + saFile.getAbsolutePath()
                            + "'. Unknown reason.", Project.MSG_WARN);
                }
            }
        } catch (IOException e) {
            throw new BuildException(e);
        } catch (JBIDescriptorException e) {
            throw new BuildException(e);
        }
    }

    public String getIdentification() {
        return identification;
    }

    public String getSuProperties() {
        return suProperties;
    }

    public void setIdentification(final String identification) {
        this.identification = identification;
    }

    public void setSuProperties(final String suProperties) {
        this.suProperties = suProperties;
    }

    /**
     * Concat splittedKeys ending with \ to be able to have '.' in su names.
     * 
     */
    private String[] analyseSplittedKeys(final String[] splittedKey) {

        String[] correctedSplittedKeys;
        final String[] newSplittedKeys = new String[splittedKey.length];
        int i = 0;
        int j = 0;

        // concat keys ending with \ and store them in a temporary array.
        while (i < splittedKey.length) {
            String key = splittedKey[i];
            while (key.endsWith("\\")) {
                key = key.substring(0, key.length() - 1);
                key += "." + splittedKey[++i];
            }
            newSplittedKeys[j++] = key;
            i++;
        }
        // Create final array with correct length
        correctedSplittedKeys = new String[j];
        for (int k = 0; k < correctedSplittedKeys.length; k++) {
            correctedSplittedKeys[k] = newSplittedKeys[k];
        }
        return correctedSplittedKeys;
    }

    /**
     * Load the Service Unit properties.
     * 
     * @throws IOException
     */
    private void loadServiceUnitProperties() throws IOException {
        final Properties props = new Properties();
        if (this.suProperties != null) {
            final InputStream isProperties = new FileInputStream(this.suProperties);
            try {
                props.load(isProperties);
            } finally {
                isProperties.close();
            }
        }
        for (final Entry entry : props.entrySet()) {
            final String keyString = (String) entry.getKey();
            final String[] splittedKey = keyString.split("\\.");
            final String[] correctedSplittedKeys = analyseSplittedKeys(splittedKey);
            if (correctedSplittedKeys.length < 2 || correctedSplittedKeys.length > 4) {
                throw new BuildException(
                        "Unexpected property name. Name must be in the form su-name.[endpoint-name].['cdk'|'component'].parameter-name=parameter-value");
            }

            final ServiceUnit serviceUnit = new ServiceUnit();
            serviceUnit.setIdentification(correctedSplittedKeys[0]);

            if (correctedSplittedKeys.length == 2) {
                serviceUnit.setParam(correctedSplittedKeys[1]);
            } else if (correctedSplittedKeys.length == 3) {
                if (correctedSplittedKeys[1].equals("cdk")
                        || correctedSplittedKeys[1].equals("component")) {
                    serviceUnit.setParam(correctedSplittedKeys[1] + "." + correctedSplittedKeys[2]);
                } else {
                    serviceUnit.setEndpoint(correctedSplittedKeys[1]);
                    serviceUnit.setParam(correctedSplittedKeys[2]);
                }
            } else {
                serviceUnit.setEndpoint(correctedSplittedKeys[1]);
                serviceUnit.setParam(correctedSplittedKeys[2] + "." + correctedSplittedKeys[3]);
            }
            serviceUnit.setValue((String) entry.getValue());
            this.serviceUnits.add(serviceUnit);
        }
    }

    /**
     * Update the given parameter in the list of DOM elements.
     * 
     * @param elements
     * @param namespace
     * @param param
     * @param value
     * @return
     */
    private final boolean updateParameter(final List elements, final String namespace, final String param,
            final String value, final String suName) {
        boolean found = false;

        for (final Element element : elements) {
            if (namespace != null) {
                // tricky namespace detection.
                if (!element.getNamespaceURI().startsWith(namespace)) {
                    continue;
                } else if (namespace.equals(COMPONENT_NAMESPACE_PREFIX)
                        && element.getNamespaceURI().startsWith(CDK_NAMESPACE_PREFIX)) {
                    continue;
                }
            }
            if (element.getLocalName().equals(param)) {
                element.setTextContent(value);
                found = true;
                this.log("Parameter '" + param + "' set to value '" + value
                        + "' in the Service Unit '" + suName + "'");
                break;
            }
        }

        return found;
    }

    /**
     * Update a Service Unit.
     * 
     * @param _serviceUnitList
     * @param udpatedSuFiles
     * @param saZip
     * @throws IOException
     * @throws JBIDescriptorException
     */
    private void updateServiceUnit(final List<_ServiceUnit> _serviceUnitList,
            final Map udpatedSuFiles, final ZipFile saZip) throws IOException,
            JBIDescriptorException {
        final String suZipName = _serviceUnitList.get(0).suZipName;
        final String suName = _serviceUnitList.get(0).suName;
        final ZipEntry suZipEntry = saZip.getEntry(suZipName);
        final InputStream suInputStream = saZip.getInputStream(suZipEntry);
        final File suTempFile = File.createTempFile(suZipName, null);
        NioUtil.copyStreamToFile(suInputStream, suTempFile);
        try (final ZipFile suTempZip = new ZipFile(suTempFile)) {
            final Jbi suJbi = JBIDescriptorBuilder.getInstance().buildJavaJBIDescriptorFromArchive(suTempZip);

            boolean found;
            String namespace = null;
            for (final _ServiceUnit _serviceUnit : _serviceUnitList) {
                found = false;
    
                if (_serviceUnit.param.startsWith("cdk.")) {
                    namespace = CDK_NAMESPACE_PREFIX;
                    _serviceUnit.param = _serviceUnit.param.substring(4);
                } else if (_serviceUnit.param.startsWith("component.")) {
                    namespace = COMPONENT_NAMESPACE_PREFIX;
                    _serviceUnit.param = _serviceUnit.param.substring(10);
                }
    
                for (final Consumes consumes : suJbi.getServices().getConsumes()) {
                    if (_serviceUnit.endpoint == null
                            || _serviceUnit.endpoint.equals(consumes.getEndpointName())) {
                        found = updateParameter(consumes.getAnyOrAny(), namespace, _serviceUnit.param,
                                _serviceUnit.value, suName);
                        if (found) {
                            break;
                        }
                    }
                }
                if (!found) {
                    for (final Provides provides : suJbi.getServices().getProvides()) {
                        if (_serviceUnit.endpoint == null
                                || _serviceUnit.endpoint.equals(provides.getEndpointName())) {
                            found = updateParameter(provides.getAnyOrAny(), namespace,
                                    _serviceUnit.param, _serviceUnit.value, suName);
                            if (found) {
                                break;
                            }
                        }
                    }
                }
    
                if (!found) {
                    this.log("Failed to find parameter '" + _serviceUnit.param
                            + "' in the Service Unit '" + suName + "'", LogLevel.WARN.getLevel());
                }
            }
    
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            JBIDescriptorBuilder.getInstance().writeXMLJBIdescriptor(suJbi, baos);
            final InputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
    
            final File suFile = File.createTempFile(suZipName.substring(0, suZipName.length() - 4),
                    ".zip");
            final ZipOutputStream zipOutputFile = new ZipOutputStream(new FileOutputStream(suFile));
    
            ZipUtil.copyAndUpdateZipFile(suTempZip, zipOutputFile,
                    new ZipEntryCallback() {
                        public InputStream onZipEntry(final ZipEntry zipEntry,
                                final InputStream zipEntryInputStream) throws IOException,
                                JBIDescriptorException {
                            if (JBIDescriptorBuilder.JBI_DESCRIPTOR_RESOURCE_IN_ARCHIVE.equals(zipEntry.getName())) {
                                return inputStream;
                            } else {
                                return zipEntryInputStream;
                            }
                        }
                    });
            zipOutputFile.flush();
            zipOutputFile.close();
    
            final InputStream isSuFile = new FileInputStream(suFile);
            try {
                udpatedSuFiles.put(suZipName, isSuFile);
            } finally {
                isSuFile.close();
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy