001: /*
002: * $Id: JettyContainer.java,v 1.20 2004/01/24 18:43:02 ajzeneski Exp $
003: *
004: * Copyright (c) 2003 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.base.container;
026:
027: import java.io.IOException;
028: import java.net.UnknownHostException;
029: import java.util.Collection;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034:
035: import org.apache.log4j.Logger;
036: import org.apache.log4j.Priority;
037: import org.mortbay.http.NCSARequestLog;
038: import org.mortbay.http.SocketListener;
039: import org.mortbay.http.SunJsseListener;
040: import org.mortbay.http.ajp.AJP13Listener;
041: import org.mortbay.jetty.Server;
042: import org.mortbay.jetty.servlet.WebApplicationContext;
043: import org.mortbay.util.Frame;
044: import org.mortbay.util.Log;
045: import org.mortbay.util.LogSink;
046: import org.mortbay.util.MultiException;
047: import org.mortbay.util.ThreadedServer;
048: import org.ofbiz.base.component.ComponentConfig;
049: import org.ofbiz.base.util.Debug;
050: import org.ofbiz.base.util.UtilURL;
051: import org.ofbiz.base.util.SSLUtil;
052:
053: /**
054: * JettyContainer - Container implementation for Jetty
055: * This container depends on the ComponentContainer as well.
056: *
057: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
058: *@version $Revision: 1.20 $
059: * @since 3.0
060: */
061: public class JettyContainer implements Container {
062:
063: public static final String module = JettyContainer.class.getName();
064: private Map servers = new HashMap();
065:
066: private void init(String configFile) throws ContainerException {
067: // configure JSSE properties
068: SSLUtil.loadJsseProperties();
069:
070: // configure jetty logging
071: Log log = Log.instance();
072: log.disableLog();
073: Log4jSink sink = new Log4jSink();
074: log.add(sink);
075: sink.setOptions(UtilURL.fromResource("debug.properties")
076: .toExternalForm());
077: try {
078: sink.start();
079: } catch (Exception e) {
080: Debug.logWarning(e, module);
081: }
082:
083: // get the container
084: ContainerConfig.Container jc = ContainerConfig.getContainer(
085: "jetty-container", configFile);
086:
087: // create the servers
088: Iterator sci = jc.properties.values().iterator();
089: while (sci.hasNext()) {
090: ContainerConfig.Container.Property prop = (ContainerConfig.Container.Property) sci
091: .next();
092: servers.put(prop.name, createServer(prop));
093: }
094:
095: // load the applications
096: Collection componentConfigs = ComponentConfig
097: .getAllComponents();
098: if (componentConfigs != null) {
099: Iterator components = componentConfigs.iterator();
100: while (components.hasNext()) {
101: ComponentConfig component = (ComponentConfig) components
102: .next();
103: Iterator appInfos = component.getWebappInfos()
104: .iterator();
105: while (appInfos.hasNext()) {
106: ComponentConfig.WebappInfo appInfo = (ComponentConfig.WebappInfo) appInfos
107: .next();
108: List virtualHosts = appInfo.getVirtualHosts();
109: Map initParameters = appInfo.getInitParameters();
110: Server server = (Server) servers
111: .get(appInfo.server);
112: if (server == null) {
113: Debug.logWarning("Server with name ["
114: + appInfo.server
115: + "] not found; not mounting ["
116: + appInfo.name + "]", module);
117: } else {
118: try {
119: // set the root location (make sure we set the paths correctly)
120: String location = component
121: .getRootLocation()
122: + appInfo.location;
123: location = location.replace('\\', '/');
124: if (!location.endsWith("/")) {
125: location = location + "/";
126: }
127:
128: // load the application
129: WebApplicationContext ctx = server
130: .addWebApplication(
131: appInfo.mountPoint,
132: location);
133: ctx.setAttribute("_serverId",
134: appInfo.server);
135:
136: // set the virtual hosts
137: Iterator vh = virtualHosts.iterator();
138: while (vh.hasNext()) {
139: ctx.addVirtualHost((String) vh.next());
140: }
141:
142: // set the init parameters
143: Iterator ip = initParameters.keySet()
144: .iterator();
145: while (ip.hasNext()) {
146: String paramName = (String) ip.next();
147: ctx.setInitParameter(paramName,
148: (String) initParameters
149: .get(paramName));
150: }
151:
152: } catch (IOException e) {
153: Debug.logError(e,
154: "Problem mounting application ["
155: + appInfo.name + " / "
156: + appInfo.location + "]",
157: module);
158: }
159: }
160: }
161: }
162: }
163: }
164:
165: private Server createServer(
166: ContainerConfig.Container.Property serverConfig)
167: throws ContainerException {
168: Server server = new Server();
169:
170: // configure the listeners/loggers
171: Iterator properties = serverConfig.properties.values()
172: .iterator();
173: while (properties.hasNext()) {
174: ContainerConfig.Container.Property props = (ContainerConfig.Container.Property) properties
175: .next();
176:
177: if ("listener".equals(props.value)) {
178: if ("default".equals(props.getProperty("type").value)) {
179: SocketListener listener = new SocketListener();
180: setListenerOptions(listener, props);
181: if (props.getProperty("identify-listener") != null) {
182: boolean identifyListener = "true"
183: .equalsIgnoreCase(props
184: .getProperty("identify-listener").value);
185: listener.setIdentifyListener(identifyListener);
186: }
187: if (props.getProperty("buffer-size") != null) {
188: int value = 0;
189: try {
190: value = Integer.parseInt(props
191: .getProperty("buffer-size").value);
192: } catch (NumberFormatException e) {
193: value = 0;
194: }
195: if (value > 0) {
196: listener.setBufferSize(value);
197: }
198: }
199: if (props.getProperty("low-resource-persist-time") != null) {
200: int value = 0;
201: try {
202: value = Integer
203: .parseInt(props
204: .getProperty("low-resource-persist-time").value);
205: } catch (NumberFormatException e) {
206: value = 0;
207: }
208: if (value > 0) {
209: listener.setLowResourcePersistTimeMs(value);
210: }
211: }
212: server.addListener(listener);
213: } else if ("sun-jsse"
214: .equals(props.getProperty("type").value)) {
215: SunJsseListener listener = new SunJsseListener();
216: setListenerOptions(listener, props);
217: if (props.getProperty("keystore") != null) {
218: listener.setKeystore(props
219: .getProperty("keystore").value);
220: }
221: if (props.getProperty("password") != null) {
222: listener.setPassword(props
223: .getProperty("password").value);
224: }
225: if (props.getProperty("key-password") != null) {
226: listener.setKeyPassword(props
227: .getProperty("key-password").value);
228: }
229: if (props.getProperty("need-client-auth") != null) {
230: boolean needClientAuth = "true"
231: .equalsIgnoreCase(props
232: .getProperty("need-client-auth").value);
233: listener.setNeedClientAuth(needClientAuth);
234: }
235: if (props.getProperty("identify-listener") != null) {
236: boolean identifyListener = "true"
237: .equalsIgnoreCase(props
238: .getProperty("identify-listener").value);
239: listener.setIdentifyListener(identifyListener);
240: }
241: if (props.getProperty("buffer-size") != null) {
242: int value = 0;
243: try {
244: value = Integer.parseInt(props
245: .getProperty("buffer-size").value);
246: } catch (NumberFormatException e) {
247: value = 0;
248: }
249: if (value > 0) {
250: listener.setBufferSize(value);
251: }
252: }
253: if (props.getProperty("low-resource-persist-time") != null) {
254: int value = 0;
255: try {
256: value = Integer
257: .parseInt(props
258: .getProperty("low-resource-persist-time").value);
259: } catch (NumberFormatException e) {
260: value = 0;
261: }
262: if (value > 0) {
263: listener.setLowResourcePersistTimeMs(value);
264: }
265: }
266: server.addListener(listener);
267: } else if ("ibm-jsse"
268: .equals(props.getProperty("type").value)) {
269: throw new ContainerException(
270: "Listener not supported yet ["
271: + props.getProperty("type").value
272: + "]");
273: } else if ("nio"
274: .equals(props.getProperty("type").value)) {
275: throw new ContainerException(
276: "Listener not supported yet ["
277: + props.getProperty("type").value
278: + "]");
279: } else if ("ajp13"
280: .equals(props.getProperty("type").value)) {
281: AJP13Listener listener = new AJP13Listener();
282: setListenerOptions(listener, props);
283: if (props.getProperty("identify-listener") != null) {
284: boolean identifyListener = "true"
285: .equalsIgnoreCase(props
286: .getProperty("identify-listener").value);
287: listener.setIdentifyListener(identifyListener);
288: }
289: if (props.getProperty("buffer-size") != null) {
290: int value = 0;
291: try {
292: value = Integer.parseInt(props
293: .getProperty("buffer-size").value);
294: } catch (NumberFormatException e) {
295: value = 0;
296: }
297: if (value > 0) {
298: listener.setBufferSize(value);
299: }
300: }
301: server.addListener(listener);
302: }
303: } else if ("request-log".equals(props.value)) {
304: NCSARequestLog rl = new NCSARequestLog();
305:
306: if (props.getProperty("filename") != null) {
307: rl.setFilename(props.getProperty("filename").value);
308: }
309:
310: if (props.getProperty("append") != null) {
311: rl.setAppend("true".equalsIgnoreCase(props
312: .getProperty("append").value));
313: }
314:
315: if (props.getProperty("buffered") != null) {
316: rl.setBuffered("true".equalsIgnoreCase(props
317: .getProperty("buffered").value));
318: }
319:
320: if (props.getProperty("extended") != null) {
321: rl.setExtended("true".equalsIgnoreCase(props
322: .getProperty("extended").value));
323: }
324:
325: if (props.getProperty("timezone") != null) {
326: rl
327: .setLogTimeZone(props
328: .getProperty("timezone").value);
329: }
330:
331: if (props.getProperty("date-format") != null) {
332: rl.setLogDateFormat(props
333: .getProperty("date-format").value);
334: }
335:
336: if (props.getProperty("retain-days") != null) {
337: int days = 90;
338: try {
339: days = Integer.parseInt(props
340: .getProperty("retain-days").value);
341: } catch (NumberFormatException e) {
342: days = 90;
343: }
344: rl.setRetainDays(days);
345: }
346: server.setRequestLog(rl);
347: }
348: }
349: return server;
350: }
351:
352: private void setListenerOptions(ThreadedServer listener,
353: ContainerConfig.Container.Property listenerProps)
354: throws ContainerException {
355: String systemHost = null;
356: if ("default".equals(listenerProps.getProperty("type").value)) {
357: systemHost = System.getProperty(listenerProps.name
358: + ".host");
359: }
360: if (listenerProps.getProperty("host") != null
361: && systemHost == null) {
362: try {
363: listener
364: .setHost(listenerProps.getProperty("host").value);
365: } catch (UnknownHostException e) {
366: throw new ContainerException(e);
367: }
368: } else {
369: String host = "0.0.0.0";
370: if (systemHost != null) {
371: host = systemHost;
372: }
373: try {
374: listener.setHost(host);
375: } catch (UnknownHostException e) {
376: throw new ContainerException(e);
377: }
378: }
379:
380: String systemPort = null;
381: if ("default".equals(listenerProps.getProperty("type").value)) {
382: systemPort = System.getProperty(listenerProps.name
383: + ".port");
384: }
385: if (listenerProps.getProperty("port") != null
386: && systemPort == null) {
387: int value = 8080;
388: try {
389: value = Integer.parseInt(listenerProps
390: .getProperty("port").value);
391: } catch (NumberFormatException e) {
392: value = 8080;
393: }
394: if (value == 0)
395: value = 8080;
396:
397: listener.setPort(value);
398: } else {
399: int port = 8080;
400: if (systemPort != null) {
401: try {
402: port = Integer.parseInt(systemPort);
403: } catch (NumberFormatException e) {
404: port = 8080;
405: }
406: }
407: listener.setPort(port);
408: }
409:
410: if (listenerProps.getProperty("min-threads") != null) {
411: int value = 0;
412: try {
413: value = Integer.parseInt(listenerProps
414: .getProperty("min-threads").value);
415: } catch (NumberFormatException e) {
416: value = 0;
417: }
418: if (value > 0) {
419: listener.setMinThreads(value);
420: }
421: }
422:
423: if (listenerProps.getProperty("max-threads") != null) {
424: int value = 0;
425: try {
426: value = Integer.parseInt(listenerProps
427: .getProperty("max-threads").value);
428: } catch (NumberFormatException e) {
429: value = 0;
430: }
431: if (value > 0) {
432: listener.setMaxThreads(value);
433: }
434: }
435:
436: if (listenerProps.getProperty("max-idle-time") != null) {
437: int value = 0;
438: try {
439: value = Integer.parseInt(listenerProps
440: .getProperty("max-idle-time").value);
441: } catch (NumberFormatException e) {
442: value = 0;
443: }
444: if (value > 0) {
445: listener.setMaxIdleTimeMs(value);
446: }
447: }
448:
449: if (listenerProps.getProperty("linger-time") != null) {
450: int value = 0;
451: try {
452: value = Integer.parseInt(listenerProps
453: .getProperty("linger-time").value);
454: } catch (NumberFormatException e) {
455: value = 0;
456: }
457: if (value > 0) {
458: listener.setLingerTimeSecs(value);
459: }
460: }
461: }
462:
463: /**
464: * @see org.ofbiz.base.container.Container#start(java.lang.String)
465: */
466: public boolean start(String configFile) throws ContainerException {
467: // start the server(s)
468: this .init(configFile);
469: if (servers != null) {
470: Iterator i = servers.values().iterator();
471: while (i.hasNext()) {
472: Server server = (Server) i.next();
473: try {
474: server.start();
475: } catch (MultiException e) {
476: Debug.logError(e, "Jetty Server Multi-Exception",
477: module);
478: throw new ContainerException(e);
479: }
480: }
481: }
482: return true;
483: }
484:
485: /**
486: * @see org.ofbiz.base.container.Container#stop()
487: */
488: public void stop() throws ContainerException {
489: if (servers != null) {
490: Iterator i = servers.values().iterator();
491: while (i.hasNext()) {
492: Server server = (Server) i.next();
493: try {
494: server.stop();
495: } catch (InterruptedException e) {
496: Debug.logWarning(e, module);
497: }
498: }
499: }
500: }
501: }
502:
503: // taken from JettyPlus
504: class Log4jSink implements LogSink {
505:
506: private String _options;
507: private transient boolean _started;
508:
509: public void setOptions(String filename) {
510: _options = filename;
511: }
512:
513: public String getOptions() {
514: return _options;
515: }
516:
517: public void start() throws Exception {
518: _started = true;
519: }
520:
521: public void stop() {
522: _started = false;
523: }
524:
525: public boolean isStarted() {
526: return _started;
527: }
528:
529: public void log(String tag, Object msg, Frame frame, long time) {
530: String method = frame.getMethod();
531: int lb = method.indexOf('(');
532: int ld = (lb > 0) ? method.lastIndexOf('.', lb) : method
533: .lastIndexOf('.');
534: if (ld < 0)
535: ld = lb;
536: String class_name = (ld > 0) ? method.substring(0, ld) : method;
537:
538: Logger log = Logger.getLogger(class_name);
539:
540: Priority priority = Priority.INFO;
541:
542: if (Log.DEBUG.equals(tag)) {
543: priority = Priority.DEBUG;
544: } else if (Log.WARN.equals(tag) || Log.ASSERT.equals(tag)) {
545: priority = Priority.ERROR;
546: } else if (Log.FAIL.equals(tag)) {
547: priority = Priority.FATAL;
548: }
549:
550: if (!log.isEnabledFor(priority)) {
551: return;
552: }
553:
554: log.log(Log4jSink.class.getName(), priority, "" + msg, null);
555: }
556:
557: public synchronized void log(String s) {
558: Logger.getRootLogger().log("jetty.log4jSink", Priority.INFO, s,
559: null);
560: }
561: }
|