1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.tomcat.util.descriptor;
18
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.net.MalformedURLException;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.net.URL;
25 import java.util.Map;
26
27 import org.apache.tomcat.util.res.StringManager;
28 import org.xml.sax.InputSource;
29 import org.xml.sax.SAXException;
30 import org.xml.sax.ext.EntityResolver2;
31
32 /**
33 * A resolver for locally cached XML resources.
34 */
35 public class LocalResolver implements EntityResolver2 {
36
37 private static final StringManager sm =
38 StringManager.getManager(Constants.PACKAGE_NAME);
39
40 private static final String[] JAVA_EE_NAMESPACES = {
41 XmlIdentifiers.JAVAEE_1_4_NS,
42 XmlIdentifiers.JAVAEE_5_NS,
43 XmlIdentifiers.JAVAEE_7_NS};
44
45
46 private final Map<String,String> publicIds;
47 private final Map<String,String> systemIds;
48 private final boolean blockExternal;
49
50 /**
51 * Constructor providing mappings of public and system identifiers to local
52 * resources. Each map contains a mapping from a well-known identifier to a
53 * URL for a local resource path.
54 *
55 * @param publicIds mapping of well-known public identifiers to local
56 * resources
57 * @param systemIds mapping of well-known system identifiers to local
58 * resources
59 * @param blockExternal are external resources blocked that are not
60 * well-known
61 */
62 public LocalResolver(Map<String,String> publicIds,
63 Map<String,String> systemIds, boolean blockExternal) {
64 this.publicIds = publicIds;
65 this.systemIds = systemIds;
66 this.blockExternal = blockExternal;
67 }
68
69
70 @Override
71 public InputSource resolveEntity(String publicId, String systemId)
72 throws SAXException, IOException {
73 return resolveEntity(null, publicId, null, systemId);
74 }
75
76
77 @Override
78 public InputSource resolveEntity(String name, String publicId,
79 String base, String systemId) throws SAXException, IOException {
80
81 // First try resolving using the publicId
82 String resolved = publicIds.get(publicId);
83 if (resolved != null) {
84 InputSource is = new InputSource(resolved);
85 is.setPublicId(publicId);
86 return is;
87 }
88
89 // If there is no systemId, can't try anything else
90 if (systemId == null) {
91 throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity",
92 name, publicId, null, base));
93 }
94
95 // Try resolving with the supplied systemId
96 resolved = systemIds.get(systemId);
97 if (resolved != null) {
98 InputSource is = new InputSource(resolved);
99 is.setPublicId(publicId);
100 return is;
101 }
102
103 // Work-around for XML documents that use just the file name for the
104 // location to refer to a JavaEE schema
105 for (String javaEENamespace : JAVA_EE_NAMESPACES) {
106 String javaEESystemId = javaEENamespace + '/' + systemId;
107 resolved = systemIds.get(javaEESystemId);
108 if (resolved != null) {
109 InputSource is = new InputSource(resolved);
110 is.setPublicId(publicId);
111 return is;
112 }
113 }
114
115 // Resolve the supplied systemId against the base
116 URI systemUri;
117 try {
118 if (base == null) {
119 systemUri = new URI(systemId);
120 } else {
121 // Can't use URI.resolve() because "jar:..." URLs are not valid
122 // hierarchical URIs so resolve() does not work. new URL()
123 // delegates to the jar: stream handler and it manages to figure
124 // it out.
125 URI baseUri = new URI(base);
126 systemUri = new URL(baseUri.toURL(), systemId).toURI();
127 }
128 systemUri = systemUri.normalize();
129 } catch (URISyntaxException e) {
130 // May be caused by a | being used instead of a : in an absolute
131 // file URI on Windows.
132 if (blockExternal) {
133 // Absolute paths aren't allowed so block it
134 throw new MalformedURLException(e.getMessage());
135 } else {
136 // See if the URLHandler can resolve it
137 return new InputSource(systemId);
138 }
139 }
140 if (systemUri.isAbsolute()) {
141 // Try the resolved systemId
142 resolved = systemIds.get(systemUri.toString());
143 if (resolved != null) {
144 InputSource is = new InputSource(resolved);
145 is.setPublicId(publicId);
146 return is;
147 }
148 if (!blockExternal) {
149 InputSource is = new InputSource(systemUri.toString());
150 is.setPublicId(publicId);
151 return is;
152 }
153 }
154
155 throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity",
156 name, publicId, systemId, base));
157 }
158
159
160 @Override
161 public InputSource getExternalSubset(String name, String baseURI)
162 throws SAXException, IOException {
163 return null;
164 }
165 }
166