1 /* 2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.internal.xjc; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.Reader; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.List; 34 35 import javax.xml.transform.stream.StreamSource; 36 import javax.xml.validation.Schema; 37 import javax.xml.validation.SchemaFactory; 38 import javax.xml.validation.ValidatorHandler; 39 40 import com.sun.xml.internal.bind.v2.util.XmlFactory; 41 import javax.xml.XMLConstants; 42 43 import org.w3c.dom.ls.LSInput; 44 import org.w3c.dom.ls.LSResourceResolver; 45 import org.xml.sax.SAXException; 46 47 import static com.sun.xml.internal.bind.v2.util.XmlFactory.allowExternalAccess; 48 49 /** 50 * Wraps a JAXP {@link Schema} object and lazily instantiate it. 51 * 52 * This object is thread-safe. There should be only one instance of 53 * this for the whole VM. 54 * 55 * @author Kohsuke Kawaguchi 56 */ 57 public final class SchemaCache { 58 59 private final boolean createResolver; 60 private final String resourceName; 61 private final Class<?> clazz; 62 63 private Schema schema; 64 65 public SchemaCache(String resourceName, Class<?> classToResolveResources) { 66 this(resourceName, classToResolveResources, false); 67 } 68 69 public SchemaCache(String resourceName, Class<?> classToResolveResources, boolean createResolver) { 70 this.resourceName = resourceName; 71 this.createResolver = createResolver; 72 this.clazz = classToResolveResources; 73 } 74 75 public ValidatorHandler newValidator() { 76 if (schema==null) { 77 synchronized (this) { 78 if (schema == null) { 79 80 ResourceResolver resourceResolver = null; 81 try (InputStream is = clazz.getResourceAsStream(resourceName)) { 82 83 StreamSource source = new StreamSource(is); 84 source.setSystemId(resourceName); 85 // do not disable secure processing - these are well-known schemas 86 87 SchemaFactory sf = XmlFactory.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI, false); 88 SchemaFactory schemaFactory = allowExternalAccess(sf, "file", false); 89 90 if (createResolver) { 91 resourceResolver = new ResourceResolver(clazz); 92 schemaFactory.setResourceResolver(resourceResolver); 93 } 94 schema = schemaFactory.newSchema(source); 95 96 } catch (IOException | SAXException e) { 97 InternalError ie = new InternalError(e.getMessage()); 98 ie.initCause(e); 99 throw ie; 100 } finally { 101 if (resourceResolver != null) resourceResolver.closeStreams(); 102 } 103 } 104 } 105 } 106 return schema.newValidatorHandler(); 107 } 108 109 class ResourceResolver implements LSResourceResolver { 110 111 private List<InputStream> streamsToClose = Collections.synchronizedList(new ArrayList<InputStream>()); 112 private Class<?> clazz; 113 114 ResourceResolver(Class<?> clazz) { 115 this.clazz = clazz; 116 } 117 118 @Override 119 public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { 120 // XSOM passes the namespace URI to the publicID parameter. 121 // we do the same here . 122 InputStream is = clazz.getResourceAsStream(systemId); 123 streamsToClose.add(is); 124 return new Input(is, publicId, systemId); 125 } 126 127 void closeStreams() { 128 for (InputStream is : streamsToClose) { 129 if (is != null) { 130 try { 131 is.close(); 132 } catch (IOException e) { 133 // nothing to do ... 134 } 135 } 136 } 137 } 138 } 139 140 } 141 142 class Input implements LSInput { 143 144 private InputStream is; 145 private String publicId; 146 private String systemId; 147 148 public Input(InputStream is, String publicId, String systemId) { 149 this.is = is; 150 this.publicId = publicId; 151 this.systemId = systemId; 152 } 153 154 @Override 155 public Reader getCharacterStream() { 156 return null; 157 } 158 159 @Override 160 public void setCharacterStream(Reader characterStream) { 161 } 162 163 @Override 164 public InputStream getByteStream() { 165 return is; 166 } 167 168 @Override 169 public void setByteStream(InputStream byteStream) { 170 } 171 172 @Override 173 public String getStringData() { 174 return null; 175 } 176 177 @Override 178 public void setStringData(String stringData) { 179 } 180 181 @Override 182 public String getSystemId() { 183 return systemId; 184 } 185 186 @Override 187 public void setSystemId(String systemId) { 188 } 189 190 @Override 191 public String getPublicId() { 192 return publicId; 193 } 194 195 @Override 196 public void setPublicId(String publicId) { 197 } 198 199 @Override 200 public String getBaseURI() { 201 return null; 202 } 203 204 @Override 205 public void setBaseURI(String baseURI) { 206 } 207 208 @Override 209 public String getEncoding() { 210 return null; 211 } 212 213 @Override 214 public void setEncoding(String encoding) { 215 } 216 217 @Override 218 public boolean getCertifiedText() { 219 return false; 220 } 221 222 @Override 223 public void setCertifiedText(boolean certifiedText) { 224 } 225 }