1 10 package org.mmbase.servlet; 11 12 import org.mmbase.module.Module; 13 import org.mmbase.module.core.MMBase; 14 import org.mmbase.module.core.MMBaseContext; 15 16 import javax.servlet.ServletContext ; 17 import javax.servlet.ServletException ; 18 19 import javax.servlet.http.HttpServlet ; 20 import javax.servlet.http.HttpServletRequest ; 21 import javax.servlet.http.HttpServletResponse ; 22 23 import java.io.IOException ; 24 import java.io.PrintWriter ; 25 26 import java.util.*; 27 28 import org.w3c.dom.*; 29 import org.xml.sax.InputSource ; 30 import org.mmbase.util.logging.Logging; 31 import org.mmbase.util.logging.Logger; 32 import org.mmbase.util.xml.DocumentReader; 33 34 35 44 public class MMBaseServlet extends HttpServlet implements MMBaseStarter { 45 46 private static final Logger log = Logging.getLoggerInstance(MMBaseServlet.class); 47 50 protected MMBase mmbase = null; 51 53 54 57 63 private static final boolean logServlets = true; 64 private static int servletCount; 68 private static Object servletCountLock = new Object (); 69 72 private static Map runningServlets = new HashMap(); 73 77 private static int printCount; 78 79 private static int servletInstanceCount = 0; 80 private static Map servletMappings = new Hashtable(); 83 private static Map associatedServlets = new Hashtable(); 86 private static Map associatedServletMappings = new Hashtable(); 89 private static Map mapToServlet = new Hashtable(); 91 92 private long start = System.currentTimeMillis(); 93 94 98 private static boolean mmbaseInited = false; 99 100 106 protected int retryAfter = 60; 107 108 109 112 private Thread initThread; 113 114 115 122 123 protected Map getAssociations() { 124 return new Hashtable(); 125 } 126 127 130 private static class ServletEntry { 131 ServletEntry(String n) { 132 this(n, null); 133 } 134 ServletEntry(String n, Integer p) { 135 name = n; 136 if (p == null) { 137 priority = 0; 138 } else { 139 priority = p.intValue(); 140 } 141 } 142 String name; 143 int priority; 144 } 145 146 147 151 public MMBase getMMBase() { 152 return mmbase; 153 } 154 155 159 public void setMMBase(MMBase mmb) { 160 Calendar cal = Calendar.getInstance(); 161 cal.setTime(new java.util.Date (System.currentTimeMillis()-start)); 162 if (! mmbaseInited) { 163 log.info("MMBase servlets are ready to receive requests, started in " +cal.get(Calendar.MINUTE)+" min "+cal.get(Calendar.SECOND)+" sec."); 164 } 165 166 mmbase = mmb; 167 mmbaseInited = true; 168 } 169 170 171 172 175 private static ServletException initException = null; 176 177 183 public void setInitException(ServletException e) { 184 initException = e; 185 } 186 187 190 public void init() throws ServletException { 191 192 String retryAfterParameter = getInitParameter("retry-after"); 193 if (retryAfterParameter == null) { 194 retryAfter = 60; 196 } else { 197 retryAfter = new Integer (retryAfterParameter).intValue(); 198 } 199 200 if (! MMBaseContext.isInitialized()) { 201 ServletContext servletContext = getServletConfig().getServletContext(); 202 MMBaseContext.init(servletContext); 203 MMBaseContext.initHtmlRoot(); 204 } 205 206 log.info("Init of servlet " + getServletName() + "."); 207 boolean initialize = false; 208 synchronized (servletMappings) { 210 initialize = (servletInstanceCount == 0); 211 servletInstanceCount++; 212 } 213 if (initialize) { 214 try { 216 217 MMBaseContext.initHtmlRoot(); 218 java.net.URL url; 220 try { 221 url = getServletConfig().getServletContext().getResource("/WEB-INF/web.xml"); 222 } catch (NoSuchMethodError nsme) { 223 log.error(nsme); 225 url = (new java.io.File (getServletConfig().getServletContext().getRealPath("/WEB-INF/web.xml"))).toURL(); 226 } 227 if (url == null) { 228 log.warn("No web.xml found"); 229 } else { 230 InputSource path = new InputSource (url.openStream()); 231 log.service("Reading servlet mappings from " + url); 232 DocumentReader webDotXml = new DocumentReader(path, false); 233 234 for (Iterator mappingsIter = webDotXml.getChildElements("web-app", "servlet-mapping"); mappingsIter.hasNext();) { 235 Element mapping = (Element) mappingsIter.next(); 236 Element servName = webDotXml.getElementByPath(mapping, "servlet-mapping.servlet-name"); 237 String name = webDotXml.getElementValue(servName); 238 if (!(name.equals(""))) { 239 Element urlPattern=webDotXml.getElementByPath(mapping, "servlet-mapping.url-pattern"); 240 String pattern=webDotXml.getElementValue(urlPattern); 241 if (!(pattern.equals(""))) { 242 List ls = (List) servletMappings.get(name); 243 if (ls == null) { 244 ls = new ArrayList(); 245 servletMappings.put(name, ls); 246 } 247 ls.add(pattern); 248 } 249 } 250 } 251 } 252 } catch (Exception e) { 253 log.error(e.getMessage() + Logging.stackTrace(e)); 254 } 255 log.debug("Loaded servlet mappings"); 256 } 257 log.debug("Associating this servlet with functions"); 258 Iterator i = getAssociations().entrySet().iterator(); 259 while (i.hasNext()) { 260 Map.Entry e = (Map.Entry) i.next(); 261 associate((String ) e.getKey(), getServletName(), (Integer ) e.getValue()); 262 } 263 log.debug("Associating this servlet with mappings"); 264 i = getServletMappings(getServletConfig().getServletName()).iterator(); 265 while (i.hasNext()) { 266 String mapping=(String )i.next(); 267 mapToServlet.put(mapping,this); 268 } 269 270 if (initialize) { 271 initThread = new MMBaseStartThread(this); 273 initThread.start(); 274 } 275 } 276 277 283 public static HttpServlet getServletByMapping(String mapping) { 284 return (HttpServlet )mapToServlet.get(mapping); 285 } 286 287 293 public static List getServletMappings(String servletName) { 294 List ls = (List) servletMappings.get(servletName); 295 if (ls==null) { 296 return Collections.EMPTY_LIST; 297 } else { 298 return Collections.unmodifiableList(ls); 299 } 300 } 301 302 312 public static List getServletMappingsByAssociation(String function) { 313 ServletEntry mapping = (ServletEntry)associatedServletMappings.get(function); 316 if (mapping != null) { 317 List mappings = new ArrayList(); 318 mappings.add(mapping.name); 319 return mappings; 320 } 321 String name = getServletByAssociation(function); 323 if (name != null) { 324 return getServletMappings(name); 325 } else { 326 return Collections.EMPTY_LIST; 327 } 328 } 329 330 341 public static String getServletByAssociation(String function) { 342 ServletEntry e = ((ServletEntry) associatedServlets.get(function)); 343 if (e != null) { 344 return e.name; 345 } else { 346 return null; 347 } 348 } 349 350 351 360 private static synchronized void associate(String function, String servletName, Integer priority) { 361 if (priority == null) priority = new Integer (0); 362 ServletEntry m = (ServletEntry) associatedServletMappings.get(function); 363 if (m != null && (priority.intValue() < m.priority)) return; 364 ServletEntry e = (ServletEntry) associatedServlets.get(function); 365 if (e != null && (priority.intValue() < e.priority)) return; 366 log.service("Associating function '" + function + "' with servlet name " + servletName + 367 (e == null ? "" : " (previous assocation was with " + e.name +")")+ 368 (m == null ? "" : " (previous assocation was with " + m.name +")")); 369 associatedServlets.put(function, new ServletEntry(servletName, priority)); 370 if (m != null) { 371 associatedServletMappings.remove(function); 372 } 373 } 374 375 384 protected static synchronized void associateMapping(String function, String servletMapping, Integer priority) { 385 if (priority == null) priority = new Integer (0); 386 ServletEntry m = (ServletEntry) associatedServletMappings.get(function); 387 if (m != null && (priority.intValue() < m.priority)) return; 388 ServletEntry e = (ServletEntry) associatedServlets.get(function); 389 if (e != null && (priority.intValue() < e.priority)) return; 390 log.service("Associating function '" + function + "' with servlet mapping " + servletMapping + 391 (e == null ? "" : " (previous assocation was with " + e.name +")")+ 392 (m == null ? "" : " (previous assocation was with " + m.name +")")); 393 associatedServletMappings.put(function, new ServletEntry(servletMapping, priority)); 394 if (e != null) { 395 associatedServlets.remove(function); 396 } 397 } 398 399 404 protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException , IOException { 405 res.setContentType("text/plain"); 406 PrintWriter pw = res.getWriter(); 407 pw.print(org.mmbase.Version.get()); 408 String q = req.getQueryString(); 409 if ("starttime".equals(q)) { 410 pw.print("\nUp since " + new Date((long) MMBase.startTime * 1000)); 411 } else if ("uptime".equals(q)) { 412 int seconds = (int) (System.currentTimeMillis() / 1000) - MMBase.startTime; 413 int days = seconds / (60 * 60 * 24); 414 seconds %= 60 * 60 * 24; 415 int hours = seconds / (60 * 60); 416 seconds %= 60 * 60; 417 int minutes = seconds / 60; 418 seconds %= 60; 419 pw.print("\nUptime: " + (days == 1 ? "1 day" : ( days > 1 ? "" + days + " days" : "")) + 420 (hours > 0 || days > 0 ? " " + (hours == 1 ? "1 hour" : "" + hours + " hours") : "") + 421 (minutes > 0 || hours > 0 ? " " + (minutes == 1 ? "1 minute" : "" + minutes + " minutes") : "") + 422 (seconds > 0 || minutes > 0 ? " " + (seconds == 1 ? "1 second" : "" + seconds + " seconds") : "")); 423 424 } else if ("server".equals(q)) { 425 String appserver = System.getProperty("catalina.base"); pw.print("\n" + getServletContext().getServerInfo() + " " + System.getProperty("java.version") + " (" + System.getProperty("java.vendor") + ") " + (appserver == null ? "" : appserver) + "@" + java.net.InetAddress.getLocalHost().getHostName() + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch")); 427 } 428 pw.close(); 429 } 430 431 432 439 protected boolean checkInited(HttpServletResponse res) throws ServletException , IOException { 440 if (initException != null) { 441 throw initException; 442 } 443 444 if (! mmbaseInited) { 445 res.setHeader("Retry-After", "" + retryAfter); 446 res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "MMBase not yet, or not successfully initialized (check mmbase log)"); 447 } 448 return mmbaseInited; 449 } 450 451 452 453 454 460 public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException ,IOException { 461 if (!checkInited(res)) { 462 return; 463 } 464 incRefCount(req); 465 try { 466 super.service(req, res); 467 } finally { decRefCount(req); 469 } 470 } 471 472 475 476 public String getServletInfo() { 477 return "Serves MMBase version information"; 478 } 479 480 481 482 485 489 protected static String getRequestURL(HttpServletRequest req) { 490 String result = req.getRequestURI(); 491 String queryString = req.getQueryString(); 492 if (queryString!=null) result += "?" + queryString; 493 return result; 494 } 495 496 497 501 502 protected void decRefCount(HttpServletRequest req) { 503 if (logServlets) { 504 String url = getRequestURL(req) + " " + req.getMethod(); 505 synchronized (servletCountLock) { 506 servletCount--; 507 ReferenceCountServlet s = (ReferenceCountServlet) runningServlets.get(this); 508 if (s!=null) { 509 if (s.refCount == 0) { 510 runningServlets.remove(this); 511 } else { 512 s.refCount--; 513 int i = s.uris.indexOf(url); 514 if (i >= 0) s.uris.remove(i); 515 } 516 517 } } } } 521 522 529 530 protected void incRefCount(HttpServletRequest req) { 531 if (logServlets) { 532 String url = getRequestURL(req) + " " + req.getMethod(); 533 int curCount; 534 synchronized (servletCountLock) { 535 servletCount++; 536 curCount = servletCount; 537 printCount++; 538 ReferenceCountServlet s = (ReferenceCountServlet) runningServlets.get(this); 539 if (s==null) { 540 runningServlets.put(this, new ReferenceCountServlet(this, url, 0)); 541 } else { 542 s.refCount++; 543 s.uris.add(url); 544 } 545 } 547 if ((printCount & 31) == 0) { if (curCount > 0) { 549 synchronized(servletCountLock) { 550 log.info("Running servlets: " + curCount); 551 for(Iterator e = runningServlets.values().iterator(); e.hasNext();) 552 log.info(e.next()); 553 } 554 555 } } 557 } 558 } 559 560 public void destroy() { 561 log.info("Servlet " + getServletName() + " is taken out of service"); 562 if (initThread != null) { 563 initThread.interrupt(); 564 } else { 565 log.debug(" " + getServletName() + " was not initialized"); 566 } 567 log.debug("Disassociating this servlet with mappings"); 568 Iterator i = getServletMappings(getServletConfig().getServletName()).iterator(); 569 while (i.hasNext()) { 570 String mapping=(String )i.next(); 571 mapToServlet.remove(mapping); 572 } 573 super.destroy(); 574 synchronized (servletMappings) { 576 577 servletInstanceCount--; 578 if (servletInstanceCount == 0) { 579 log.info("Unloaded servlet mappings"); 580 associatedServlets.clear(); 581 servletMappings.clear(); 582 log.info("No MMBase servlets left; modules can be shut down"); 583 Module.shutdownModules(); 584 ThreadGroup threads = MMBaseContext.getThreadGroup(); 585 log.service("Send interrupt to " + threads.activeCount() + " threads in " + 586 threads + " of " + threads.getParent()); 587 threads.interrupt(); 588 Thread.yield(); 589 org.mmbase.util.FileWatcher.shutdown(); 590 org.mmbase.cache.CacheManager.shutdown(); 591 Logging.shutdown(); 592 mmbase = null; 593 } 594 } 595 } 596 597 601 private class ReferenceCountServlet { 602 606 MMBaseServlet servlet; 607 611 List uris = new ArrayList(); 612 616 int refCount; 617 618 621 ReferenceCountServlet(MMBaseServlet servlet, String uri, int refCount) { 622 this.servlet = servlet; 623 uris.add(uri); 624 this.refCount = refCount; 625 } 626 627 630 public String toString() { 631 return "servlet("+servlet+"), refcount("+(refCount+1)+"), uri's("+uris+")"; 632 } 633 } 634 635 636 } 637
| Popular Tags
|