001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.webapp;
031:
032: import com.caucho.config.types.PathBuilder;
033: import com.caucho.log.Log;
034: import com.caucho.management.j2ee.J2EEManagedObject;
035: import com.caucho.management.j2ee.WebModule;
036: import com.caucho.server.deploy.DeployConfig;
037: import com.caucho.server.deploy.DeployControllerAdmin;
038: import com.caucho.server.deploy.EnvironmentDeployController;
039: import com.caucho.server.host.Host;
040: import com.caucho.server.util.CauchoSystem;
041: import com.caucho.util.L10N;
042: import com.caucho.util.Alarm;
043: import com.caucho.vfs.Path;
044: import com.caucho.webbeans.manager.*;
045:
046: import javax.servlet.jsp.el.ELException;
047: import java.io.IOException;
048: import java.util.ArrayList;
049: import java.util.Map;
050: import java.util.logging.Logger;
051: import java.util.regex.Matcher;
052: import java.util.regex.Pattern;
053: import javax.webbeans.*;
054:
055: /**
056: * A configuration entry for a web-app.
057: */
058: public class WebAppController extends
059: EnvironmentDeployController<WebApp, WebAppConfig> {
060: private static final L10N L = new L10N(WebAppController.class);
061: private static final Logger log = Log.open(WebAppController.class);
062:
063: protected WebAppContainer _container;
064:
065: private WebAppController _parent;
066:
067: // The context path is the URL prefix for the web-app
068: private String _contextPath;
069: private String _version = "";
070:
071: // Any old version web-app
072: private WebAppController _oldWebAppController;
073: private long _oldWebAppExpireTime;
074:
075: private String _warName;
076:
077: // regexp values
078: private ArrayList<String> _regexpValues;
079:
080: private boolean _isInheritSession;
081: private boolean _isDynamicDeploy;
082:
083: private ArrayList<Path> _dependPathList = new ArrayList<Path>();
084:
085: private String _sourceType = "unknown";
086:
087: private final Object _statisticsLock = new Object();
088:
089: private volatile long _lifetimeConnectionCount;
090: private volatile long _lifetimeConnectionTime;
091: private volatile long _lifetimeReadBytes;
092: private volatile long _lifetimeWriteBytes;
093: private volatile long _lifetimeClientDisconnectCount;
094:
095: private WebAppAdmin _admin = new WebAppAdmin(this );
096:
097: public WebAppController() {
098: this ("/", "/", null, null);
099: }
100:
101: public WebAppController(String name, String contextPath,
102: Path rootDirectory, WebAppContainer container) {
103: super (name, rootDirectory);
104:
105: _container = container;
106:
107: setContextPath(contextPath);
108:
109: getVariableMap().put("app", new Var());
110: getVariableMap().put("webApp", new Var());
111: }
112:
113: /**
114: * Returns the webApp's context path
115: */
116: public String getContextPath() {
117: return _contextPath;
118: }
119:
120: /**
121: * Sets the webApp's context path
122: */
123: public void setContextPath(String contextPath) {
124: if (!contextPath.equals("") && !contextPath.startsWith("/"))
125: contextPath = "/" + contextPath;
126:
127: if (contextPath.endsWith("/"))
128: contextPath = contextPath.substring(0,
129: contextPath.length() - 1);
130:
131: _contextPath = contextPath;
132: }
133:
134: /**
135: * Returns the webApp's context path
136: */
137: public String getContextPath(String uri) {
138: if (getConfig() == null || getConfig().getURLRegexp() == null)
139: return getContextPath();
140:
141: Pattern regexp = getConfig().getURLRegexp();
142: Matcher matcher = regexp.matcher(uri);
143:
144: int tail = 0;
145: while (tail >= 0 && tail <= uri.length()) {
146: String prefix = uri.substring(0, tail);
147:
148: matcher.reset(prefix);
149:
150: if (matcher.find() && matcher.start() == 0)
151: return matcher.group();
152:
153: if (tail < uri.length()) {
154: tail = uri.indexOf('/', tail + 1);
155: if (tail < 0)
156: tail = uri.length();
157: } else
158: break;
159: }
160:
161: return _contextPath;
162: }
163:
164: /**
165: * Sets the war name prefix.
166: */
167: public void setWarName(String warName) {
168: _warName = warName;
169: }
170:
171: /**
172: * Gets the war name prefix.
173: */
174: public String getWarName() {
175: return _warName;
176: }
177:
178: /**
179: * Gets the URL
180: */
181: public String getURL() {
182: if (_container != null)
183: return _container.getURL() + _contextPath;
184: else
185: return _contextPath;
186: }
187:
188: /**
189: * Returns the parent controller.
190: */
191: public WebAppController getParent() {
192: return _parent;
193: }
194:
195: /**
196: * Returns the web-app container.
197: */
198: public WebAppContainer getContainer() {
199: return _container;
200: }
201:
202: /**
203: * Sets the parent controller.
204: */
205: public void setParentWebApp(WebAppController parent) {
206: _parent = parent;
207: }
208:
209: /**
210: * Returns the containing host.
211: */
212: public Host getHost() {
213: if (_container != null)
214: return _container.getHost();
215: else
216: return null;
217: }
218:
219: /**
220: * Returns the source (for backwards compatibility)
221: */
222: public String getSourceType() {
223: return _sourceType;
224: }
225:
226: /**
227: * Sets the source (for backwards compatibility)
228: */
229: public void setSourceType(String type) {
230: _sourceType = type;
231: }
232:
233: /**
234: * Sets the regexp values.
235: */
236: public void setRegexpValues(ArrayList<String> values) {
237: _regexpValues = values;
238: }
239:
240: /**
241: * True for inherit-session webApps.
242: */
243: public boolean isInheritSession() {
244: return _isInheritSession;
245: }
246:
247: /**
248: * True for inherit-session
249: */
250: public void setInheritSession(boolean inheritSession) {
251: _isInheritSession = inheritSession;
252: }
253:
254: /**
255: * Returns the webApp object.
256: */
257: public WebApp getWebApp() {
258: return getDeployInstance();
259: }
260:
261: /**
262: * Set true for a dynamically deployed webApp.
263: */
264: public void setDynamicDeploy(boolean isDynamicDeploy) {
265: _isDynamicDeploy = isDynamicDeploy;
266: }
267:
268: /**
269: * Returns true for a dynamically deployed webApp.
270: */
271: public boolean isDynamicDeploy() {
272: return _isDynamicDeploy;
273: }
274:
275: protected String getMBeanTypeName() {
276: return "WebApp";
277: }
278:
279: protected String getMBeanId() {
280: String name = getId();
281: if (name.equals(""))
282: name = "/";
283:
284: return name;
285: }
286:
287: /**
288: * Sets the version id.
289: */
290: protected void setVersion(String version) {
291: _version = version;
292: }
293:
294: /**
295: * Gets the version id.
296: */
297: public String getVersion() {
298: return _version;
299: }
300:
301: /**
302: * Sets the old version web-app.
303: */
304: public void setOldWebApp(WebAppController oldWebApp, long expireTime) {
305: _oldWebAppController = oldWebApp;
306: _oldWebAppExpireTime = expireTime;
307:
308: WebApp webApp = getDeployInstance();
309:
310: if (webApp != null)
311: webApp.setOldWebApp(oldWebApp.request(), expireTime);
312: }
313:
314: /**
315: * Adds a version to the controller list.
316: */
317: /*
318: protected WebAppController addVersion(WebAppController controller)
319: {
320: WebAppVersioningController versioningController
321: = new WebAppVersioningController(getContextPath());
322:
323: versioningController.addVersion(this);
324: versioningController.addVersion(controller);
325:
326: return versioningController;
327: }
328: */
329:
330: /**
331: * Returns the deploy admin.
332: */
333: @Override
334: protected DeployControllerAdmin getDeployAdmin() {
335: return _admin;
336: }
337:
338: @Override
339: protected void initEnd() {
340: super .initEnd();
341:
342: J2EEManagedObject.register(new WebModule(this ));
343: }
344:
345: /**
346: * Returns the admin.
347: */
348: public WebAppAdmin getAdmin() {
349: return _admin;
350: }
351:
352: /**
353: * Returns true if the controller matches.
354: */
355: public boolean isNameMatch(String url) {
356: if (CauchoSystem.isCaseInsensitive())
357: return url.equalsIgnoreCase(_contextPath);
358: else
359: return url.equals(_contextPath);
360: }
361:
362: /**
363: * Merges two entries.
364: */
365: protected WebAppController merge(WebAppController newController) {
366: if (getConfig() != null && getConfig().getURLRegexp() != null)
367: return newController;
368: else if (newController.getConfig() != null
369: && newController.getConfig().getURLRegexp() != null)
370: return this ;
371: else {
372: Thread thread = Thread.currentThread();
373: ClassLoader oldLoader = thread.getContextClassLoader();
374:
375: try {
376: thread.setContextClassLoader(getParentClassLoader());
377:
378: // The contextPath comes from current web-app
379: WebAppController mergedController = new WebAppController(
380: getContextPath(), getContextPath(),
381: getRootDirectory(), _container);
382:
383: // server/1h1{2,3}
384: // This controller overrides configuration from the new controller
385: mergedController.mergeController(this );
386: mergedController.mergeController(newController);
387:
388: return mergedController;
389: } finally {
390: thread.setContextClassLoader(oldLoader);
391: }
392: }
393: }
394:
395: /**
396: * Returns the var.
397: */
398: public Var getVar() {
399: return new Var();
400: }
401:
402: /**
403: * Returns the webApp object.
404: */
405: public boolean destroy() {
406: if (!super .destroy())
407: return false;
408:
409: if (_container != null)
410: _container.removeWebApp(this );
411:
412: return true;
413: }
414:
415: /**
416: * Any extra steps needed to deploy the webApp.
417: */
418: protected void protectedWebApp() throws Exception {
419: Path root = getRootDirectory();
420: // XXX: need to re-add to control.
421: root.lookup("WEB-INF").chmod(0750);
422: root.lookup("META-INF").chmod(0750);
423: }
424:
425: /**
426: * Adding any dependencies.
427: */
428: protected void addDependencies() throws Exception {
429: }
430:
431: /**
432: * Adds a dependent file.
433: */
434: public void addDepend(Path path) {
435: _dependPathList.add(path);
436: }
437:
438: /**
439: * Initialize the controller.
440: */
441: protected void initBegin() {
442: getVariableMap().put("app-dir", getRootDirectory());
443:
444: super .initBegin();
445: }
446:
447: protected void fillInitList(ArrayList<DeployConfig> initList) {
448: if (_container != null) {
449: for (WebAppConfig config : _container
450: .getWebAppDefaultList()) {
451: if (config.getPrologue() != null)
452: initList.add(config.getPrologue());
453: }
454:
455: for (WebAppConfig config : _container
456: .getWebAppDefaultList())
457: initList.add(config);
458: }
459:
460: super .fillInitList(initList);
461: }
462:
463: /**
464: * Instantiate the webApp.
465: */
466: protected WebApp instantiateDeployInstance() {
467: return new Application(this );
468: }
469:
470: /**
471: * Creates the webApp.
472: */
473: protected void configureInstanceVariables(WebApp app)
474: throws Throwable {
475: WebBeansContainer webBeans = WebBeansContainer.create();
476: webBeans.addSingleton(app, getContextPath(), Standard.class);
477: webBeans.addSingleton(getVar(), "webApp", Standard.class);
478: webBeans.addSingleton(getVar(), "app", Standard.class);
479:
480: for (Map.Entry<String, Object> entry : getVariableMap()
481: .entrySet()) {
482: webBeans.addSingleton(entry.getValue(), entry.getKey(),
483: Standard.class);
484: }
485:
486: app.setRegexp(_regexpValues);
487: app.setDynamicDeploy(isDynamicDeploy());
488:
489: if (_oldWebAppController != null
490: && Alarm.getCurrentTime() < _oldWebAppExpireTime) {
491: app.setOldWebApp(_oldWebAppController.request(),
492: _oldWebAppExpireTime);
493: }
494:
495: super .configureInstanceVariables(app);
496: }
497:
498: protected void extendJMXContext(Map<String, String> context) {
499: context.put("WebApp", getMBeanId());
500: }
501:
502: protected Path calculateRootDirectory() throws ELException {
503: Path appDir = null;
504:
505: if (appDir == null && getConfig() != null) {
506: String path = getConfig().getRootDirectory();
507:
508: if (path != null)
509: appDir = PathBuilder.lookupPath(path);
510: }
511:
512: if (appDir == null && _container != null)
513: appDir = _container.getDocumentDirectory().lookup(
514: "./" + _contextPath);
515:
516: if (appDir == null && getDeployInstance() != null)
517: appDir = getDeployInstance().getAppDir();
518:
519: return appDir;
520: }
521:
522: /**
523: * Override to prevent removing of special files.
524: */
525: protected void removeExpandFile(Path path, String relPath)
526: throws IOException {
527: if (relPath.equals("./WEB-INF/resin-web.xml"))
528: return;
529:
530: super .removeExpandFile(path, relPath);
531: }
532:
533: public long getLifetimeConnectionCount() {
534: synchronized (_statisticsLock) {
535: return _lifetimeConnectionCount;
536: }
537: }
538:
539: public long getLifetimeConnectionTime() {
540: synchronized (_statisticsLock) {
541: return _lifetimeConnectionTime;
542: }
543: }
544:
545: public long getLifetimeReadBytes() {
546: synchronized (_statisticsLock) {
547: return _lifetimeReadBytes;
548: }
549: }
550:
551: public long getLifetimeWriteBytes() {
552: synchronized (_statisticsLock) {
553: return _lifetimeWriteBytes;
554: }
555: }
556:
557: public long getLifetimeClientDisconnectCount() {
558: synchronized (_statisticsLock) {
559: return _lifetimeClientDisconnectCount;
560: }
561: }
562:
563: /**
564: * Update statistics with the results of one request.
565: *
566: * @param milliseconds the number of millesconds for the request
567: * @param readBytes the number of bytes read
568: * @param writeBytes the number of bytes written
569: * @param isClientDisconnect true if the request ended with a client DisconnectException
570: */
571: public void updateStatistics(long milliseconds, int readBytes,
572: int writeBytes, boolean isClientDisconnect) {
573: synchronized (_statisticsLock) {
574: _lifetimeConnectionCount++;
575: _lifetimeConnectionTime += milliseconds;
576: _lifetimeReadBytes += readBytes;
577: _lifetimeWriteBytes += writeBytes;
578: if (isClientDisconnect)
579: _lifetimeClientDisconnectCount++;
580: }
581: }
582:
583: @Override
584: protected Logger getLog() {
585: return log;
586: }
587:
588: /**
589: * Returns a printable view.
590: */
591: public String toString() {
592: if (com.caucho.util.Alarm.isTest())
593: return "WebAppController" + "[" + getId() + "]";
594: else
595: return "WebAppController$" + System.identityHashCode(this )
596: + "[" + getId() + "]";
597: }
598:
599: /**
600: * EL variables for the app.
601: */
602: public class Var {
603: public String getUrl() {
604: return WebAppController.this .getURL();
605: }
606:
607: public String getId() {
608: String id = WebAppController.this .getId();
609:
610: if (id != null)
611: return id;
612: else
613: return WebAppController.this .getContextPath();
614: }
615:
616: public String getName() {
617: if (getWarName() != null)
618: return getWarName();
619: else
620: return getId();
621: }
622:
623: public Path getAppDir() {
624: return WebAppController.this .getRootDirectory();
625: }
626:
627: public Path getDocDir() {
628: return WebAppController.this .getRootDirectory();
629: }
630:
631: public Path getRoot() {
632: return WebAppController.this .getRootDirectory();
633: }
634:
635: public Path getRootDir() {
636: return WebAppController.this .getRootDirectory();
637: }
638:
639: public String getContextPath() {
640: return WebAppController.this .getContextPath();
641: }
642:
643: public ArrayList<String> getRegexp() {
644: return _regexpValues;
645: }
646:
647: public String toString() {
648: return "WebApp[" + getURL() + "]";
649: }
650: }
651: }
|