1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.util;
21
22 import org.w3c.dom.Document;
23 import org.w3c.dom.Node;
24 import org.w3c.dom.NodeList;
25 import org.xml.sax.SAXException;
26
27 import javax.faces.application.ViewHandler;
28 import javax.faces.context.ExternalContext;
29 import javax.faces.context.FacesContext;
30 import javax.servlet.ServletContext;
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.net.URL;
37 import java.net.URLConnection;
38 import java.util.ArrayList;
39 import java.util.Enumeration;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43
44 public class WebXmlUtils {
45
46 private static final Map<Class<Throwable>, String> ERROR_PAGE_LOCATIONS = new HashMap<>();
47
48 public static String getErrorPageLocation(final Throwable exception) {
49 if (ERROR_PAGE_LOCATIONS.size() <= 0) {
50 init();
51 }
52
53 String location = null;
54
55 Class<?> exceptionClass = exception.getClass();
56 while (exceptionClass != null && location == null) {
57 location = ERROR_PAGE_LOCATIONS.get(exceptionClass);
58 exceptionClass = exceptionClass.getSuperclass();
59 }
60
61 if (location == null) {
62 location = ERROR_PAGE_LOCATIONS.get(null);
63 }
64
65 return location;
66 }
67
68 private static void init() {
69 final FacesContext facesContext = FacesContext.getCurrentInstance();
70 final ExternalContext externalContext = facesContext.getExternalContext();
71
72 try {
73 final List<Document> webXmls = getWebXmls(facesContext);
74
75 String locationDefault = null;
76 String location500 = null;
77
78 for (final Document document : webXmls) {
79 final NodeList errorPages = document.getElementsByTagName("error-page");
80
81 for (int i = 0; i < errorPages.getLength(); i++) {
82 final Node errorPage = errorPages.item(i);
83
84 String errorCode = null;
85 String exceptionType = null;
86 String location = null;
87
88 final NodeList children = errorPage.getChildNodes();
89 for (int j = 0; j < children.getLength(); j++) {
90 final Node child = children.item(j);
91 final String name = child.getNodeName();
92
93 if ("error-code".equals(name)) {
94 errorCode = child.getFirstChild().getNodeValue().trim();
95 } else if ("exception-type".equals(name)) {
96 exceptionType = child.getFirstChild().getNodeValue().trim();
97 } else if ("location".equals(name)) {
98 location = child.getFirstChild().getNodeValue().trim();
99 }
100 }
101
102 if (exceptionType != null) {
103 final Class<Throwable> key = (Class<Throwable>) Class.forName(exceptionType);
104 final String value = normalizePath(externalContext, location);
105 ERROR_PAGE_LOCATIONS.put(key, value);
106 } else if ("500".equals(errorCode)) {
107 location500 = location;
108 } else if (errorCode == null && exceptionType == null) {
109 locationDefault = location;
110 }
111 }
112 }
113
114 if (!ERROR_PAGE_LOCATIONS.containsKey(null)) {
115 final String value = normalizePath(externalContext, location500 != null ? location500 : locationDefault);
116 ERROR_PAGE_LOCATIONS.put(null, value);
117 }
118 } catch (IOException | ParserConfigurationException | ClassNotFoundException | SAXException e) {
119 throw new UnsupportedOperationException(e);
120 }
121 }
122
123 private static List<Document> getWebXmls(final FacesContext facesContext)
124 throws ParserConfigurationException, IOException, SAXException {
125 final List<Document> webXmls = new ArrayList<>();
126
127 final DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
128 for (final URL url : getWebXmlUrls(facesContext)) {
129 webXmls.add(getWebXml(documentBuilder, url));
130 }
131
132 return webXmls;
133 }
134
135 private static List<URL> getWebXmlUrls(final FacesContext facesContext) throws IOException {
136 final List<URL> urls = new ArrayList<>();
137 final ServletContext servletContext = (ServletContext) facesContext.getExternalContext().getContext();
138 urls.add(servletContext.getResource("/WEB-INF/web.xml"));
139
140 final Enumeration<URL> webFragments = Thread.currentThread().getContextClassLoader()
141 .getResources("META-INF/web-fragment.xml");
142 while (webFragments.hasMoreElements()) {
143 urls.add(webFragments.nextElement());
144 }
145
146 return urls;
147 }
148
149 private static Document getWebXml(final DocumentBuilder documentBuilder, final URL url)
150 throws ParserConfigurationException, IOException, SAXException {
151 if (url != null) {
152 final URLConnection connection = url.openConnection();
153 connection.setUseCaches(false);
154
155 try (final InputStream input = connection.getInputStream()) {
156 final Document document = documentBuilder.parse(input);
157 document.getDocumentElement().normalize();
158 return document;
159 }
160 } else {
161 return null;
162 }
163 }
164
165 private static String normalizePath(final ExternalContext externalContext, final String path) {
166 if (path == null) {
167 return null;
168 }
169
170 if (externalContext.getRequestPathInfo() != null) {
171 final String prefix = externalContext.getRequestServletPath();
172 if (path.startsWith(prefix)) {
173 return path.substring(prefix.length());
174 } else {
175 return path;
176 }
177 } else {
178 final String suffixInitParam = externalContext.getInitParameter(ViewHandler.FACELETS_SUFFIX_PARAM_NAME);
179 final String suffix = suffixInitParam != null ? suffixInitParam : ViewHandler.DEFAULT_FACELETS_SUFFIX;
180
181 if (path.endsWith(suffix)) {
182 return path;
183 } else {
184 return path.substring(0, path.lastIndexOf('.')) + suffix;
185 }
186 }
187 }
188 }