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.lang.Nullable;
026import org.springframework.util.Assert;
027
028/**
029 * {@link EntityResolver} implementation that delegates to a {@link BeansDtdResolver}
030 * and a {@link PluggableSchemaResolver} for DTDs and XML schemas, respectively.
031 *
032 * @author Rob Harrop
033 * @author Juergen Hoeller
034 * @author Rick Evans
035 * @since 2.0
036 * @see BeansDtdResolver
037 * @see PluggableSchemaResolver
038 */
039public class DelegatingEntityResolver implements EntityResolver {
040
041        /** Suffix for DTD files. */
042        public static final String DTD_SUFFIX = ".dtd";
043
044        /** Suffix for schema definition files. */
045        public static final String XSD_SUFFIX = ".xsd";
046
047
048        private final EntityResolver dtdResolver;
049
050        private final EntityResolver schemaResolver;
051
052
053        /**
054         * Create a new DelegatingEntityResolver that delegates to
055         * a default {@link BeansDtdResolver} and a default {@link PluggableSchemaResolver}.
056         * <p>Configures the {@link PluggableSchemaResolver} with the supplied
057         * {@link ClassLoader}.
058         * @param classLoader the ClassLoader to use for loading
059         * (can be {@code null}) to use the default ClassLoader)
060         */
061        public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
062                this.dtdResolver = new BeansDtdResolver();
063                this.schemaResolver = new PluggableSchemaResolver(classLoader);
064        }
065
066        /**
067         * Create a new DelegatingEntityResolver that delegates to
068         * the given {@link EntityResolver EntityResolvers}.
069         * @param dtdResolver the EntityResolver to resolve DTDs with
070         * @param schemaResolver the EntityResolver to resolve XML schemas with
071         */
072        public DelegatingEntityResolver(EntityResolver dtdResolver, EntityResolver schemaResolver) {
073                Assert.notNull(dtdResolver, "'dtdResolver' is required");
074                Assert.notNull(schemaResolver, "'schemaResolver' is required");
075                this.dtdResolver = dtdResolver;
076                this.schemaResolver = schemaResolver;
077        }
078
079
080        @Override
081        @Nullable
082        public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId)
083                        throws SAXException, IOException {
084
085                if (systemId != null) {
086                        if (systemId.endsWith(DTD_SUFFIX)) {
087                                return this.dtdResolver.resolveEntity(publicId, systemId);
088                        }
089                        else if (systemId.endsWith(XSD_SUFFIX)) {
090                                return this.schemaResolver.resolveEntity(publicId, systemId);
091                        }
092                }
093
094                // Fall back to the parser's default behavior.
095                return null;
096        }
097
098
099        @Override
100        public String toString() {
101                return "EntityResolver delegating " + XSD_SUFFIX + " to " + this.schemaResolver +
102                                " and " + DTD_SUFFIX + " to " + this.dtdResolver;
103        }
104
105}