Package com.alibaba.citrus.springext.impl

Source Code of com.alibaba.citrus.springext.impl.SpringSchemasSourceInfoImpl

/*
* Copyright (c) 2002-2012 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.impl;

import static com.alibaba.citrus.util.Assert.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;
import static java.util.Collections.*;

import java.net.URI;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.citrus.springext.Namespaces;
import com.alibaba.citrus.springext.ResourceResolver;
import com.alibaba.citrus.springext.ResourceResolver.PropertyHandler;
import com.alibaba.citrus.springext.ResourceResolver.Resource;
import com.alibaba.citrus.springext.Schema;
import com.alibaba.citrus.springext.Schemas;
import com.alibaba.citrus.springext.SourceInfo;
import com.alibaba.citrus.springext.support.ClasspathResourceResolver;
import com.alibaba.citrus.springext.support.SourceInfoSupport;
import com.alibaba.citrus.springext.support.SpringSchemasSourceInfo;
import com.alibaba.citrus.util.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver;
import org.springframework.beans.factory.xml.PluggableSchemaResolver;
import org.springframework.util.ClassUtils;

/**
* 将Spring所支持的<code>META-INF/spring.schemas</code>中定义的schemas移到本地服务器。
*
* @author Michael Zhou
*/
public class SpringPluggableSchemas implements Schemas, Namespaces {
    private final static Logger  log                       = LoggerFactory.getLogger(SpringPluggableSchemas.class);
    private final static String  SCHEMA_MAPPINGS_LOCATION  = PluggableSchemaResolver.DEFAULT_SCHEMA_MAPPINGS_LOCATION;
    private final static String  HANDLER_MAPPINGS_LOCATION = DefaultNamespaceHandlerResolver.DEFAULT_HANDLER_MAPPINGS_LOCATION;
    private final static String  TOOLING_PARAMS_LOCATION   = "META-INF/spring.tooling";
    private final static Pattern SCHEMA_VERSION_PATTERN    = Pattern.compile("-((\\d+)(.\\d+)*)\\.xsd$");
    private final ResourceResolver                 resourceResolver;
    private final Map<String, Schema>              nameToSchemaMappings;
    private final Map<String, String>              uriToNameMappings;
    private final Set<String>                      namespaces;
    private final Set<String>                      namespacesUnmodified;
    private final Map<String, Map<String, String>> toolingParameters;
    private       boolean                          initialized;

    /** 通过默认的<code>ClassLoader</code>来查找spring schemas。 */
    public SpringPluggableSchemas() {
        this(null, null);
    }

    /**
     * 通过指定的<code>ClassLoader</code>来查找spring schemas。
     * 如果未指定<code>ClassLoader</code>,则使用默认的<code>ClassLoader</code>
     */
    public SpringPluggableSchemas(ClassLoader classLoader) {
        this(classLoader, null);
    }

    /**
     * 通过指定的<code>ResourceResolver</code>来查找spring schemas。
     * 适合来实现IDE plugins。
     */
    public SpringPluggableSchemas(ResourceResolver resourceResolver) {
        this(null, assertNotNull(resourceResolver, "no resourceResolver was specified"));
    }

    private SpringPluggableSchemas(ClassLoader classLoader, ResourceResolver resourceResolver) {
        if (resourceResolver == null) {
            if (classLoader == null) {
                classLoader = ClassUtils.getDefaultClassLoader();
            }

            this.resourceResolver = new ClasspathResourceResolver(classLoader);
        } else {
            // IDE plugin mode
            this.resourceResolver = resourceResolver;
        }

        this.nameToSchemaMappings = createTreeMap();
        this.uriToNameMappings = createTreeMap();
        this.namespaces = createTreeSet();
        this.namespacesUnmodified = unmodifiableSet(namespaces);
        this.toolingParameters = createHashMap();
    }

    @Override
    public Set<String> getAvailableNamespaces() {
        ensureInit();
        return namespacesUnmodified;
    }

    public Map<String, Schema> getNamedMappings() {
        ensureInit();
        return nameToSchemaMappings;
    }

    public Map<String, String> getUriToNameMappings() {
        ensureInit();
        return uriToNameMappings;
    }

    public Map<String, String> getToolingParameters(String namespaceURI) {
        ensureInit();
        return toolingParameters.get(trimToNull(namespaceURI));
    }

    private void ensureInit() {
        if (initialized) {
            return;
        }

        initialized = true;

        log.trace("Trying to load Spring schema mappings at {}", SCHEMA_MAPPINGS_LOCATION);

        final String desc = "SpringSchema[" + SCHEMA_MAPPINGS_LOCATION + "]";

        class SpringSchemasSourceInfoImpl extends SourceInfoSupport<SourceInfo<?>> implements SpringSchemasSourceInfo {
            SpringSchemasSourceInfoImpl() {
            }
        }

        // spring.tooling
        resourceResolver.loadAllProperties(TOOLING_PARAMS_LOCATION, new PropertyHandler() {
            public void handle(String key, String value, Resource source, int lineNumber) {
                String namespaceAndParamName = trimToNull(key);

                if (namespaceAndParamName != null) {
                    int index = namespaceAndParamName.indexOf("@");
                    String namespace = null;
                    String paramName = null;

                    if (index >= 0) {
                        namespace = trimToNull(namespaceAndParamName.substring(0, index));
                        paramName = trimToNull(namespaceAndParamName.substring(index + 1));
                    }

                    if (namespace != null && paramName != null) {
                        Map<String, String> params = toolingParameters.get(namespace);

                        if (params == null) {
                            params = createHashMap();
                            toolingParameters.put(namespace, params);
                        }

                        params.put(paramName, trimToNull(value));
                    }
                }
            }
        });

        // spring.schemas
        resourceResolver.loadAllProperties(SCHEMA_MAPPINGS_LOCATION, new PropertyHandler() {
            public void handle(String key, String value, Resource source, int lineNumber) {
                String uri = trimToNull(key);
                String classpathLocation = trimToNull(value);

                if (uri == null || classpathLocation == null) {
                    return; // invalid and ignored
                }

                String schemaName = getSchemaName(uri);
                Matcher matcher = SCHEMA_VERSION_PATTERN.matcher(schemaName);
                String version = null;

                if (matcher.find()) {
                    version = matcher.group(1);
                }

                SpringSchemasSourceInfoImpl pluginSourceInfo = new SpringSchemasSourceInfoImpl();
                pluginSourceInfo.setSource(source, lineNumber);

                Resource schemaSource = getResource(classpathLocation, uri);

                if (schemaSource != null) {
                    Schema schema = SchemaImpl.createSpringPluggableSchema(
                            schemaName, version, true, desc, schemaSource,
                            new SourceInfoSupport<SpringSchemasSourceInfo>(pluginSourceInfo).setSource(schemaSource), toolingParameters);

                    nameToSchemaMappings.put(schemaName, schema);
                    uriToNameMappings.put(uri, schemaName);

                    String namespace = schema.getTargetNamespace();

                    if (namespace != null) {
                        namespaces.add(namespace);
                    }
                }
            }
        });

        // 在spring.handlers中,有一些namespace是没有schema的(例如:http://www.springframework.org/schema/p),所以在spring.schemas中找不到。
        // 但我们需要在这里把它引进来,以方便IDE plugins读取。
        resourceResolver.loadAllProperties(HANDLER_MAPPINGS_LOCATION, new PropertyHandler() {
            public void handle(String key, String value, Resource source, int lineNumber) {
                String namespace = trimToNull(key);

                if (namespace != null) {
                    namespaces.add(namespace);
                }
            }
        });

        if (log.isDebugEnabled() && !uriToNameMappings.isEmpty()) {
            ToStringBuilder buf = new ToStringBuilder();

            buf.format("Loaded Spring schema mappings at %s, %d schemas found.", SCHEMA_MAPPINGS_LOCATION,
                       uriToNameMappings.size()).appendMap(uriToNameMappings);

            log.debug(buf.toString());
        }
    }

    private Resource getResource(String classpathLocation, String uri) {
        Resource resource = resourceResolver.getResource(classpathLocation);

        if (resource == null) {
            log.warn("Could not find schema {} for URI: {}", classpathLocation, uri);
        }

        return resource;
    }

    private String getSchemaName(String uri) {
        // 替换URI,将http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        // 替换成:www.springframework.org/schema/beans/spring-beans-2.5.xsd
        return URI.create(uri).normalize().getSchemeSpecificPart().replaceAll("^/+|/+$", "");
    }

    @Override
    public String toString() {
        ToStringBuilder buf = new ToStringBuilder();

        buf.format("SpringPluggableSchemas[loaded from %s]", SCHEMA_MAPPINGS_LOCATION);
        buf.appendMap(uriToNameMappings);

        return buf.toString();
    }
}
TOP

Related Classes of com.alibaba.citrus.springext.impl.SpringSchemasSourceInfoImpl

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.