1 25 package org.ofbiz.catalina.container; 26 27 import java.io.File ; 28 import java.io.IOException ; 29 import java.net.URL ; 30 import java.util.Collection ; 31 import java.util.HashMap ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Map ; 35 import javax.naming.InitialContext ; 36 import javax.naming.NamingException ; 37 import javax.xml.parsers.ParserConfigurationException ; 38 39 import org.ofbiz.base.component.ComponentConfig; 40 import org.ofbiz.base.container.ClassLoaderContainer; 41 import org.ofbiz.base.container.Container; 42 import org.ofbiz.base.container.ContainerConfig; 43 import org.ofbiz.base.container.ContainerException; 44 import org.ofbiz.base.util.Debug; 45 import org.ofbiz.base.util.UtilURL; 46 import org.ofbiz.base.util.UtilValidate; 47 import org.ofbiz.base.util.UtilXml; 48 import org.ofbiz.entity.GenericDelegator; 49 50 import org.apache.catalina.Cluster; 51 import org.apache.catalina.Context; 52 import org.apache.catalina.Engine; 53 import org.apache.catalina.Host; 54 import org.apache.catalina.LifecycleException; 55 import org.apache.catalina.Manager; 56 import org.apache.catalina.ServerFactory; 57 import org.apache.catalina.cluster.mcast.McastService; 58 import org.apache.catalina.cluster.tcp.ReplicationListener; 59 import org.apache.catalina.cluster.tcp.ReplicationTransmitter; 60 import org.apache.catalina.cluster.tcp.ReplicationValve; 61 import org.apache.catalina.cluster.tcp.SimpleTcpCluster; 62 import org.apache.catalina.connector.Connector; 63 import org.apache.catalina.core.StandardContext; 64 import org.apache.catalina.core.StandardEngine; 65 import org.apache.catalina.core.StandardServer; 66 import org.apache.catalina.core.StandardWrapper; 67 import org.apache.catalina.realm.MemoryRealm; 68 import org.apache.catalina.session.StandardManager; 69 import org.apache.catalina.startup.Embedded; 70 import org.apache.catalina.util.ServerInfo; 71 import org.apache.catalina.valves.AccessLogValve; 72 import org.apache.catalina.valves.RequestDumperValve; 73 import org.apache.coyote.ProtocolHandler; 74 import org.apache.coyote.http11.Http11Protocol; 75 import org.w3c.dom.Document ; 76 import org.w3c.dom.Element ; 77 import org.xml.sax.SAXException ; 78 79 127 128 135 public class CatalinaContainer implements Container { 136 137 public static final String CATALINA_HOSTS_HOME = System.getProperty("ofbiz.home") + "/framework/catalina/hosts"; 138 public static final String J2EE_SERVER = "OFBiz Container 3.1"; 139 public static final String J2EE_APP = "OFBiz"; 140 public static final String module = CatalinaContainer.class.getName(); 141 protected static Map mimeTypes = new HashMap (); 142 143 protected GenericDelegator delegator = null; 144 protected Embedded embedded = null; 145 protected Map clusterConfig = new HashMap (); 146 protected Map engines = new HashMap (); 147 protected Map hosts = new HashMap (); 148 149 protected boolean contextReloadable = false; 150 protected boolean crossContext = false; 151 protected boolean distribute = false; 152 153 protected boolean enableDefaultMimeTypes = true; 154 155 158 public void init(String [] args, String configFile) throws ContainerException { 159 System.setProperty("catalina.home", System.getProperty("ofbiz.home") + "/framework/catalina"); 161 162 ContainerConfig.Container cc = ContainerConfig.getContainer("catalina-container", configFile); 164 if (cc == null) { 165 throw new ContainerException("No catalina-container configuration found in container config!"); 166 } 167 168 boolean useNaming = ContainerConfig.getPropertyValue(cc, "use-naming", false); 170 172 this.delegator = GenericDelegator.getGenericDelegator(ContainerConfig.getPropertyValue(cc, "delegator-name", "default")); 174 this.contextReloadable = ContainerConfig.getPropertyValue(cc, "apps-context-reloadable", false); 175 this.crossContext = ContainerConfig.getPropertyValue(cc, "apps-cross-context", true); 176 this.distribute = ContainerConfig.getPropertyValue(cc, "apps-distributable", true); 177 178 StandardServer server = (StandardServer) ServerFactory.getServer(); 180 try { 181 server.setGlobalNamingContext(new InitialContext ()); 182 } catch (NamingException e) { 183 throw new ContainerException(e); 184 } 185 186 embedded = new Embedded(); 188 embedded.setUseNaming(useNaming); 189 190 List engineProps = cc.getPropertiesWithValue("engine"); 192 if (engineProps == null && engineProps.size() == 0) { 193 throw new ContainerException("Cannot load CatalinaContainer; no engines defined!"); 194 } 195 Iterator ei = engineProps.iterator(); 196 while (ei.hasNext()) { 197 ContainerConfig.Container.Property engineProp = (ContainerConfig.Container.Property) ei.next(); 198 createEngine(engineProp); 199 } 200 201 loadComponents(); 203 204 List connectorProps = cc.getPropertiesWithValue("connector"); 206 if (connectorProps == null && connectorProps.size() == 0) { 207 throw new ContainerException("Cannot load CatalinaContainer; no connectors defined!"); 208 } 209 Iterator ci = connectorProps.iterator(); 210 while (ci.hasNext()) { 211 ContainerConfig.Container.Property connectorProp = (ContainerConfig.Container.Property) ci.next(); 212 createConnector(connectorProp); 213 } 214 215 try { 216 embedded.initialize(); 217 } catch (LifecycleException e) { 218 throw new ContainerException(e); 219 } 220 } 221 222 public boolean start() throws ContainerException { 223 try { 225 embedded.start(); 226 } catch (LifecycleException e) { 227 throw new ContainerException(e); 228 } 229 230 Connector[] cons = embedded.findConnectors(); 231 for (int i = 0; i < cons.length; i++) { 232 ProtocolHandler ph = cons[i].getProtocolHandler(); 233 if (ph instanceof Http11Protocol) { 234 Http11Protocol hph = (Http11Protocol) ph; 235 Debug.logInfo("Connector " + hph.getProtocol() + " @ " + hph.getPort() + " - " + 236 (hph.getSecure() ? "secure" : "not-secure") + " [" + cons[i].getProtocolHandlerClassName() + "] started.", module); 237 } else { 238 Debug.logInfo("Connector " + cons[i].getProtocol() + " @ " + cons[i].getPort() + " - " + 239 (cons[i].getSecure() ? "secure" : "not-secure") + " [" + cons[i].getProtocolHandlerClassName() + "] started.", module); 240 } 241 } 242 Debug.logInfo("Started " + ServerInfo.getServerInfo(), module); 243 return true; 244 } 245 246 protected Engine createEngine(ContainerConfig.Container.Property engineConfig) throws ContainerException { 247 if (embedded == null) { 248 throw new ContainerException("Cannot create Engine without Embedded instance!"); 249 } 250 251 ContainerConfig.Container.Property defaultHostProp = engineConfig.getProperty("default-host"); 252 if (defaultHostProp == null) { 253 throw new ContainerException("default-host element of server property is required for catalina!"); 254 } 255 256 String engineName = engineConfig.name; 257 String hostName = defaultHostProp.value; 258 259 StandardEngine engine = (StandardEngine) embedded.createEngine(); 260 engine.setName(engineName); 261 engine.setDefaultHost(hostName); 262 263 String jvmRoute = ContainerConfig.getPropertyValue(engineConfig, "jvm-route", null); 265 if (jvmRoute != null) { 266 engine.setJvmRoute(jvmRoute); 267 } 268 269 String dbConfigPath = "config/catalina-users.xml"; 271 MemoryRealm realm = new MemoryRealm(); 272 realm.setPathname(dbConfigPath); 273 engine.setRealm(realm); 274 275 engines.put(engine.getName(), engine); 277 278 Host host = createHost(engine, hostName); 280 hosts.put(engineName + "._DEFAULT", host); 281 282 List clusterProps = engineConfig.getPropertiesWithValue("cluster"); 284 if (clusterProps != null && clusterProps.size() > 1) { 285 throw new ContainerException("Only one cluster configuration allowed per engine"); 286 } 287 288 if (clusterProps != null && clusterProps.size() > 0) { 289 ContainerConfig.Container.Property clusterProp = (ContainerConfig.Container.Property) clusterProps.get(0); 290 createCluster(clusterProp, host); 291 clusterConfig.put(engineName, clusterProp); 292 } 293 294 boolean enableRequestDump = ContainerConfig.getPropertyValue(engineConfig, "enable-request-dump", false); 296 if (enableRequestDump) { 297 RequestDumperValve rdv = new RequestDumperValve(); 298 engine.addValve(rdv); 299 } 300 301 String logDir = ContainerConfig.getPropertyValue(engineConfig, "access-log-dir", null); 303 AccessLogValve al = null; 304 if (logDir != null) { 305 al = new AccessLogValve(); 306 if (!logDir.startsWith("/")) { 307 logDir = System.getProperty("ofbiz.home") + "/" + logDir; 308 } 309 File logFile = new File (logDir); 310 if (!logFile.isDirectory()) { 311 throw new ContainerException("Log directory [" + logDir + "] is not available; make sure the directory is created"); 312 } 313 al.setDirectory(logFile.getAbsolutePath()); 314 } 315 316 String alp2 = ContainerConfig.getPropertyValue(engineConfig, "access-log-pattern", null); 317 if (al != null && !UtilValidate.isEmpty(alp2)) { 318 al.setPattern(alp2); 319 } 320 321 String alp3 = ContainerConfig.getPropertyValue(engineConfig, "access-log-prefix", null); 322 if (al != null && !UtilValidate.isEmpty(alp3)) { 323 al.setPrefix(alp3); 324 } 325 326 327 boolean alp4 = ContainerConfig.getPropertyValue(engineConfig, "access-log-resolve", true); 328 if (al != null) { 329 al.setResolveHosts(alp4); 330 } 331 332 boolean alp5 = ContainerConfig.getPropertyValue(engineConfig, "access-log-rotate", false); 333 if (al != null) { 334 al.setRotatable(alp5); 335 } 336 337 if (al != null) { 338 engine.addValve(al); 339 } 340 341 embedded.addEngine(engine); 342 return engine; 343 } 344 345 protected Host createHost(Engine engine, String hostName) throws ContainerException { 346 if (embedded == null) { 347 throw new ContainerException("Cannot create Host without Embedded instance!"); 348 } 349 350 Host host = embedded.createHost(hostName, CATALINA_HOSTS_HOME); 351 host.setDeployOnStartup(true); 352 host.setAutoDeploy(true); 353 host.setRealm(engine.getRealm()); 354 engine.addChild(host); 355 hosts.put(engine.getName() + hostName, host); 356 357 return host; 358 } 359 360 protected Cluster createCluster(ContainerConfig.Container.Property clusterProps, Host host) throws ContainerException { 361 String defaultValveFilter = ".*.gif;.*.js;.*.jpg;.*.htm;.*.html;.*.txt;"; 362 363 ReplicationValve clusterValve = new ReplicationValve(); 364 clusterValve.setFilter(ContainerConfig.getPropertyValue(clusterProps, "rep-valve-filter", defaultValveFilter)); 365 366 String mcb = ContainerConfig.getPropertyValue(clusterProps, "mcast-bind-addr", null); 367 String mca = ContainerConfig.getPropertyValue(clusterProps, "mcast-addr", null); 368 int mcp = ContainerConfig.getPropertyValue(clusterProps, "mcast-port", -1); 369 int mcd = ContainerConfig.getPropertyValue(clusterProps, "mcast-freq", 500); 370 int mcf = ContainerConfig.getPropertyValue(clusterProps, "mcast-drop-time", 3000); 371 372 if (mca == null || mcp == -1) { 373 throw new ContainerException("Cluster configuration requires mcast-addr and mcast-port properties"); 374 } 375 376 McastService mcast = new McastService(); 377 if (mcb != null) { 378 mcast.setMcastBindAddress(mcb); 379 } 380 381 mcast.setMcastAddr(mca); 382 mcast.setMcastPort(mcp); 383 mcast.setMcastDropTime(mcd); 384 mcast.setMcastFrequency(mcf); 385 386 String tla = ContainerConfig.getPropertyValue(clusterProps, "tcp-listen-host", "auto"); 387 int tlp = ContainerConfig.getPropertyValue(clusterProps, "tcp-listen-port", 4001); 388 int tlt = ContainerConfig.getPropertyValue(clusterProps, "tcp-sector-timeout", 100); 389 int tlc = ContainerConfig.getPropertyValue(clusterProps, "tcp-thread-count", 6); 390 392 if (tlp == -1) { 393 throw new ContainerException("Cluster configuration requires tcp-listen-port property"); 394 } 395 396 ReplicationListener listener = new ReplicationListener(); 397 listener.setTcpListenAddress(tla); 398 listener.setTcpListenPort(tlp); 399 listener.setTcpSelectorTimeout(tlt); 400 listener.setTcpThreadCount(tlc); 401 403 ReplicationTransmitter trans = new ReplicationTransmitter(); 404 trans.setReplicationMode(ContainerConfig.getPropertyValue(clusterProps, "replication-mode", "pooled")); 405 406 String mgrClassName = ContainerConfig.getPropertyValue(clusterProps, "manager-class", "org.apache.catalina.cluster.session.DeltaManager"); 407 boolean expireSession = ContainerConfig.getPropertyValue(clusterProps, "expire-session", false); 409 boolean useDirty = ContainerConfig.getPropertyValue(clusterProps, "use-dirty", true); 410 411 SimpleTcpCluster cluster = new SimpleTcpCluster(); 412 cluster.setClusterName(clusterProps.name); 413 cluster.setManagerClassName(mgrClassName); 414 cluster.setExpireSessionsOnShutdown(expireSession); 416 cluster.setUseDirtyFlag(useDirty); 417 418 cluster.setClusterReceiver(listener); 419 cluster.setClusterSender(trans); 420 cluster.setMembershipService(mcast); 421 cluster.addValve(clusterValve); 422 cluster.setPrintToScreen(true); 423 424 host.setCluster(cluster); 426 Debug.logInfo("Catalina Cluster [" + cluster.getClusterName() + "] configured for host - " + host.getName(), module); 427 428 return cluster; 429 } 430 431 protected Connector createConnector(ContainerConfig.Container.Property connectorProp) throws ContainerException { 432 if (embedded == null) { 433 throw new ContainerException("Cannot create Connector without Embedded instance!"); 434 } 435 436 String protocol = ContainerConfig.getPropertyValue(connectorProp, "protocol", "HTTP/1.1"); 438 String address = ContainerConfig.getPropertyValue(connectorProp, "address", "0.0.0.0"); 439 int port = ContainerConfig.getPropertyValue(connectorProp, "port", 0); 440 boolean secure = ContainerConfig.getPropertyValue(connectorProp, "secure", false); 441 if (protocol.toLowerCase().startsWith("ajp")) { 442 protocol = "ajp"; 443 } else if ("memory".equals(protocol.toLowerCase())) { 444 protocol = "memory"; 445 } else if (secure) { 446 protocol = "https"; 447 } else { 448 protocol = "http"; 449 } 450 451 Connector connector = null; 452 if (connectorProp.properties != null && connectorProp.properties.size() > 0) { 453 connector = embedded.createConnector(address, port, protocol); 454 try { 455 Iterator i = connectorProp.properties.values().iterator(); 456 while (i.hasNext()) { 457 ContainerConfig.Container.Property prop = (ContainerConfig.Container.Property) i.next(); 458 connector.setProperty(prop.name, prop.value); 459 } 461 embedded.addConnector(connector); 462 } catch (Exception e) { 463 throw new ContainerException(e); 464 } 465 } 466 return connector; 467 } 468 469 protected Context createContext(ComponentConfig.WebappInfo appInfo) throws ContainerException { 470 Map initParameters = appInfo.getInitParameters(); 472 List virtualHosts = appInfo.getVirtualHosts(); 473 Engine engine = (Engine) engines.get(appInfo.server); 474 if (engine == null) { 475 Debug.logWarning("Server with name [" + appInfo.server + "] not found; not mounting [" + appInfo.name + "]", module); 476 return null; 477 } 478 479 String location = appInfo.componentConfig.getRootLocation() + appInfo.location; 481 location = location.replace('\\', '/'); 482 if (location.endsWith("/")) { 483 location = location.substring(0, location.length() - 1); 484 } 485 486 String mount = appInfo.mountPoint; 488 if (mount.endsWith("/*")) { 489 mount = mount.substring(0, mount.length() - 2); 490 } 491 492 Manager sessionMgr = new StandardManager(); 494 495 StandardContext context = (StandardContext) embedded.createContext(mount, location); 497 context.setJ2EEApplication(J2EE_APP); 498 context.setJ2EEServer(J2EE_SERVER); 499 context.setLoader(embedded.createLoader(ClassLoaderContainer.getClassLoader())); 500 501 context.setDisplayName(appInfo.name); 502 context.setDocBase(location); 503 context.setAllowLinking(true); 504 505 context.setReloadable(contextReloadable); 506 context.setDistributable(distribute); 507 context.setCrossContext(crossContext); 508 context.setManager(sessionMgr); 509 context.getServletContext().setAttribute("_serverId", appInfo.server); 510 511 StandardWrapper defaultServlet = new StandardWrapper(); 513 defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet"); 514 defaultServlet.setServletName("default"); 515 defaultServlet.setLoadOnStartup(1); 516 defaultServlet.addInitParameter("debug", "0"); 517 defaultServlet.addInitParameter("listing", "true"); 518 defaultServlet.addMapping("/"); 519 context.addChild(defaultServlet); 520 context.addServletMapping("/", "default"); 521 522 StandardWrapper jspServlet = new StandardWrapper(); 524 jspServlet.setServletClass("org.apache.jasper.servlet.JspServlet"); 525 jspServlet.setServletName("jsp"); 526 jspServlet.setLoadOnStartup(1); 527 jspServlet.addInitParameter("fork", "false"); 528 jspServlet.addInitParameter("xpoweredBy", "true"); 529 jspServlet.addMapping("*.jsp"); 530 jspServlet.addMapping("*.jspx"); 531 context.addChild(jspServlet); 532 context.addServletMapping("*.jsp", "jsp"); 533 534 configureMimeTypes(context); 536 537 Iterator ip = initParameters.keySet().iterator(); 539 while (ip.hasNext()) { 540 String paramName = (String ) ip.next(); 541 context.addParameter(paramName, (String ) initParameters.get(paramName)); 542 } 543 544 if (UtilValidate.isEmpty(virtualHosts)) { 545 Host host = (Host) hosts.get(engine.getName() + "._DEFAULT"); 546 context.setRealm(host.getRealm()); 547 host.addChild(context); 548 context.getMapper().setDefaultHostName(host.getName()); 549 } else { 550 Iterator vhi = virtualHosts.iterator(); 552 String hostName = (String ) vhi.next(); 553 554 boolean newHost = false; 555 Host host = (Host) hosts.get(engine.getName() + "." + hostName); 556 if (host == null) { 557 host = createHost(engine, hostName); 558 newHost = true; 559 } 560 while (vhi.hasNext()) { 561 host.addAlias((String ) vhi.next()); 562 } 563 context.setRealm(host.getRealm()); 564 host.addChild(context); 565 context.getMapper().setDefaultHostName(host.getName()); 566 567 if (newHost) { 568 hosts.put(engine.getName() + "." + hostName, host); 569 } 570 } 571 572 return context; 573 } 574 575 protected void loadComponents() throws ContainerException { 576 if (embedded == null) { 577 throw new ContainerException("Cannot load web applications without Embedded instance!"); 578 } 579 580 Collection componentConfigs = ComponentConfig.getAllComponents(); 582 if (componentConfigs != null) { 583 Iterator components = componentConfigs.iterator(); 584 while (components.hasNext()) { 585 ComponentConfig component = (ComponentConfig) components.next(); 586 Iterator appInfos = component.getWebappInfos().iterator(); 587 while (appInfos.hasNext()) { 588 ComponentConfig.WebappInfo appInfo = (ComponentConfig.WebappInfo) appInfos.next(); 589 createContext(appInfo); 590 } 591 } 592 } 593 594 } 595 596 public void stop() throws ContainerException { 597 try { 598 embedded.stop(); 599 } catch (LifecycleException e) { 600 Debug.logError(e, module); 602 } 603 } 604 605 protected void configureMimeTypes(Context context) throws ContainerException { 606 Map mimeTypes = CatalinaContainer.getMimeTypes(); 607 if (mimeTypes != null && mimeTypes.size() > 0) { 608 Iterator i = mimeTypes.entrySet().iterator(); 609 while (i.hasNext()) { 610 Map.Entry entry = (Map.Entry ) i.next(); 611 context.addMimeMapping((String )entry.getKey(), (String )entry.getValue()); 612 } 613 } 614 } 615 616 protected static synchronized Map getMimeTypes() throws ContainerException { 617 if (mimeTypes != null && mimeTypes.size() > 0) { 618 return mimeTypes; 619 } 620 621 if (mimeTypes == null) mimeTypes = new HashMap (); 622 URL xmlUrl = UtilURL.fromResource("mime-type.xml"); 623 624 Document mimeTypeDoc = null; 626 try { 627 mimeTypeDoc = UtilXml.readXmlDocument(xmlUrl, true); 628 } catch (SAXException e) { 629 throw new ContainerException("Error reading the mime-type.xml config file: " + xmlUrl, e); 630 } catch (ParserConfigurationException e) { 631 throw new ContainerException("Error reading the mime-type.xml config file: " + xmlUrl, e); 632 } catch (IOException e) { 633 throw new ContainerException("Error reading the mime-type.xml config file: " + xmlUrl, e); 634 } 635 636 if (mimeTypeDoc == null) { 637 Debug.logError("Null document returned for mime-type.xml", module); 638 return null; 639 } 640 641 Element root = mimeTypeDoc.getDocumentElement(); 643 644 Iterator elementIter = UtilXml.childElementList(root, "mime-mapping").iterator(); 646 while (elementIter.hasNext()) { 647 Element curElement = (Element ) elementIter.next(); 648 String extension = UtilXml.childElementValue(curElement, "extension"); 649 String type = UtilXml.childElementValue(curElement, "mime-type"); 650 mimeTypes.put(extension, type); 651 } 652 653 return mimeTypes; 654 } 655 } 656 | Popular Tags |