Package com.alibaba.citrus.springext.impl

Source Code of com.alibaba.citrus.springext.impl.ContributionImpl$ContributionSchemaSource

/*
* 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.springext.Schema.*;
import static com.alibaba.citrus.springext.support.SchemaUtil.*;
import static com.alibaba.citrus.util.Assert.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static java.util.Collections.*;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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.ContributionType;
import com.alibaba.citrus.springext.Schema;
import com.alibaba.citrus.springext.VersionableSchemas;
import com.alibaba.citrus.util.ToStringBuilder;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.InputStreamSource;

/**
* 实现<code>Contribution</code>接口。
*
* @author Michael Zhou
*/
public class ContributionImpl implements Contribution {
    private final static Logger log = LoggerFactory.getLogger(Contribution.class);
    private final ConfigurationPoint         configurationPoint;
    private final ConfigurationPointSettings settings;
    private final ContributionKey            key;
    private final String                     implementationClassName;
    private       VersionableSchemas         schemas;

    ContributionImpl(ConfigurationPointImpl cp, ConfigurationPointSettings settings, ContributionType type,
                     String name, String contributionClassName) {
        this.configurationPoint = assertNotNull(cp, "configurationPoint");
        this.settings = settings;
        this.key = new ContributionKey(name, type);
        this.implementationClassName = contributionClassName; // 可能为空,但推迟到创建时再报错
    }

    public ConfigurationPoint getConfigurationPoint() {
        return configurationPoint;
    }

    public ContributionType getType() {
        return key.getType();
    }

    public String getName() {
        return key.getName();
    }

    ContributionKey getKey() {
        return key;
    }

    public String getImplementationClassName() {
        return implementationClassName;
    }

    public VersionableSchemas getSchemas() {
        if (schemas == null) {
            String mainName = configurationPoint.getName() + "/" + getName(); // configurationPointName/contributionName
            Schema mainSchema = loadMainSchema(mainName);
            Schema[] versionedSchemas = loadVersionedSchemas(mainName);

            schemas = new VersionableSchemasImpl(mainSchema, versionedSchemas);
        }

        return schemas;
    }

    private Schema loadMainSchema(String mainName) {
        String schemaName = mainName + "." + XML_SCHEMA_EXTENSION;
        URL resource;

        try {
            resource = settings.getResource(schemaName, log);
            assertNotNull(resource, schemaName);
            log.debug("Found schema file for contribution {}: {}", mainName, resource);
        } catch (IOException e) {
            log.warn("Failed to load schema: {}:  {}", schemaName, e);
            resource = null;
        }

        if (resource == null) {
            return null; // no schema found
        } else {
            return new SchemaImpl(schemaName, null, getDescription(), new ContributionSchemaSource(resource,
                                                                                                   getConfigurationPoint().getConfigurationPoints(), getConfigurationPoint()));
        }
    }

    private Schema[] loadVersionedSchemas(String mainName) {
        String schemaNamePattern = mainName + "-*." + XML_SCHEMA_EXTENSION;
        Pattern pattern = Pattern.compile("^.*(" + mainName + "-(.+)\\." + XML_SCHEMA_EXTENSION + ")$");
        List<URL> resources;

        try {
            resources = settings.getResources(schemaNamePattern, log);
        } catch (IOException e) {
            log.warn("Failed to load schemas: {}:  {}", schemaNamePattern, e);
            resources = emptyList();
        }

        assertNotNull(resources, schemaNamePattern);

        List<Schema> schemas = createLinkedList();

        for (Iterator<URL> i = resources.iterator(); i.hasNext(); ) {
            URL url = i.next();
            String path = url.getPath();
            Matcher matcher = pattern.matcher(path);

            if (matcher.matches()) {
                String schemaName = matcher.group(1);
                String schemaVersion = matcher.group(2);

                if (checkVersion(schemaVersion)) {
                    schemas.add(new SchemaImpl(schemaName, schemaVersion, getDescription(),
                                               new ContributionSchemaSource(url, getConfigurationPoint().getConfigurationPoints(),
                                                                            getConfigurationPoint())));
                } else {
                    i.remove();
                }
            } else {
                throw new ConfigurationPointException("Invalid schema name: " + url);
            }
        }

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

            buf.format("Found %d versioned schema files for contribution %s:", resources.size(), mainName);
            buf.append(resources);

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

        return schemas.toArray(new Schema[schemas.size()]);
    }

    /**
     * 检查schemaName-version组合是否为另一个contribution的名字,如果是,则抛弃该组合。
     * <p>
     * 例如:有两个contribution:<code>break</code><code>break-if</code>。那么后者的schema:
     * <code>break-if.xsd</code>就会被误判成前者的某个version版本。该方法用来检查并排除这种情况。
     * </p>
     */
    private boolean checkVersion(String schemaVersion) {
        String name = getName();

        for (String v : schemaVersion.split("-")) {
            name += "-" + v;

            for (ContributionType type : ContributionType.values()) {
                if (getConfigurationPoint().getContribution(name, type) != null) {
                    return false;
                }
            }
        }

        return true;
    }

    /** 用于生成或取得contribution schema的内容。 */
    private static class ContributionSchemaSource implements InputStreamSource {
        private final URL                 url;
        private final ConfigurationPoints cps;
        private final ConfigurationPoint  thisCp;

        public ContributionSchemaSource(URL url, ConfigurationPoints cps, ConfigurationPoint thisCp) {
            this.url = assertNotNull(url, "no schema URL");
            this.cps = assertNotNull(cps, "no ConfigurationPoints");
            this.thisCp = assertNotNull(thisCp, "this ConfigurationPoint");
        }

        /**
         * 读取contribution schema,必要时处理和改进其内容。
         * <p>
         * 但假如schema读取失败,则只返回原始的schema流。
         * </p>
         */
        public InputStream getInputStream() throws IOException {
            try {
                return new ByteArrayInputStream(getContributionSchemaContent(getOriginalInputStream(),
                                                                             url.toExternalForm(), true, cps, thisCp));
            } catch (DocumentException e) {
                return getOriginalInputStream();
            }
        }

        private InputStream getOriginalInputStream() throws IOException {
            URLConnection connection = this.url.openConnection();
            connection.setUseCaches(false);
            return connection.getInputStream();
        }

        @Override
        public String toString() {
            return url.toExternalForm();
        }
    }

    public String getDescription() {
        return String.format("Contribution[%s:%s]", getConfigurationPoint().getName(), getName());
    }

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

        buf.format("Contribution[toConfigurationPoint=%s, name=%s, type=%s, class=%s]",
                   getConfigurationPoint().getName(), getName(), getType(), implementationClassName).start();

        buf.append(getSchemas());

        return buf.end().toString();
    }
}
TOP

Related Classes of com.alibaba.citrus.springext.impl.ContributionImpl$ContributionSchemaSource

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.