Package com.consol.citrus.admin.service

Source Code of com.consol.citrus.admin.service.SpringBeanService

/*
* Copyright 2006-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.consol.citrus.admin.service;

import com.consol.citrus.admin.exception.CitrusAdminRuntimeException;
import com.consol.citrus.admin.spring.config.*;
import com.consol.citrus.admin.spring.model.SpringBean;
import com.consol.citrus.admin.jaxb.JAXBHelper;
import com.consol.citrus.util.FileUtils;
import com.consol.citrus.util.XMLUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.w3c.dom.Element;
import org.w3c.dom.ls.LSParser;
import org.w3c.dom.ls.LSSerializer;

import javax.annotation.PostConstruct;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.util.*;

/**
* Service is able to add, remove update Spring XML bean definitions to some ordinary
* Spring XML application context. Service uses XML load and save parser and serializer
* in order to manipulate XML contents.
*
* @author Christoph Deppisch
*/
@Component
public class SpringBeanService {

    @Autowired
    protected JAXBHelper jaxbHelper;
   
    /** JaxBContext holds xml bean definition packages known to this context */
    private JAXBContext jaxbContext;

    /** XSLT transformer factory */
    private TransformerFactory transformerFactory = TransformerFactory.newInstance();

    /** Logger */
    private static Logger log = LoggerFactory.getLogger(SpringBeanService.class);
   
    @PostConstruct
    protected void init() {
        jaxbContext = jaxbHelper.createJAXBContextByPath(
                "com.consol.citrus.admin.spring.model",
                "com.consol.citrus.model.config.core",
                "com.consol.citrus.model.config.jms",
                "com.consol.citrus.model.config.ws",
                "com.consol.citrus.model.config.mail",
                "com.consol.citrus.model.config.ssh",
                "com.consol.citrus.model.config.vertx",
                "com.consol.citrus.model.config.ftp",
                "com.consol.citrus.model.config.http");

        transformerFactory.setURIResolver(new URIResolver() {
            @Override
            public Source resolve(String href, String base) throws TransformerException {
                try {
                    return new StreamSource(new ClassPathResource("com/consol/citrus/admin/transform/" + href).getInputStream());
                } catch (IOException e) {
                    throw new TransformerException("Failed to resolve uri: " + href, e);
                }
            }
        });
    }

    /**
     * Reads file import locations from Spring bean application context.
     * @param configFile
     * @return
     */
    public List<File> getConfigImports(File configFile) {
        LSParser parser = XMLUtils.createLSParser();

        GetSpringImportsFilter filter = new GetSpringImportsFilter(configFile);
        parser.setFilter(filter);
        parser.parseURI(configFile.toURI().toString());

        return filter.getImportedFiles();
    }
   
    /**
     * Finds bean definition element by id and type in Spring application context and
     * performs unmarshalling in order to return JaxB object.
     * @param configFile
     * @param id
     * @param type
     * @return
     */
    public <T> T getBeanDefinition(File configFile, String id, Class<T> type) {
        LSParser parser = XMLUtils.createLSParser();

        GetSpringBeanFilter filter = new GetSpringBeanFilter(id, type);
        parser.setFilter(filter);

        List<File> configFiles = new ArrayList<File>();
        configFiles.add(configFile);
        configFiles.addAll(getConfigImports(configFile));

        for (File file : configFiles) {
            parser.parseURI(file.toURI().toString());

            if (filter.getBeanDefinition() != null) {
                return createJaxbObjectFromElement(filter.getBeanDefinition(), type);
            }
        }

        return null;
    }
   
    /**
     * Finds all bean definition elements by type in Spring application context and
     * performs unmarshalling in order to return a list of JaxB object.
     * @param configFile
     * @param type
     * @return
     */
    public <T> List<T> getBeanDefinitions(File configFile, Class<T> type) {
        return getBeanDefinitions(configFile, type, null);
    }

    /**
     * Finds all bean definition elements by type and attribute values in Spring application context and
     * performs unmarshalling in order to return a list of JaxB object.
     * @param configFile
     * @param type
     * @param attributes
     * @return
     */
    public <T> List<T> getBeanDefinitions(File configFile, Class<T> type, Map<String, String> attributes) {
        List<T> beanDefinitions = new ArrayList<T>();

        List<File> importedFiles = getConfigImports(configFile);
        for (File importLocation : importedFiles) {
            beanDefinitions.addAll(getBeanDefinitions(importLocation, type, attributes));
        }

        LSParser parser = XMLUtils.createLSParser();

        GetSpringBeansFilter filter = new GetSpringBeansFilter(type, attributes);
        parser.setFilter(filter);
        parser.parseURI(configFile.toURI().toString());

        for (Element element : filter.getBeanDefinitions()) {
            beanDefinitions.add(createJaxbObjectFromElement(element, type));
        }

        return beanDefinitions;
    }

    /**
     * Find all Spring bean definitions in application context for given bean type.
     * @param configFile
     * @param beanType
     * @return
     */
    public List<String> getBeanNames(File configFile, String beanType) {
        List<SpringBean> beanDefinitions = getBeanDefinitions(configFile, SpringBean.class, Collections.singletonMap("class", beanType));

        List<String> beanNames = new ArrayList<String>();
        for (SpringBean beanDefinition : beanDefinitions) {
            beanNames.add(beanDefinition.getId());
        }

        return beanNames;
    }
   
    /**
     * Method adds a new Spring bean definition to the XML application context file.
     * @param configFile
     * @param jaxbElement
     */
    public void addBeanDefinition(File configFile, Object jaxbElement) {
        Source xsltSource;
        Source xmlSource;
        try {
            xsltSource = new StreamSource(new ClassPathResource("com/consol/citrus/admin/transform/add-bean.xsl").getInputStream());
            xsltSource.setSystemId("add-bean");
            xmlSource = new StringSource(FileUtils.readToString(new FileInputStream(configFile)));

            //create transformer
            Transformer transformer = transformerFactory.newTransformer(xsltSource);
            transformer.setParameter("bean_content", getXmlContent(jaxbElement));

            //transform
            StringResult result = new StringResult();
            transformer.transform(xmlSource, result);
            FileUtils.writeToFile(result.toString(), configFile);
            return;
        } catch (IOException e) {
            throw new CitrusAdminRuntimeException("Unable to read update bean definition transformation source", e);
        } catch (TransformerException e) {
            throw new CitrusAdminRuntimeException("Failed to update bean definition", e);
        }
    }
   
    /**
     * Method removes a Spring bean definition from the XML application context file. Bean definition is
     * identified by its id or bean name.
     * @param configFile
     * @param id
     */
    public void removeBeanDefinition(File configFile, String id) {
        Source xsltSource;
        Source xmlSource;
        try {
            xsltSource = new StreamSource(new ClassPathResource("com/consol/citrus/admin/transform/delete-bean.xsl").getInputStream());
            xsltSource.setSystemId("delete-bean");

            List<File> configFiles = new ArrayList<File>();
            configFiles.add(configFile);
            configFiles.addAll(getConfigImports(configFile));

            for (File file : configFiles) {
                xmlSource = new StringSource(FileUtils.readToString(new FileInputStream(configFile)));

                //create transformer
                Transformer transformer = transformerFactory.newTransformer(xsltSource);
                transformer.setParameter("bean_id", id);

                //transform
                StringResult result = new StringResult();
                transformer.transform(xmlSource, result);
                FileUtils.writeToFile(result.toString(), file);
                return;
            }
        } catch (IOException e) {
            throw new CitrusAdminRuntimeException("Unable to read update bean definition transformation source", e);
        } catch (TransformerException e) {
            throw new CitrusAdminRuntimeException("Failed to update bean definition", e);
        }
    }

    /**
     * Method removes all Spring bean definitions of given type from the XML application context file.
     * @param configFile
     * @param type
     */
    public void removeBeanDefinitions(File configFile, Class<?> type) {
        Source xsltSource;
        Source xmlSource;
        try {
            xsltSource = new StreamSource(new ClassPathResource("com/consol/citrus/admin/transform/delete-bean-type.xsl").getInputStream());
            xsltSource.setSystemId("delete-bean");

            List<File> configFiles = new ArrayList<File>();
            configFiles.add(configFile);
            configFiles.addAll(getConfigImports(configFile));

            for (File file : configFiles) {
                xmlSource = new StringSource(FileUtils.readToString(new FileInputStream(configFile)));

                String beanElement = type.getAnnotation(XmlRootElement.class).name();
                String beanNamespace = type.getPackage().getAnnotation(XmlSchema.class).namespace();

                //create transformer
                Transformer transformer = transformerFactory.newTransformer(xsltSource);
                transformer.setParameter("bean_element", beanElement);
                transformer.setParameter("bean_namespace", beanNamespace);

                //transform
                StringResult result = new StringResult();
                transformer.transform(xmlSource, result);
                FileUtils.writeToFile(result.toString(), file);
                return;
            }
        } catch (IOException e) {
            throw new CitrusAdminRuntimeException("Unable to read update bean definition transformation source", e);
        } catch (TransformerException e) {
            throw new CitrusAdminRuntimeException("Failed to update bean definition", e);
        }
    }
   
    /**
     * Method updates an existing Spring bean definition in a XML application context file. Bean definition is
     * identified by its id or bean name.
     * @param configFile
     * @param id
     * @param jaxbElement
     */
    public void updateBeanDefinition(File configFile, String id, Object jaxbElement) {
        Source xsltSource;
        Source xmlSource;
        try {
            xsltSource = new StreamSource(new ClassPathResource("com/consol/citrus/admin/transform/update-bean.xsl").getInputStream());
            xsltSource.setSystemId("update-bean");

            List<File> configFiles = new ArrayList<File>();
            configFiles.add(configFile);
            configFiles.addAll(getConfigImports(configFile));

            LSParser parser = XMLUtils.createLSParser();
            GetSpringBeanFilter getBeanFilter = new GetSpringBeanFilter(id, jaxbElement.getClass());
            parser.setFilter(getBeanFilter);

            for (File file : configFiles) {
                parser.parseURI(file.toURI().toString());
                if (getBeanFilter.getBeanDefinition() != null) {
                    xmlSource = new StringSource(FileUtils.readToString(new FileInputStream(file)));

                    //create transformer
                    Transformer transformer = transformerFactory.newTransformer(xsltSource);
                    transformer.setParameter("bean_id", id);
                    transformer.setParameter("bean_content", getXmlContent(jaxbElement));

                    //transform
                    StringResult result = new StringResult();
                    transformer.transform(xmlSource, result);
                    FileUtils.writeToFile(result.toString(), file);
                    return;
                }
            }
        } catch (IOException e) {
            throw new CitrusAdminRuntimeException("Unable to read update bean definition transformation source", e);
        } catch (TransformerException e) {
            throw new CitrusAdminRuntimeException("Failed to update bean definition", e);
        }
    }

    /**
     * Method updates existing Spring bean definitions in a XML application context file. Bean definition is
     * identified by its type defining class.
     *
     * @param configFile
     * @param type
     * @param jaxbElement
     */
    public void updateBeanDefinitions(File configFile, Class<?> type, Object jaxbElement) {
        Source xsltSource;
        Source xmlSource;
        try {
            xsltSource = new StreamSource(new ClassPathResource("com/consol/citrus/admin/transform/update-bean-type.xsl").getInputStream());
            xsltSource.setSystemId("update-bean");

            List<File> configFiles = new ArrayList<File>();
            configFiles.add(configFile);
            configFiles.addAll(getConfigImports(configFile));

            LSParser parser = XMLUtils.createLSParser();
            GetSpringBeansFilter getBeanFilter = new GetSpringBeansFilter(type, null);
            parser.setFilter(getBeanFilter);

            for (File file : configFiles) {
                parser.parseURI(file.toURI().toString());
                if (!CollectionUtils.isEmpty(getBeanFilter.getBeanDefinitions())) {
                    xmlSource = new StringSource(FileUtils.readToString(new FileInputStream(file)));

                    String beanElement = type.getAnnotation(XmlRootElement.class).name();
                    String beanNamespace = type.getPackage().getAnnotation(XmlSchema.class).namespace();

                    //create transformer
                    Transformer transformer = transformerFactory.newTransformer(xsltSource);
                    transformer.setParameter("bean_element", beanElement);
                    transformer.setParameter("bean_namespace", beanNamespace);
                    transformer.setParameter("bean_content", getXmlContent(jaxbElement));

                    //transform
                    StringResult result = new StringResult();
                    transformer.transform(xmlSource, result);
                    FileUtils.writeToFile(result.toString(), file);
                    return;
                }
            }
        } catch (IOException e) {
            throw new CitrusAdminRuntimeException("Unable to read update bean definition transformation source", e);
        } catch (TransformerException e) {
            throw new CitrusAdminRuntimeException("Failed to update bean definition", e);
        }
    }

    /**
     * Marshal jaxb element and try to perform basic formatting like namespace clean up
     * and attribute formatting with xsl transformation.
     * @param jaxbElement
     * @return
     */
    private String getXmlContent(Object jaxbElement) {
        String jaxbContent = jaxbHelper.marshal(jaxbContext, jaxbElement);
        log.debug("Formatting bean definition: " + jaxbContent);

        Source xsltSource;
        try {
            xsltSource = new StreamSource(new ClassPathResource("com/consol/citrus/admin/transform/format-bean.xsl").getInputStream());
            Transformer transformer = transformerFactory.newTransformer(xsltSource);

            //transform
            StringResult result = new StringResult();
            transformer.transform(new StringSource(jaxbContent), result);

            return result.toString();
        } catch (IOException e) {
            throw new CitrusAdminRuntimeException("Unable to read update bean definition transformation source", e);
        } catch (TransformerException e) {
            throw new CitrusAdminRuntimeException("Failed to update bean definition", e);
        }
    }

    /**
     * Creates a DOM element node from JAXB element.
     * @param element
     * @param type
     * @return
     */
    private <T> T createJaxbObjectFromElement(Element element, Class<T> type) {
        LSSerializer serializer = XMLUtils.createLSSerializer();
        return jaxbHelper.unmarshal(jaxbContext, type, serializer.writeToString(element));
    }

}
TOP

Related Classes of com.consol.citrus.admin.service.SpringBeanService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.