001/** 002 * Copyright 2005-2017 The Kuali Foundation 003 * 004 * Licensed under the Educational Community 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 * http://www.opensource.org/licenses/ecl2.php 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 */ 016package org.kuali.rice.ken.util; 017 018import javax.xml.XMLConstants; 019 020import org.apache.log4j.Logger; 021 022/** 023 * Utility base class for Entity and LSResource Resolvers that should resolve 024 * arguments to resources in the ClassLoader. 025 * @author Kuali Rice Team (rice.collab@kuali.org) 026 */ 027public class ClassLoaderResourceResolver { 028 protected final Logger LOG = Logger.getLogger(getClass()); 029 030 /** 031 * This contains definitions for items in the core "xml" schema, i.e. base, id, lang, and space attributes. 032 */ 033 private static final String XML_NAMESPACE_SCHEMA = "http://www.w3.org/2001/xml.xsd"; 034 private static final String XSD_NAMESPACE_SCHEMA = XMLConstants.W3C_XML_SCHEMA_NS_URI; 035 036 /** 037 * Root path in class loader. Defaults to "schema". 038 */ 039 protected final String base; 040 /** 041 * Prefix of resources to honor. Defaults to "" (no specific prefix). 042 */ 043 protected final String prefix; 044 045 /** 046 * Constructs a ClassLoaderResourceResolver.java. 047 */ 048 public ClassLoaderResourceResolver() { 049 this.base = "schema"; 050 this.prefix = ""; 051 } 052 053 /** 054 * Constructs a ClassLoaderResourceResolver.java. 055 * @param base 056 * @param prefix 057 */ 058 public ClassLoaderResourceResolver(String base, String prefix) { 059 this.base = base; 060 this.prefix = prefix; 061 } 062 063 /** 064 * @param systemId 065 * @return String 066 */ 067 protected String resolveSystemId(String systemId) { 068 if (systemId.equals(XML_NAMESPACE_SCHEMA)) { 069 return base + "/xml.xsd"; 070 } else if (systemId.equals(XSD_NAMESPACE_SCHEMA)) { 071 return base + "/XMLSchema.xsd"; 072 } else if (systemId.startsWith("resource:" + prefix +"/")) { 073 /* It turns out that the stock XMLSchema.xsd refers to XMLSchema.dtd in a relative 074 fashion which results in the parser qualifying it to some local file:// path 075 which breaks our detection here. 076 So I have made a small mod to the stock XMLSchema.xsd so that it instead refers to 077 resource:XMLSchema.dtd which can be looked up locally. 078 The same is true for XMLSchema.dtd with regard to datatypes.dtd, so I have also 079 modified XMLSchema.dtd to refer to resource:datatypes.dtd. 080 An alternative would be to rely on publicId, however that would essentially hard code 081 the lookup to always be in the classpath and rule out being able to redirect the location 082 of the physical resource through the systemId, which is useful. 083 */ 084 085 String path = base + "/" + systemId.substring(("resource:" + prefix + "/").length()); 086 // ok, if the path does not itself end in .xsd or .dtd, it is bare/abstract 087 // so realize it by appending .xsd 088 // this allows us to support looking up files ending with ".dtd" through resource: without 089 // having extra logic to attempt to look up both suffixes for every single resource: 090 // (all of which except XMLSchema.dtd and datatypes.dtd at this point are .xsd files) 091 if (!(systemId.endsWith(".xsd") || systemId.endsWith(".dtd"))) { 092 path += ".xsd"; 093 } 094 return path; 095 } else { 096 return null; 097 } 098 } 099}