001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.factory.xml;
018
019import java.io.IOException;
020
021import org.xml.sax.EntityResolver;
022import org.xml.sax.InputSource;
023import org.xml.sax.SAXException;
024
025import org.springframework.util.Assert;
026
027/**
028 * {@link EntityResolver} implementation that delegates to a {@link BeansDtdResolver}
029 * and a {@link PluggableSchemaResolver} for DTDs and XML schemas, respectively.
030 *
031 * @author Rob Harrop
032 * @author Juergen Hoeller
033 * @author Rick Evans
034 * @since 2.0
035 * @see BeansDtdResolver
036 * @see PluggableSchemaResolver
037 */
038public class DelegatingEntityResolver implements EntityResolver {
039
040        /** Suffix for DTD files */
041        public static final String DTD_SUFFIX = ".dtd";
042
043        /** Suffix for schema definition files */
044        public static final String XSD_SUFFIX = ".xsd";
045
046
047        private final EntityResolver dtdResolver;
048
049        private final EntityResolver schemaResolver;
050
051
052        /**
053         * Create a new DelegatingEntityResolver that delegates to
054         * a default {@link BeansDtdResolver} and a default {@link PluggableSchemaResolver}.
055         * <p>Configures the {@link PluggableSchemaResolver} with the supplied
056         * {@link ClassLoader}.
057         * @param classLoader the ClassLoader to use for loading
058         * (can be {@code null}) to use the default ClassLoader)
059         */
060        public DelegatingEntityResolver(ClassLoader classLoader) {
061                this.dtdResolver = new BeansDtdResolver();
062                this.schemaResolver = new PluggableSchemaResolver(classLoader);
063        }
064
065        /**
066         * Create a new DelegatingEntityResolver that delegates to
067         * the given {@link EntityResolver EntityResolvers}.
068         * @param dtdResolver the EntityResolver to resolve DTDs with
069         * @param schemaResolver the EntityResolver to resolve XML schemas with
070         */
071        public DelegatingEntityResolver(EntityResolver dtdResolver, EntityResolver schemaResolver) {
072                Assert.notNull(dtdResolver, "'dtdResolver' is required");
073                Assert.notNull(schemaResolver, "'schemaResolver' is required");
074                this.dtdResolver = dtdResolver;
075                this.schemaResolver = schemaResolver;
076        }
077
078
079        @Override
080        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
081                if (systemId != null) {
082                        if (systemId.endsWith(DTD_SUFFIX)) {
083                                return this.dtdResolver.resolveEntity(publicId, systemId);
084                        }
085                        else if (systemId.endsWith(XSD_SUFFIX)) {
086                                return this.schemaResolver.resolveEntity(publicId, systemId);
087                        }
088                }
089
090                // Fall back to the parser's default behavior.
091                return null;
092        }
093
094
095        @Override
096        public String toString() {
097                return "EntityResolver delegating " + XSD_SUFFIX + " to " + this.schemaResolver +
098                                " and " + DTD_SUFFIX + " to " + this.dtdResolver;
099        }
100
101}