com.azaptree.services.spring.application.config.SpringApplicationServiceConfig.java Source code

Java tutorial

Introduction

Here is the source code for com.azaptree.services.spring.application.config.SpringApplicationServiceConfig.java

Source

package com.azaptree.services.spring.application.config;

/*
 * #%L
 * AZAPTREE-SPRING-APPLICATION-SERVICE
 * %%
 * Copyright (C) 2012 - 2013 AZAPTREE.COM
 * %%
 * 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.
 * #L%
 */

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.util.JAXBSource;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.xml.sax.SAXException;

import com.azaptree.services.commons.xml.XmlUtils;
import com.azaptree.services.spring.application.config.SpringApplicationService.ConfigurationClasses;
import com.azaptree.services.spring.application.config.SpringApplicationService.JvmSystemProperties;
import com.azaptree.services.spring.application.config.SpringApplicationService.JvmSystemProperties.Prop;
import com.azaptree.services.spring.application.config.SpringApplicationService.SpringProfiles;

public class SpringApplicationServiceConfig {

    private Class<?>[] configurationClasses;

    private Properties jvmSystemProperties;

    private String[] springProfiles;

    public SpringApplicationServiceConfig(final InputStream xml) throws JAXBException, ClassNotFoundException {
        init(xml);
    }

    public SpringApplicationServiceConfig(final String xmlLocation)
            throws IOException, ClassNotFoundException, JAXBException {
        Assert.hasText(xmlLocation, "xmlResourcePath is required");
        final PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        final Resource resource = resourceResolver.getResource(xmlLocation);

        try (InputStream xml = resource.getInputStream()) {
            init(xml);
        }
    }

    public AnnotationConfigApplicationContext createAnnotationConfigApplicationContext() {
        final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        if (ArrayUtils.isNotEmpty(springProfiles)) {
            ctx.getEnvironment().setActiveProfiles(springProfiles);
        }

        if (ArrayUtils.isNotEmpty(configurationClasses)) {
            for (final Class<?> c : configurationClasses) {
                ctx.register(c);
            }
        }

        ctx.refresh();
        ctx.registerShutdownHook();
        return ctx;
    }

    private void generateSchema(final OutputStream os) {
        try {
            JAXBContext.newInstance(SpringApplicationService.class).generateSchema(new SchemaOutputResolver() {

                @Override
                public Result createOutput(final String namespaceUri, final String suggestedFileName)
                        throws IOException {
                    final StreamResult result = new StreamResult(os);
                    result.setSystemId("");
                    return result;
                }
            });
        } catch (final IOException | JAXBException e) {
            throw new RuntimeException("generateSchema() failed", e);
        }
    }

    /**
     * Spring Configuration classes - used to configure a Spring ApplicationContext using Java based configuration
     * 
     * @return
     */
    public Class<?>[] getConfigurationClasses() {
        return configurationClasses;
    }

    /**
     * Before creating the Spring ApplicationContext, the specified JVM system properties will be set
     * 
     * @return
     */
    public Properties getJvmSystemProperties() {
        return jvmSystemProperties;
    }

    private void init(final InputStream xml) throws JAXBException, ClassNotFoundException {
        Assert.notNull(xml, "xml is required");
        final SpringApplicationService config = parse(xml);
        log(config);
        loadConfigurationClasses(config);
        loadJvmSystemProperties(config);
        loadSpringProfiles(config);
    }

    private void loadSpringProfiles(SpringApplicationService config) {
        final SpringProfiles springProfiles = config.getSpringProfiles();
        if (springProfiles != null) {
            final List<String> profiles = springProfiles.getProfile();
            if (!CollectionUtils.isEmpty(profiles)) {
                this.springProfiles = profiles.toArray(new String[profiles.size()]);
            }
        }
    }

    private void loadConfigurationClasses(final SpringApplicationService config) throws ClassNotFoundException {
        final ConfigurationClasses configurationClasses = config.getConfigurationClasses();
        if (configurationClasses != null && !CollectionUtils.isEmpty(configurationClasses.getClazz())) {
            final ClassLoader cl = getClass().getClassLoader();
            final List<Class<?>> configClasses = new ArrayList<>(configurationClasses.getClazz().size());
            for (final String clazz : configurationClasses.getClazz()) {
                final Class<?> c = cl.loadClass(clazz.trim());
                if (c.getAnnotation(Configuration.class) == null) {
                    throw new IllegalArgumentException(String.format(
                            "Class must be annotated with @org.springframework.context.annotation.Configuration: {}",
                            clazz));
                }
                configClasses.add(c);
            }
            this.configurationClasses = configClasses.toArray(new Class<?>[configClasses.size()]);
        }

    }

    private void loadJvmSystemProperties(final SpringApplicationService config) {
        final JvmSystemProperties props = config.getJvmSystemProperties();
        if (props != null && !CollectionUtils.isEmpty(props.getProp())) {
            jvmSystemProperties = new Properties();
            for (final Prop prop : props.getProp()) {
                jvmSystemProperties.setProperty(prop.getName(), prop.getValue().trim());
            }
        }
    }

    private void log(final SpringApplicationService config) {
        final StringWriter sw = new StringWriter();
        final Marshaller m;
        try {
            final JAXBContext ctx = JAXBContext.newInstance(SpringApplicationService.class.getPackage().getName());
            m = ctx.createMarshaller();
        } catch (final JAXBException e) {
            throw new IllegalStateException("Failed to create marshller ", e);
        }

        try {
            m.marshal(config, sw);
        } catch (final JAXBException e) {
            throw new IllegalStateException("Failed to marshal SpringApplicationService", e);
        }

        LoggerFactory.getLogger(getClass()).info("XML config:\n{}", XmlUtils.prettyFormatXml(sw.toString(), 4));
    }

    private SpringApplicationService parse(final InputStream xml) throws JAXBException {
        Assert.notNull(xml);
        final JAXBContext jc = JAXBContext.newInstance(SpringApplicationService.class);
        final Unmarshaller u = jc.createUnmarshaller();
        final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final ByteArrayOutputStream bos = new ByteArrayOutputStream(512);
        generateSchema(bos);
        try {
            final SpringApplicationService springApplicationService = (SpringApplicationService) u.unmarshal(xml);
            final Schema schema = schemaFactory
                    .newSchema(new StreamSource(new ByteArrayInputStream(bos.toByteArray())));
            final Validator validator = schema.newValidator();
            validator.validate(new JAXBSource(jc, springApplicationService));
            return springApplicationService;
        } catch (SAXException | IOException e) {
            throw new IllegalArgumentException(
                    "Failed to parse XML. The XML must conform to the following schema:\n" + bos, e);
        }
    }

    @Override
    public String toString() {
        final ToStringBuilder sb = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
        if (ArrayUtils.isNotEmpty(configurationClasses)) {
            final String[] names = new String[configurationClasses.length];
            for (int i = 0; i < names.length; i++) {
                names[i] = configurationClasses[i].getName();
            }
            sb.append("configurationClasses", Arrays.toString(names));
        }
        if (ArrayUtils.isNotEmpty(springProfiles)) {
            sb.append("springProfiles", Arrays.toString(springProfiles));
        }

        if (!CollectionUtils.isEmpty(jvmSystemProperties)) {
            final StringWriter sw = new StringWriter(256);
            try {
                jvmSystemProperties.store(sw, "JVM System Propperties");
            } catch (final IOException e) {
                throw new RuntimeException(e);
            }
            sb.append("jvmSystemProperties", sw.toString());
        }

        return sb.toString();
    }
}