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.FileNotFoundException; 020import java.io.IOException; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024import org.xml.sax.EntityResolver; 025import org.xml.sax.InputSource; 026 027import org.springframework.core.io.ClassPathResource; 028import org.springframework.core.io.Resource; 029 030/** 031 * {@link EntityResolver} implementation for the Spring beans DTD, 032 * to load the DTD from the Spring class path (or JAR file). 033 * 034 * <p>Fetches "spring-beans-2.0.dtd" from the class path resource 035 * "/org/springframework/beans/factory/xml/spring-beans-2.0.dtd", 036 * no matter whether specified as some local URL that includes "spring-beans" 037 * in the DTD name or as "https://www.springframework.org/dtd/spring-beans-2.0.dtd". 038 * 039 * @author Juergen Hoeller 040 * @author Colin Sampaleanu 041 * @since 04.06.2003 042 * @see ResourceEntityResolver 043 */ 044public class BeansDtdResolver implements EntityResolver { 045 046 private static final String DTD_EXTENSION = ".dtd"; 047 048 private static final String DTD_FILENAME = "spring-beans-2.0"; 049 050 private static final String DTD_NAME = "spring-beans"; 051 052 private static final Log logger = LogFactory.getLog(BeansDtdResolver.class); 053 054 055 @Override 056 public InputSource resolveEntity(String publicId, String systemId) throws IOException { 057 if (logger.isTraceEnabled()) { 058 logger.trace("Trying to resolve XML entity with public ID [" + publicId + 059 "] and system ID [" + systemId + "]"); 060 } 061 062 if (systemId != null && systemId.endsWith(DTD_EXTENSION)) { 063 int lastPathSeparator = systemId.lastIndexOf('/'); 064 int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator); 065 if (dtdNameStart != -1) { 066 String dtdFile = DTD_FILENAME + DTD_EXTENSION; 067 if (logger.isTraceEnabled()) { 068 logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath"); 069 } 070 try { 071 Resource resource = new ClassPathResource(dtdFile, getClass()); 072 InputSource source = new InputSource(resource.getInputStream()); 073 source.setPublicId(publicId); 074 source.setSystemId(systemId); 075 if (logger.isDebugEnabled()) { 076 logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile); 077 } 078 return source; 079 } 080 catch (FileNotFoundException ex) { 081 if (logger.isDebugEnabled()) { 082 logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex); 083 } 084 } 085 } 086 } 087 088 // Fall back to the parser's default behavior. 089 return null; 090 } 091 092 093 @Override 094 public String toString() { 095 return "EntityResolver for spring-beans DTD"; 096 } 097 098}