Package com.avast.syringe.config

Source Code of com.avast.syringe.config.XmlSchemaGenerator

package com.avast.syringe.config;

import com.avast.syringe.config.internal.ConfigClassAnalyzer;
import com.avast.syringe.config.internal.InjectableProperty;
import com.avast.syringe.config.internal.ReflectionInjectableProperty;
import com.avast.syringe.config.internal.TypeConversion;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import nu.xom.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Set;

/**
* Generates an XML schema file describing the XML configuration for a given
* configuration class. Can be used via a {@link #generateXmlSchema(OutputStream) Java API}
* and it also provides a {@link #main(String...)}} method.
*/
public class XmlSchemaGenerator {

    public static final String NS_SCHEMA = "http://www.w3.org/2001/XMLSchema";
    public static final String SCHEMAS_URL = "http://www.avast.com/schemas/";

    private final Class<?> configClass;
    private final String namespaceUri;

    public static void main(String... args) throws Exception {

//        Package[] packages = Package.getPackages();
//        for (Package aPackage : packages) {
//            System.out.println(aPackage);
//        }
//
        if (args.length < 1) {
            System.out.println("Usage: java " + XmlSchemaGenerator.class + "<class> [<namespace-uri>]");
            System.exit(1);
        }

        Class<?> configClass = Class.forName(args[0]);
        if (args.length < 2) {
            new XmlSchemaGenerator(configClass).generateXmlSchema(System.out);
        } else {
            String namespaceUri = args[1];
            new XmlSchemaGenerator(configClass, namespaceUri).generateXmlSchema(System.out);
        }
    }

    public XmlSchemaGenerator(Class<?> configClass) {
        this(configClass, XmlInstanceGenerator.getNamespace(configClass));
    }

    public XmlSchemaGenerator(Class<?> configClass, String namespaceUri) {
        Preconditions.checkNotNull(configClass, "configClass");
        Preconditions.checkNotNull(namespaceUri, "namespaceUri");

        this.configClass = configClass;
        this.namespaceUri = namespaceUri;
    }

    public void generateXmlSchema(OutputStream output) throws IOException {
        Element schemaEl = new Element("xs:schema", NS_SCHEMA);
        schemaEl.addNamespaceDeclaration(null, namespaceUri);
        schemaEl.addAttribute(new Attribute("targetNamespace", namespaceUri));
        schemaEl.addAttribute(new Attribute("elementFormDefault", "qualified"));

        Element topElementEl = new Element("xs:element", NS_SCHEMA);
        topElementEl.addAttribute(new Attribute("name", "config"));
        schemaEl.appendChild(topElementEl);

        Element topComplexTypeEl = new Element("xs:complexType", NS_SCHEMA);
        topElementEl.appendChild(topComplexTypeEl);

        final Element topAllEl = new Element("xs:all", NS_SCHEMA);
        topComplexTypeEl.appendChild(topAllEl);

        // 'decorators' attribute in the <config> element
        final Element decorAttrEl = new Element("xs:attribute", NS_SCHEMA);
        decorAttrEl.addAttribute(new Attribute("name", "decorators"));
        decorAttrEl.addAttribute(new Attribute("type", "xs:string"));
        decorAttrEl.addAttribute(new Attribute("use", "optional"));

        topComplexTypeEl.appendChild(decorAttrEl);

        Set<InjectableProperty> listProperties = Sets.newHashSet();
        Set<InjectableProperty> mapProperties = Sets.newHashSet();
        Set<InjectableProperty> refProperties = Sets.newHashSet();

        HashSet<String> declaredRefTypes = Sets.newHashSet();

        for (InjectableProperty property : new ConfigClassAnalyzer(configClass).getConfigProperties()) {

            if (property.isContextual()) {
                // Ignore contextual properties
                continue;
            }

            String propTypeName;
            if (property.isArray() || property.isCollection()) {
                propTypeName = property.getName() + "Type";
                listProperties.add(property);
            } else if (property.isMap()) {
                propTypeName = property.getName() + "Type";
                mapProperties.add(property);
            } else if (property.isReference()) {
                propTypeName = property.getType().getName();
                refProperties.add(property);
            } else {
                propTypeName = TypeConversion.getXmlSchemaTypeName(property.getType());
            }

            Element elementEl = new Element("xs:element", NS_SCHEMA);
            elementEl.addAttribute(new Attribute("name", property.getName()));
            elementEl.addAttribute(new Attribute("type", propTypeName));
            String minOccurs = "1";
            if (property.isOptional()) {
                minOccurs = "0";
            }
            elementEl.addAttribute(new Attribute("minOccurs", minOccurs));
            elementEl.addAttribute(new Attribute("maxOccurs", "1"));
            topAllEl.appendChild(elementEl);
        }

        for (InjectableProperty property : listProperties) {
            Class<?> componentType = property.getArrayOrCollectionComponentType();
            String componentTypeName = TypeConversion.getXmlSchemaTypeName(componentType);

            Element complexTypeEl = new Element("xs:complexType", NS_SCHEMA);
            complexTypeEl.addAttribute(new Attribute("name", property.getName() + "Type"));
            schemaEl.appendChild(complexTypeEl);

            appendTypeInfoAnnotation(complexTypeEl, "list");

            Element sequenceEl = new Element("xs:sequence", NS_SCHEMA);
            complexTypeEl.appendChild(sequenceEl);

            Element elementEl = new Element("xs:element", NS_SCHEMA);
            elementEl.addAttribute(new Attribute("name", "value"));
            elementEl.addAttribute(new Attribute("type", componentTypeName));
            if (property.isOptional()) {
                elementEl.addAttribute(new Attribute("minOccurs", "0"));
            }
            elementEl.addAttribute(new Attribute("maxOccurs", "unbounded"));
            sequenceEl.appendChild(elementEl);

            // Declare the reference type
            if (ReflectionInjectableProperty.isReference(componentType)) {
                declareReferenceType(schemaEl, declaredRefTypes, componentTypeName);
            }
        }

        for (InjectableProperty property : mapProperties) {
            Class<?> keyType = property.getMapKeyType();
            Class<?> valueType = property.getMapValueType();
            String keyTypeName = TypeConversion.getXmlSchemaTypeName(keyType);
            String valueTypeName = TypeConversion.getXmlSchemaTypeName(valueType);

            Element complexTypeEl = new Element("xs:complexType", NS_SCHEMA);
            complexTypeEl.addAttribute(new Attribute("name", property.getName() + "Type"));
            schemaEl.appendChild(complexTypeEl);

            appendTypeInfoAnnotation(complexTypeEl, "map");

            Element sequenceEl = new Element("xs:sequence", NS_SCHEMA);
            complexTypeEl.appendChild(sequenceEl);

            Element elementEl = new Element("xs:element", NS_SCHEMA);
            elementEl.addAttribute(new Attribute("name", "entry"));
            if (property.isOptional()) {
                elementEl.addAttribute(new Attribute("minOccurs", "0"));
            }
            elementEl.addAttribute(new Attribute("maxOccurs", "unbounded"));
            sequenceEl.appendChild(elementEl);

            Element subComplexTypeEl = new Element("xs:complexType", NS_SCHEMA);
            elementEl.appendChild(subComplexTypeEl);

            Element simpleContentEl = new Element("xs:simpleContent", NS_SCHEMA);
            subComplexTypeEl.appendChild(simpleContentEl);

            Element extensionEl = new Element("xs:extension", NS_SCHEMA);
            extensionEl.addAttribute(new Attribute("base", valueTypeName));
            simpleContentEl.appendChild(extensionEl);

            Element attributeEl = new Element("xs:attribute", NS_SCHEMA);
            attributeEl.addAttribute(new Attribute("name", "key"));
            attributeEl.addAttribute(new Attribute("type", keyTypeName));
            attributeEl.addAttribute(new Attribute("use", "required"));
            extensionEl.appendChild(attributeEl);

            // Declare the reference type
            if (ReflectionInjectableProperty.isReference(keyType)) {
                declareReferenceType(schemaEl, declaredRefTypes, keyTypeName);
            }

            // Declare the reference type
            if (ReflectionInjectableProperty.isReference(valueType)) {
                declareReferenceType(schemaEl, declaredRefTypes, valueTypeName);
            }

        }

        for (InjectableProperty property : refProperties) {
            String typeName = property.getType().getName();
            declareReferenceType(schemaEl, declaredRefTypes, typeName);
        }

        Serializer serializer = new Serializer(output, "utf-8");
        serializer.setIndent(4);
        serializer.setMaxLength(160);
        serializer.write(new Document(schemaEl));
    }

    private void declareReferenceType(Element schemaEl, HashSet<String> declaredRefTypes, String typeName) {
        if (declaredRefTypes.contains(typeName)) {
            return;
        }

        Element simpleTypeEl = new Element("xs:simpleType", NS_SCHEMA);
        simpleTypeEl.addAttribute(new Attribute("name", typeName));
        schemaEl.appendChild(simpleTypeEl);

        appendTypeInfoAnnotation(simpleTypeEl, "reference");

        Element restrictionEl = new Element("xs:restriction", NS_SCHEMA);
        simpleTypeEl.appendChild(restrictionEl);

        restrictionEl.addAttribute(new Attribute("base", "xs:string"));

        declaredRefTypes.add(typeName);
    }

    private void appendTypeInfoAnnotation(Element complexTypeEl, String typeInfo) {
        Element annotEl = new Element("xs:annotation", NS_SCHEMA);
        complexTypeEl.appendChild(annotEl);

        Element appInfoEl = new Element("xs:appinfo", NS_SCHEMA);
        annotEl.appendChild(appInfoEl);

        Text appInfoContent = new Text("type_info");
        appInfoEl.appendChild(appInfoContent);

        Element docEl = new Element("xs:documentation", NS_SCHEMA);
        annotEl.appendChild(docEl);

        Text docElContent = new Text(typeInfo);
        docEl.appendChild(docElContent);
    }


}
TOP

Related Classes of com.avast.syringe.config.XmlSchemaGenerator

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.