Package com.alibaba.citrus.springext.export

Source Code of com.alibaba.citrus.springext.export.SchemaExporter$AddPrefixFilter

/*
* Copyright 2010 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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.alibaba.citrus.springext.export;

import static com.alibaba.citrus.util.Assert.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;
import static com.alibaba.citrus.util.io.StreamUtil.*;
import static javax.xml.XMLConstants.*;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ResourceLoader;

import com.alibaba.citrus.springext.DocumentFilter;
import com.alibaba.citrus.springext.Schema;
import com.alibaba.citrus.springext.Schemas;
import com.alibaba.citrus.springext.impl.ConfigurationPointsImpl;
import com.alibaba.citrus.springext.support.SchemaSet;
import com.alibaba.citrus.springext.support.resolver.SpringPluggableSchemas;

/**
* װ�غͷ���schemas��������������������
*
* @author Michael Zhou
*/
public class SchemaExporter {
    protected final Logger log = LoggerFactory.getLogger(getClass());
    private final Entries entries;
    private final SchemaSet schemas;
    private final Map<String, Set<Schema>> nsToSchemas;

    public SchemaExporter() {
        this((ResourceLoader) null);
    }

    public SchemaExporter(ResourceLoader resourceLoader) {
        this(new ConfigurationPointsImpl(resourceLoader == null ? null : resourceLoader.getClassLoader()),
                new SpringPluggableSchemas(resourceLoader));
    }

    public SchemaExporter(Schemas... schemasList) {
        this.entries = new Entries();
        this.schemas = new SchemaSet(schemasList);
        this.nsToSchemas = createHashMap();

        // ��������ͬnamespace��schema����һ�𣬲������Ƶ����򣬼�����beans.xsd��beans-2.5.xsd��beans-2.0.xsd ˳��
        for (Schema schema : schemas.getNamedMappings().values()) {
            this.entries.put(schema.getName(), new Entry(schema.getName(), schema));

            String namespace = schema.getTargetNamespace();

            if (namespace != null) {
                Set<Schema> nsSchemas = nsToSchemas.get(namespace);

                if (nsSchemas == null) {
                    nsSchemas = createTreeSet(new Comparator<Schema>() {
                        public int compare(Schema o1, Schema o2) {
                            return o2.getName().compareTo(o1.getName());
                        }
                    });

                    nsToSchemas.put(namespace, nsSchemas);
                }

                nsSchemas.add(schema);
            }
        }
    }

    private Entries getEntries() {
        return entries;
    }

    public Entry getRootEntry() {
        return getEntries().getRoot();
    }

    public Entry getEntry(String path) {
        return getEntries().get(path);
    }

    public void writeTo(Writer out, Entry entry, String charset) throws IOException {
        writeTo(out, entry, charset, (String) null);
    }

    public void writeTo(Writer out, Entry entry, String charset, String uriPrefix) throws IOException {
        writeTo(out, entry, charset, uriPrefix == null ? null : new AddPrefixFilter(uriPrefix));
    }

    private void writeTo(Writer out, Entry entry, String charset, DocumentFilter filter) throws IOException {
        writeText(entry.getSchema().getText(charset, filter), out, true);
    }

    /**
     * ����һ��schema�ļ���㡣
     */
    public static final class Entry {
        private final String path;
        private final String name;
        private final boolean directory;
        private final boolean root;
        private final Schema schema;
        private final Map<String, Entry> subEntries;

        /**
         * ���������root entry��
         */
        private Entry() {
            this.path = "";
            this.name = "";
            this.directory = true;
            this.root = true;
            this.schema = null;
            this.subEntries = createTreeMap();
        }

        public Entry(String path) {
            this(path, null);
        }

        public Entry(String path, Schema schema) {
            this.path = assertNotNull(trimToNull(path), "path");
            this.directory = path.endsWith("/");

            int fromIndex = this.directory ? path.length() - 2 : path.length();

            this.name = path.substring(path.lastIndexOf("/", fromIndex) + 1);
            this.root = false;
            this.schema = schema;
            this.subEntries = createTreeMap();

            if (this.directory) {
                assertNull(schema, "schema");
            } else {
                assertNotNull(schema, "schema");
            }
        }

        public String getPath() {
            return path;
        }

        public String getId() {
            if (isRoot()) {
                return "ROOT";
            } else {
                return path.replaceFirst("\\.[^-\\./]*$|/+$", "").replace('/', '-').replace('.', '-');
            }
        }

        public String getName() {
            return name;
        }

        public boolean isDirectory() {
            return directory;
        }

        public boolean isRoot() {
            return root;
        }

        public Collection<Entry> getSubEntries() {
            return subEntries.values();
        }

        public Schema getSchema() {
            return schema;
        }

        public boolean containsSchemaWithTargetNamespace() {
            boolean hasNs = false;

            if (isDirectory()) {
                for (Entry subEntry : getSubEntries()) {
                    if (subEntry.containsSchemaWithTargetNamespace()) {
                        hasNs = true;
                        break;
                    }
                }
            } else if (getSchema() != null) {
                hasNs = getSchema().getTargetNamespace() != null;
            }

            return hasNs;
        }

        private final static String PREFIX_ITEM = "+---";
        private final static String PREFIX_LAST_ITEM = "\\---";
        private final static String INDENT_BEFORE_LAST_ITEM = "|   ";
        private final static String INDENT_AFTER_LAST_ITEM = "    ";

        public String tree() {
            StringWriter sw = new StringWriter();

            try {
                tree(sw);
            } catch (IOException e) {
                unexpectedException(e);
            }

            return sw.toString();
        }

        public void tree(Appendable buf) throws IOException {
            tree(buf, "");
        }

        public void tree(Appendable buf, String prefix) throws IOException {
            tree(buf, prefix, prefix);
        }

        private void tree(Appendable buf, String prefix, String indent) throws IOException {
            buf.append(prefix).append(getName()).append("\n");

            for (Iterator<Entry> i = subEntries.values().iterator(); i.hasNext();) {
                Entry subEntry = i.next();
                String subPrefix;
                String subIndent;

                if (i.hasNext()) {
                    subPrefix = indent + PREFIX_ITEM;
                    subIndent = indent + INDENT_BEFORE_LAST_ITEM;
                } else {
                    subPrefix = indent + PREFIX_LAST_ITEM;
                    subIndent = indent + INDENT_AFTER_LAST_ITEM;
                }

                subEntry.tree(buf, subPrefix, subIndent);
            }
        }

        /**
         * Files sort by name without extension, then directories.
         */
        private String getSortKey() {
            String name = getName();

            if (!isDirectory()) {
                int slashIndex = name.lastIndexOf("/");
                int dotIndex = name.lastIndexOf(".");

                if (slashIndex < dotIndex && dotIndex >= 0) {
                    return "0-" + name.substring(0, dotIndex);
                }

                return "0-" + name;
            }

            return "1-" + name;
        }

        @Override
        public String toString() {
            return root ? "/" : path;
        }
    }

    private final class Entries extends HashMap<String, Entry> {
        private static final long serialVersionUID = -4000525580274040823L;

        public Entries() {
            super.put("", new Entry());
        }

        public Entry getRoot() {
            return get("");
        }

        @Override
        public Entry put(String path, Entry entry) {
            assertTrue(path.equals(entry.getPath()));

            if (path.endsWith("/")) {
                path = path.substring(0, path.length() - 1);
            }

            String parentPath = path.substring(0, path.lastIndexOf("/") + 1);
            Entry parentEntry = get(parentPath);

            if (parentEntry == null) {
                parentEntry = new Entry(parentPath);
                this.put(parentPath, parentEntry); // recursively
            }

            parentEntry.subEntries.put(entry.getSortKey(), entry);

            Entry old = super.put(entry.getPath(), entry);

            log.trace("Added entry: {}", entry.getPath());

            return old;
        }
    }

    /**
     * �����п�ʶ���URI�ϣ�����ָ��ǰ׺��
     */
    private class AddPrefixFilter implements DocumentFilter {
        private final String prefix;

        public AddPrefixFilter(String prefix) {
            if (prefix != null) {
                if (!prefix.endsWith("/")) {
                    prefix += "/";
                }
            }

            this.prefix = prefix;
        }

        public Document filter(Document doc, String systemId) {
            if (prefix != null) {
                Element root = doc.getRootElement();

                // <xsd:schema>
                if (W3C_XML_SCHEMA_NS_URI.equals(root.getNamespaceURI()) && "schema".equals(root.getName())) {
                    Namespace xsd = DocumentHelper.createNamespace("xsd", W3C_XML_SCHEMA_NS_URI);
                    QName includeName = DocumentHelper.createQName("include", xsd);
                    QName importName = DocumentHelper.createQName("import", xsd);

                    // for each <xsd:include>
                    for (Iterator<?> i = root.elementIterator(includeName); i.hasNext();) {
                        Element includeElement = (Element) i.next();
                        String schemaLocation = trimToNull(includeElement.attributeValue("schemaLocation"));

                        if (schemaLocation != null) {
                            schemaLocation = getNewSchemaLocation(schemaLocation, null, systemId);

                            if (schemaLocation != null) {
                                includeElement.addAttribute("schemaLocation", schemaLocation);
                            }
                        }
                    }

                    // for each <xsd:import>
                    for (Iterator<?> i = root.elementIterator(importName); i.hasNext();) {
                        Element importElement = (Element) i.next();
                        String schemaLocation = importElement.attributeValue("schemaLocation");
                        String namespace = trimToNull(importElement.attributeValue("namespace"));

                        if (schemaLocation != null || namespace != null) {
                            schemaLocation = getNewSchemaLocation(schemaLocation, namespace, systemId);

                            if (schemaLocation != null) {
                                importElement.addAttribute("schemaLocation", schemaLocation);
                            }
                        }
                    }
                }
            }

            return doc;
        }

        private String getNewSchemaLocation(String schemaLocation, String namespace, String systemId) {
            // ����ָ����schemaLocation�ж�
            if (schemaLocation != null) {
                Schema schema = schemas.findSchema(schemaLocation);

                if (schema != null) {
                    return prefix + schema.getName();
                } else {
                    return schemaLocation; // ����ԭ����location���������Ǵ���ģ�
                }
            }

            // �ٸ���namespace�ж�
            if (namespace != null) {
                Set<Schema> nsSchemas = nsToSchemas.get(namespace);

                if (nsSchemas != null && !nsSchemas.isEmpty()) {
                    // ���ȣ���������ͬns��schema�в��Ұ汾��ͬ��schema��
                    String versionedExtension = getVersionedExtension(systemId);

                    if (versionedExtension != null) {
                        for (Schema schema : nsSchemas) {
                            if (schema.getName().endsWith(versionedExtension)) {
                                return prefix + schema.getName();
                            }
                        }
                    }

                    // ��Σ�ѡ���һ��Ĭ�ϵ�schema����˳���ǣ�beans.xsd��beans-2.5.xsd��beans-2.0.xsd
                    return prefix + nsSchemas.iterator().next().getName();
                }
            }

            return null;
        }

        /**
         * ����spring-aop-2.5.xsdȡ��-2.5.xsd��
         */
        private String getVersionedExtension(String systemId) {
            if (systemId != null) {
                int dashIndex = systemId.lastIndexOf("-");
                int slashIndex = systemId.lastIndexOf("/");

                if (dashIndex > slashIndex) {
                    return systemId.substring(dashIndex);
                }
            }

            return null;
        }
    }
}
TOP

Related Classes of com.alibaba.citrus.springext.export.SchemaExporter$AddPrefixFilter

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.