001package runwar.undertow; 002 003import java.io.File; 004import java.util.HashMap; 005 006import javax.xml.parsers.DocumentBuilder; 007import javax.xml.parsers.DocumentBuilderFactory; 008 009import org.w3c.dom.Document; 010 011import io.undertow.servlet.api.DeploymentInfo; 012import io.undertow.servlet.api.FilterInfo; 013import io.undertow.servlet.api.ListenerInfo; 014import io.undertow.servlet.api.MimeMapping; 015import io.undertow.servlet.api.ServletInfo; 016 017import java.util.EventListener; 018import java.util.Map; 019 020import runwar.logging.Logger; 021 022import javax.servlet.Filter; 023import javax.servlet.Servlet; 024import javax.servlet.DispatcherType; 025 026import org.w3c.dom.Element; 027import org.w3c.dom.Node; 028import org.w3c.dom.NodeList; 029 030public class WebXMLParser { 031 032 private static Logger log = Logger.getLogger("RunwarLogger"); 033 034 /** 035 * Parses the web.xml and configures the context. 036 * 037 * @param webxml 038 * @param info 039 */ 040 @SuppressWarnings("unchecked") 041 public static void parseWebXml(File webxml, DeploymentInfo info) { 042 if (!webxml.exists() || !webxml.canRead()) { 043 log.error("Error reading web.xml! exists:"+webxml.exists()+"readable:"+webxml.canRead()); 044 } 045 try { 046 String webinfPath = webxml.getParentFile().getCanonicalPath(); 047 if (File.separatorChar=='\\') { 048 webinfPath = webinfPath.replace("\\", "\\\\"); 049 } 050 trace("parsing %s",webxml.getCanonicalPath()); 051 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 052 DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 053 Document doc = docBuilder.parse(webxml); 054 // normalize text representation 055 doc.getDocumentElement().normalize(); 056 057 trace("Root element of the doc is %s", doc.getDocumentElement().getNodeName()); 058 // to hold our servlets 059 Map<String, ServletInfo> servletMap = new HashMap<String, ServletInfo>(); 060 // to hold our filters 061 Map<String, FilterInfo> filterMap = new HashMap<String, FilterInfo>(); 062 // do context-param - available to the entire scope of the web 063 // application 064 NodeList listOfElements = doc.getElementsByTagName("context-param"); 065 int totalElements = listOfElements.getLength(); 066 067 trace("Total no of context-params: %s", totalElements); 068 for (int s = 0; s < totalElements; s++) { 069 Node fstNode = listOfElements.item(s); 070 if (fstNode.getNodeType() == Node.ELEMENT_NODE) { 071 Element fstElmnt = (Element) fstNode; 072 NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("param-name"); 073 Element fstNmElmnt = (Element) fstNmElmntLst.item(0); 074 NodeList fstNm = fstNmElmnt.getChildNodes(); 075 String pName = (fstNm.item(0)).getNodeValue().trim(); 076 trace("context param name: %s", pName); 077 NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("param-value"); 078 Element lstNmElmnt = (Element) lstNmElmntLst.item(0); 079 NodeList lstNm = lstNmElmnt.getChildNodes(); 080 String pValue = (lstNm.item(0)).getNodeValue().trim(); 081 // replace any /WEB-INF paths with the real path 082 // this was for adobe CF, which is just nuts... undoing for now 083 //pValue = pValue.replaceAll(".?/WEB-INF", webinfPath); 084 trace("context param value: %s", pValue); 085 info.addServletContextAttribute(pName, pValue); 086 info.addInitParameter(pName, pValue); 087 } 088 } 089 // do listener 090 listOfElements = doc.getElementsByTagName("listener"); 091 totalElements = listOfElements.getLength(); 092 trace("Total no of listeners: %s", totalElements); 093 for (int s = 0; s < totalElements; s++) { 094 Node fstNode = listOfElements.item(s); 095 if (fstNode.getNodeType() == Node.ELEMENT_NODE) { 096 Element fstElmnt = (Element) fstNode; 097 NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("listener-class"); 098 Element fstNmElmnt = (Element) fstNmElmntLst.item(0); 099 NodeList fstNm = fstNmElmnt.getChildNodes(); 100 String pName = (fstNm.item(0)).getNodeValue().trim(); 101 trace("Param name: %s", pName); 102 ListenerInfo listener = new ListenerInfo((Class<? extends EventListener>) info.getClassLoader() 103 .loadClass(pName)); 104 info.addListener(listener); 105 } 106 } 107 // do filter 108 listOfElements = doc.getElementsByTagName("filter"); 109 totalElements = listOfElements.getLength(); 110 trace("Total no of filters: %s", totalElements); 111 for (int s = 0; s < totalElements; s++) { 112 Node fstNode = listOfElements.item(s); 113 if (fstNode.getNodeType() == Node.ELEMENT_NODE) { 114 Element fstElmnt = (Element) fstNode; 115 NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("filter-name"); 116 Element fstNmElmnt = (Element) fstNmElmntLst.item(0); 117 NodeList fstNm = fstNmElmnt.getChildNodes(); 118 String pName = (fstNm.item(0)).getNodeValue().trim(); 119 trace("Filter name: %s", pName); 120 NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("filter-class"); 121 Element lstNmElmnt = (Element) lstNmElmntLst.item(0); 122 NodeList lstNm = lstNmElmnt.getChildNodes(); 123 String pValue = (lstNm.item(0)).getNodeValue().trim(); 124 trace("Filter class: %s", pValue); 125 // create the filter 126 FilterInfo filter = new FilterInfo(pName, (Class<? extends Filter>) info.getClassLoader() 127 .loadClass(pValue)); 128 // do init-param - available in the context of a servlet 129 // or filter in the web application 130 NodeList listOfInitParams = fstElmnt.getElementsByTagName("init-param"); 131 int totalInitParams = listOfInitParams.getLength(); 132 trace("Total no of init-params: %s", totalInitParams); 133 for (int i = 0; i < totalInitParams; i++) { 134 Node inNode = listOfInitParams.item(i); 135 if (inNode.getNodeType() == Node.ELEMENT_NODE) { 136 Element inElmnt = (Element) inNode; 137 NodeList inNmElmntLst = inElmnt.getElementsByTagName("param-name"); 138 Element inNmElmnt = (Element) inNmElmntLst.item(0); 139 NodeList inNm = inNmElmnt.getChildNodes(); 140 String inName = (inNm.item(0)).getNodeValue().trim(); 141 trace("Param name: %s", inName); 142 NodeList inValElmntLst = inElmnt.getElementsByTagName("param-value"); 143 Element inValElmnt = (Element) inValElmntLst.item(0); 144 NodeList inVal = inValElmnt.getChildNodes(); 145 String inValue = (inVal.item(0)).getNodeValue().trim(); 146 trace("Param value: %s", inValue); 147 // add the param 148 filter.addInitParam(inName, inValue); 149 } 150 } 151 // do async-supported 152 NodeList ldElmntLst = fstElmnt.getElementsByTagName("async-supported"); 153 if (ldElmntLst != null && ldElmntLst.getLength()>0) { 154 Element ldElmnt = (Element) ldElmntLst.item(0); 155 NodeList ldNm = ldElmnt.getChildNodes(); 156 String pAsync = (ldNm.item(0)).getNodeValue().trim(); 157 trace("Async supported: %s", pAsync); 158 filter.setAsyncSupported(Boolean.valueOf(pAsync)); 159 } 160 // add to map 161 filterMap.put(pName, filter); 162 } 163 // add filters 164 info.addFilters(filterMap.values()); 165 } 166 // do filter mappings 167 if (!filterMap.isEmpty()) { 168 listOfElements = doc.getElementsByTagName("filter-mapping"); 169 totalElements = listOfElements.getLength(); 170 trace("Total no of filter-mappings: %s", totalElements); 171 for (int s = 0; s < totalElements; s++) { 172 Node fstNode = listOfElements.item(s); 173 if (fstNode.getNodeType() == Node.ELEMENT_NODE) { 174 Element fstElmnt = (Element) fstNode; 175 NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("filter-name"); 176 Element fstNmElmnt = (Element) fstNmElmntLst.item(0); 177 NodeList fstNm = fstNmElmnt.getChildNodes(); 178 String pName = (fstNm.item(0)).getNodeValue().trim(); 179 trace("Param name: %s", pName); 180 // lookup the filter info 181 FilterInfo filter = filterMap.get(pName); 182 // add the mapping 183 if (filter != null) { 184 NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("url-pattern"); 185 if(lstNmElmntLst != null && lstNmElmntLst.item(0) != null) { 186 Element lstNmElmnt = (Element) lstNmElmntLst.item(0); 187 NodeList lstNm = lstNmElmnt.getChildNodes(); 188 String pValue = (lstNm.item(0)).getNodeValue().trim(); 189 NodeList dstNmElmntLst = fstElmnt.getElementsByTagName("dispatcher"); 190 191 if ( dstNmElmntLst == null || dstNmElmntLst.getLength() == 0 ){ 192 trace("Request FilterURL Mapping: " + pName + " is %s", pValue); 193 info.addFilterUrlMapping( pName, pValue, DispatcherType.valueOf( "REQUEST") ); 194 } else { 195 int totalDispatchers = dstNmElmntLst.getLength(); 196 for(int i = 0; i < totalDispatchers; i++){ 197 Element dstNmElmnt = (Element) dstNmElmntLst.item(i); 198 NodeList dstNm = dstNmElmnt.getChildNodes(); 199 String dValue = (dstNm.item(0)).getNodeValue().trim(); 200 info.addFilterUrlMapping( pName, pValue, DispatcherType.valueOf( dValue ) ); 201 trace("FilterURL: %s", pName); 202 trace("FilterURL: %s", pValue); 203 } 204 } 205 } 206 lstNmElmntLst = fstElmnt.getElementsByTagName("servlet-name"); 207 if (lstNmElmntLst != null && lstNmElmntLst.item(0) != null) { 208 Element inNmElmnt = (Element) lstNmElmntLst.item(0); 209 NodeList inNm = inNmElmnt.getChildNodes(); 210 String pValue = (inNm.item(0)).getNodeValue().trim(); 211 info.addFilterServletNameMapping(pName, pValue, DispatcherType.valueOf("REQUEST")); 212 trace("Filter Servlet: " + pName + " for %s", pValue); 213 } 214 } else { 215 log.warnf("No servlet found for %s", pName); 216 } 217 } 218 } 219 } 220 // do servlet 221 NodeList listOfServlets = doc.getElementsByTagName("servlet"); 222 totalElements = listOfServlets.getLength(); 223 trace("Total no of servlets: %s", totalElements); 224 for (int s = 0; s < listOfServlets.getLength(); s++) { 225 Node fstNode = listOfServlets.item(s); 226 if (fstNode.getNodeType() == Node.ELEMENT_NODE) { 227 Element fstElmnt = (Element) fstNode; 228 NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("servlet-name"); 229 Element fstNmElmnt = (Element) fstNmElmntLst.item(0); 230 NodeList fstNm = fstNmElmnt.getChildNodes(); 231 String pName = (fstNm.item(0)).getNodeValue().trim(); 232 trace("Adding servlet to undertow: ************* %s *************", pName); 233 trace("Param name: %s", pName); 234 NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("servlet-class"); 235 Element lstNmElmnt = (Element) lstNmElmntLst.item(0); 236 NodeList lstNm = lstNmElmnt.getChildNodes(); 237 String pValue = (lstNm.item(0)).getNodeValue().trim(); 238 trace("Param value: %s", pValue); 239 // create the servlet 240 ServletInfo servlet = new ServletInfo(pName, (Class<? extends Servlet>) info.getClassLoader() 241 .loadClass(pValue)); 242 // parse load on startup 243 NodeList ldElmntLst = fstElmnt.getElementsByTagName("load-on-startup"); 244 if (ldElmntLst != null) { 245 Element ldElmnt = (Element) ldElmntLst.item(0); 246 if(ldElmnt != null) { 247 NodeList ldNm = ldElmnt.getChildNodes(); 248 String pLoad = (ldNm.item(0)).getNodeValue().trim(); 249 trace("Load on startup: %s", pLoad); 250 servlet.setLoadOnStartup(Integer.valueOf(pLoad)); 251 } 252 } 253 servlet.setRequireWelcomeFileMapping(true); 254 // do init-param - available in the context of a servlet 255 // or filter in the web application 256 listOfElements = fstElmnt.getElementsByTagName("init-param"); 257 totalElements = listOfElements.getLength(); 258 trace("Total no of init-params: %s", totalElements); 259 for (int i = 0; i < totalElements; i++) { 260 Node inNode = listOfElements.item(i); 261 if (inNode.getNodeType() == Node.ELEMENT_NODE) { 262 Element inElmnt = (Element) inNode; 263 NodeList inNmElmntLst = inElmnt.getElementsByTagName("param-name"); 264 Element inNmElmnt = (Element) inNmElmntLst.item(0); 265 NodeList inNm = inNmElmnt.getChildNodes(); 266 String inName = (inNm.item(0)).getNodeValue().trim(); 267 trace("Param name: %s", inName); 268 NodeList inValElmntLst = inElmnt.getElementsByTagName("param-value"); 269 Element inValElmnt = (Element) inValElmntLst.item(0); 270 NodeList inVal = inValElmnt.getChildNodes(); 271 String inValue = (inVal.item(0)).getNodeValue().trim(); 272 inValue = inValue.replaceAll(".?/WEB-INF", webinfPath); 273 trace("Param value: %s", inValue); 274 // add the param 275 servlet.addInitParam(inName, inValue); 276 } 277 } 278 // add to the map 279 servletMap.put(servlet.getName(), servlet); 280 } 281 } 282 // do servlet-mapping 283 if (!servletMap.isEmpty()) { 284 listOfElements = doc.getElementsByTagName("servlet-mapping"); 285 totalElements = listOfElements.getLength(); 286 log.warnf("Total no of servlet-mappings: %2", totalElements); 287 for (int s = 0; s < totalElements; s++) { 288 Node fstNode = listOfElements.item(s); 289 if (fstNode.getNodeType() == Node.ELEMENT_NODE) { 290 Element fstElmnt = (Element) fstNode; 291 NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("servlet-name"); 292 Element fstNmElmnt = (Element) fstNmElmntLst.item(0); 293 NodeList fstNm = fstNmElmnt.getChildNodes(); 294 String pName = (fstNm.item(0)).getNodeValue().trim(); 295 trace("Param name: %s", pName); 296 // lookup the servlet info 297 ServletInfo servlet = servletMap.get(pName); 298 // add the mapping 299 if (servlet != null) { 300 NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("url-pattern"); 301 for (int p = 0; p < lstNmElmntLst.getLength(); p++) { 302 Element lstNmElmnt = (Element) lstNmElmntLst.item(p); 303 NodeList lstNm = lstNmElmnt.getChildNodes(); 304 String pValue = (lstNm.item(0)).getNodeValue().trim(); 305 trace("Param value: %s", pValue); 306 servlet.addMapping(pValue); 307 308 } 309 } else { 310 log.warnf("No servlet found for %s", pName); 311 } 312 } 313 } 314 // add servlets to deploy info 315 info.addServlets(servletMap.values()); 316 } 317 // do welcome files 318 listOfElements = doc.getElementsByTagName("welcome-file-list"); 319 totalElements = listOfElements.getLength(); 320 trace("Total no of welcome-files: %s", totalElements); 321 for (int s = 0; s < totalElements; s++) { 322 Node fstNode = listOfElements.item(s); 323 if (fstNode.getNodeType() == Node.ELEMENT_NODE) { 324 Element fstElmnt = (Element) fstNode; 325 NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("welcome-file"); 326 int totalWelcomeFiles = fstNmElmntLst.getLength(); 327 328 log.debug( "Adding welcome pages:" ); 329 for(int i=0; i < totalWelcomeFiles; i++){ 330 Element fstNmElmnt = (Element) fstNmElmntLst.item(i); 331 NodeList fstNm = fstNmElmnt.getChildNodes(); 332 String pName = (fstNm.item(0)).getNodeValue().trim(); 333 trace("Param name: %s", pName); 334 log.debug( "welcome page:" + pName); 335 // add welcome page 336 info.addWelcomePage(pName); 337 } 338 } 339 } 340 // do mime types files 341 listOfElements = doc.getElementsByTagName("mime-mapping"); 342 totalElements = listOfElements.getLength(); 343 log.debugf("Total no of mime-mapping: %s", totalElements); 344 for (int i = 0; i < totalElements; i++) { 345 Node inNode = listOfElements.item(i); 346 if (inNode.getNodeType() == Node.ELEMENT_NODE) { 347 Element inElmnt = (Element) inNode; 348 NodeList inNmElmntLst = inElmnt.getElementsByTagName("extension"); 349 Element inNmElmnt = (Element) inNmElmntLst.item(0); 350 NodeList inNm = inNmElmnt.getChildNodes(); 351 String extention = (inNm.item(0)).getNodeValue().trim(); 352 NodeList inValElmntLst = inElmnt.getElementsByTagName("mime-type"); 353 Element inValElmnt = (Element) inValElmntLst.item(0); 354 NodeList inVal = inValElmnt.getChildNodes(); 355 String mimeType = (inVal.item(0)).getNodeValue().trim(); 356 log.debug("extension: " + extention + " mime-type: "+mimeType); 357 // add the type 358 info.addMimeMapping(new MimeMapping(extention,mimeType)); 359 } 360 } 361 // do display name 362 NodeList dNmElmntLst = doc.getElementsByTagName("display-name"); 363 if (dNmElmntLst.getLength() == 1) { 364 Node dNmNode = dNmElmntLst.item(0); 365 if (dNmNode.getNodeType() == Node.TEXT_NODE) { 366 String dName = dNmNode.getNodeValue().trim(); 367 trace("Display name: %s", dName); 368 info.setDisplayName(dName); 369 } 370 } 371 // TODO add security stuff 372 } catch (Exception e) { 373 e.printStackTrace(); 374 log.error("Error reading web.xml", e); 375 } 376 } 377 378 private static void trace(String string, Object elements) { 379 log.tracef(string,elements); 380// System.out.printf(string,elements); 381// System.out.println(); 382 } 383 384}