Package com.alibaba.citrus.springext.impl

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

/*
* 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.FileUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;
import static java.util.Collections.*;

import java.net.URI;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import com.alibaba.citrus.springext.ConfigurationPoint;
import com.alibaba.citrus.springext.ConfigurationPointException;
import com.alibaba.citrus.springext.ConfigurationPoints;
import com.alibaba.citrus.springext.Contribution;
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.SourceInfo;
import com.alibaba.citrus.springext.support.SourceInfoSupport;
import com.alibaba.citrus.util.ToStringBuilder;
import com.alibaba.citrus.util.ToStringBuilder.MapBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 解析configuration point namespace。
*
* @author Michael Zhou
*/
public class ConfigurationPointsImpl implements ConfigurationPoints {
    private final static Logger log                 = LoggerFactory.getLogger(ConfigurationPoints.class);
    private final static String NAMESPACE_URI_KEY   = "namespaceUri";
    private final static String DEFAULT_ELEMENT_KEY = "defaultElement";
    private final static String PREFERRED_NS_PREFIX = "nsPrefix";
    private final ConfigurationPointSettings      settings;
    private final String                          configurationPointsLocation;
    private final Map<String, ConfigurationPoint> namespaceUriToConfigurationPoints; // namespaceUri => configurationPoint
    private final Set<String>                     namespaces;
    private final Map<String, ConfigurationPoint> nameToConfigurationPoints; // name => configurationPoint
    private final Collection<ConfigurationPoint>  configurationPoints;
    private       boolean                         initialized;

    /** 通过默认的<code>ClassLoader</code>来查找和创建<code>ConfigurationPoint</code>s。 */
    public ConfigurationPointsImpl() {
        this(null, null, null);
    }

    /**
     * 通过指定的<code>ClassLoader</code>来查找和创建<code>ConfigurationPoint</code>s。
     * 如果未指定<code>ClassLoader</code>,则使用默认的<code>ClassLoader</code>
     */
    public ConfigurationPointsImpl(ClassLoader classLoader) {
        this(classLoader, null);
    }

    /**
     * 通过指定的<code>ClassLoader</code>来查找和创建<code>ConfigurationPoint</code>s。
     * 如果未指定<code>ClassLoader</code>,则使用默认的<code>ClassLoader</code>
     */
    public ConfigurationPointsImpl(ClassLoader classLoader, String configurationPointsLocation) {
        this(classLoader, null, configurationPointsLocation);
    }

    /** 通过指定<code>ResourceResolver</code>来查找和创建<code>ConfigurationPoint</code>s。 */
    public ConfigurationPointsImpl(ResourceResolver resourceResolver) {
        this(resourceResolver, null);
    }

    /** 通过指定<code>ResourceResolver</code>来查找和创建<code>ConfigurationPoint</code>s。 */
    public ConfigurationPointsImpl(ResourceResolver resourceResolver, String configurationPointsLocation) {
        this(null, assertNotNull(resourceResolver, "no resourceResolver was specified"), configurationPointsLocation);
    }

    private ConfigurationPointsImpl(ClassLoader classLoader, ResourceResolver resourceResolver, String configurationPointsLocation) {
        this.configurationPointsLocation = defaultIfEmpty(configurationPointsLocation, DEFAULT_CONFIGURATION_POINTS_LOCATION);
        this.namespaceUriToConfigurationPoints = createTreeMap();
        this.namespaces = unmodifiableSet(namespaceUriToConfigurationPoints.keySet()); // sorted by ns
        this.nameToConfigurationPoints = createTreeMap();
        this.configurationPoints = unmodifiableCollection(nameToConfigurationPoints.values());// sorted by name

        if (resourceResolver == null) {
            this.settings = new ConfigurationPointSettings(classLoader, this.configurationPointsLocation);
        } else {
            // IDE plugin mode
            this.settings = new ConfigurationPointSettings(resourceResolver, this.configurationPointsLocation);
        }
    }

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

        initialized = true;
        loadConfigurationPoints();
    }

    private void loadConfigurationPoints() {
        log.trace("Trying to load configuration points at {}", configurationPointsLocation);

        settings.resourceResolver.loadAllProperties(configurationPointsLocation, new PropertyHandler() {
            public void handle(String key, String value, Resource source, int lineNumber) {
                String name = normalizeConfigurationPointName(key);

                if (name == null) {
                    return;
                }

                Map<String, String> params = parseNamespaceUriAndParams(value);
                String namespaceUri = assertNotNull(params.get(NAMESPACE_URI_KEY), "namespaceUri");

                if (!namespaceUri.endsWith(name)) {
                    throw new ConfigurationPointException("Naming Convention Violation: namespace URI [" + namespaceUri
                                                          + "] of configuration point should end with its name [" + name
                                                          + "].  This configuration point is located at " + configurationPointsLocation + ".");
                }

                String defaultElementName = params.get(DEFAULT_ELEMENT_KEY);
                String preferredNsPrefix = params.get(PREFERRED_NS_PREFIX);

                ConfigurationPoint cp = new ConfigurationPointImpl(
                        ConfigurationPointsImpl.this, settings, name, namespaceUri, defaultElementName, preferredNsPrefix,
                        new SourceInfoSupport<SourceInfo<?>>().setSource(source, lineNumber));

                namespaceUriToConfigurationPoints.put(namespaceUri, cp);
                nameToConfigurationPoints.put(name, cp);
            }
        });

        if (log.isDebugEnabled()) {
            ToStringBuilder buf = new ToStringBuilder();

            buf.format("Loaded configuration points at %s, %d configuration points found.",
                       configurationPointsLocation, nameToConfigurationPoints.size());

            MapBuilder mb = new MapBuilder().setSortKeys(true).setPrintCount(true);

            for (String name : nameToConfigurationPoints.keySet()) {
                mb.append(name, nameToConfigurationPoints.get(name).getNamespaceUri());
            }

            mb.appendTo(buf);

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

    public Set<String> getAvailableNamespaces() {
        ensureInit();
        return namespaces;
    }

    public Collection<ConfigurationPoint> getConfigurationPoints() {
        ensureInit();
        return configurationPoints;
    }

    public ConfigurationPoint getConfigurationPointByName(String name) {
        ensureInit();
        name = normalizeConfigurationPointName(name);

        if (name != null) {
            return ensureInitConfigurationPoint((ConfigurationPointImpl) nameToConfigurationPoints
                    .get(name));
        } else {
            return null;
        }
    }

    public ConfigurationPoint getConfigurationPointByNamespaceUri(String namespaceUri) {
        ensureInit();
        namespaceUri = normalizeNamespaceUri(namespaceUri);

        if (namespaceUri != null) {
            return ensureInitConfigurationPoint((ConfigurationPointImpl) namespaceUriToConfigurationPoints
                    .get(namespaceUri));
        } else {
            return null;
        }
    }

    private ConfigurationPoint ensureInitConfigurationPoint(ConfigurationPointImpl cp) {
        if (cp != null) {
            cp.init(); // if not inited yet
        }

        return cp;
    }

    private String normalizeConfigurationPointName(String name) {
        return trimToNull(normalizeRelativePath(name, true)); // 规格化,除去首尾slash
    }

    private String normalizeNamespaceUri(String uri) {
        uri = trimToNull(uri);

        if (uri != null) {
            uri = URI.create(uri).normalize().toString().replaceAll("/$", "");
        }

        return uri;
    }

    private Map<String, String> parseNamespaceUriAndParams(String uriAndParams) {
        uriAndParams = trimToNull(uriAndParams);

        if (uriAndParams == null) {
            return null;
        }

        Map<String, String> params = createHashMap(4);
        String[] parts = uriAndParams.split(",|;");

        for (String part : parts) {
            part = trimToNull(part);

            if (part != null) {
                int index = part.indexOf("=");

                if (index >= 0) {
                    String paramKey = trimToNull(part.substring(0, index));
                    String paramValue = trimToNull(part.substring(index + 1));

                    if (paramKey == null) {
                        throw new IllegalArgumentException("Illegal namespace URI: " + uriAndParams);
                    }

                    params.put(paramKey, paramValue);
                } else {
                    if (params.containsKey(NAMESPACE_URI_KEY)) {
                        throw new IllegalArgumentException("Illegal namespace URI: " + uriAndParams);
                    }

                    params.put(NAMESPACE_URI_KEY, normalizeNamespaceUri(part));
                }
            }
        }

        if (!params.containsKey(NAMESPACE_URI_KEY)) {
            throw new IllegalArgumentException("Illegal namespace URI: " + uriAndParams);
        }

        return params;
    }

    public Map<String, Schema> getNamedMappings() {
        Map<String, Schema> mappings = createTreeMap();

        for (ConfigurationPoint cp : getConfigurationPoints()) {
            mappings.putAll(cp.getSchemas().getNamedMappings()); // side effects: init cp if not inited yet

            for (Contribution contrib : cp.getContributions()) {
                mappings.putAll(contrib.getSchemas().getNamedMappings());
            }
        }

        return mappings;
    }

    @Override
    public String toString() {
        if (!initialized) {
            return "ConfigurationPoints[uninitialized]";
        } else {
            ToStringBuilder buf = new ToStringBuilder();

            buf.format("ConfigurationPoints[%d cps, loaded from %s]", configurationPoints.size(),
                       configurationPointsLocation);

            if (!configurationPoints.isEmpty()) {
                buf.appendCollection(configurationPoints);
            }

            return buf.toString();
        }
    }
}
TOP

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

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.