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:
045: import javax.servlet.jsp.el.ELException;
046: import java.io.IOException;
047: import java.util.*;
048: import java.util.logging.Logger;
049: import java.util.regex.Matcher;
050: import java.util.regex.Pattern;
051:
052: /**
053: * A configuration entry for a versioning web-app.
054: */
055: public class WebAppVersioningController extends WebAppController {
056: private static final L10N L = new L10N(
057: WebAppVersioningController.class);
058: private static final Logger log = Logger
059: .getLogger(WebAppController.class.getName());
060:
061: private static final long EXPIRE_PERIOD = 3600 * 1000L;
062:
063: private long _versionRolloverTime = EXPIRE_PERIOD;
064:
065: private ArrayList<WebAppController> _controllerList = new ArrayList<WebAppController>();
066:
067: private final WebAppExpandDeployGenerator _generator;
068:
069: private long _restartTime;
070:
071: private WebAppController _primaryController;
072: private boolean _isModified = true;
073:
074: public WebAppVersioningController(String contextPath,
075: WebAppExpandDeployGenerator generator,
076: WebAppContainer container) {
077: super (contextPath, contextPath, null, container);
078:
079: _generator = generator;
080: }
081:
082: /**
083: * Merges two entries.
084: */
085: /*
086: protected WebAppController merge(WebAppController newController)
087: {
088: if (getConfig() != null && getConfig().getURLRegexp() != null)
089: return newController;
090: else if (newController.getConfig() != null &&
091: newController.getConfig().getURLRegexp() != null)
092: return this;
093: else {
094: Thread thread = Thread.currentThread();
095: ClassLoader oldLoader = thread.getContextClassLoader();
096:
097: try {
098: thread.setContextClassLoader(getParentClassLoader());
099:
100: // The contextPath comes from current web-app
101: WebAppController mergedController
102: = new WebAppController(getContextPath(),
103: getRootDirectory(),
104: _container);
105:
106: // server/1h1{2,3}
107: // This controller overrides configuration from the new controller
108: mergedController.mergeController(this);
109: mergedController.mergeController(newController);
110:
111: return mergedController;
112: } finally {
113: thread.setContextClassLoader(oldLoader);
114: }
115: }
116: }
117: */
118:
119: void setModified(boolean isModified) {
120: _isModified = isModified;
121: }
122:
123: /**
124: * Returns the instance for a top-level request
125: * @return the request object or null for none.
126: */
127: @Override
128: public WebApp request() {
129: if (_isModified)
130: updateVersion();
131:
132: WebAppController controller = _primaryController;
133:
134: if (controller != null)
135: return controller.request();
136: else
137: return null;
138: }
139:
140: /**
141: * Returns the instance for a subrequest.
142: *
143: * @return the request object or null for none.
144: */
145: @Override
146: public WebApp subrequest() {
147: if (_isModified)
148: updateVersion();
149:
150: WebAppController controller = _primaryController;
151:
152: if (controller != null)
153: return controller.request();
154: else
155: return null;
156: }
157:
158: /**
159: * Starts the entry.
160: */
161: @Override
162: protected WebApp startImpl() {
163: if (_isModified)
164: updateVersion();
165:
166: WebAppController controller = _primaryController;
167:
168: if (controller != null)
169: return controller.request();
170: else
171: return null;
172: }
173:
174: /**
175: * Initialize the controller.
176: */
177: protected void initBegin() {
178: /*
179: super.initBegin();
180: */
181: }
182:
183: private void updateVersion() {
184: synchronized (this ) {
185: if (!_isModified)
186: return;
187: _isModified = false;
188:
189: _controllerList = new ArrayList<WebAppController>();
190:
191: ArrayList<String> versionNames = _generator
192: .getVersionNames(getId());
193:
194: if (versionNames != null) {
195: Collections.sort(versionNames,
196: new VersionNameComparator());
197:
198: for (int i = 0; i < versionNames.size() && i < 2; i++) {
199: String versionName = versionNames.get(i);
200:
201: WebAppController newController = _container
202: .getWebAppGenerator().findController(
203: versionName);
204:
205: _controllerList.add(newController);
206: }
207:
208: //Collections.sort(_controllerList, new VersionComparator());
209:
210: _primaryController = _controllerList.get(0);
211:
212: if (_restartTime > 0 && _controllerList.size() > 1) {
213: long expireTime = Alarm.getCurrentTime()
214: + _versionRolloverTime;
215:
216: _primaryController.setOldWebApp(_controllerList
217: .get(1), expireTime);
218:
219: }
220:
221: _restartTime = Alarm.getCurrentTime();
222: }
223: }
224: }
225:
226: /**
227: * Returns a printable view.
228: */
229: public String toString() {
230: return "WebAppVersioningController" + "[" + getId() + "]";
231: }
232:
233: static class VersionNameComparator implements Comparator<String> {
234: public int compare(String versionA, String versionB) {
235: /*
236: String versionA = a.getVersion();
237: String versionB = b.getVersion();
238: */
239:
240: int lengthA = versionA.length();
241: int lengthB = versionB.length();
242:
243: int indexA = 0;
244: int indexB = 0;
245:
246: while (indexA < lengthA && indexB < lengthB) {
247: int valueA = 0;
248: int valueB = 0;
249: char chA;
250: char chB;
251:
252: for (; indexA < lengthA
253: && '0' <= (chA = versionA.charAt(indexA))
254: && chA <= '9'; indexA++) {
255: valueA = 10 * valueA + chA - '0';
256: }
257:
258: for (; indexB < lengthB
259: && '0' <= (chB = versionB.charAt(indexB))
260: && chB <= '9'; indexB++) {
261: valueB = 10 * valueB + chB - '0';
262: }
263:
264: if (valueA < valueB)
265: return 1;
266: else if (valueB < valueA)
267: return -1;
268:
269: while (indexA < lengthA
270: && indexB < lengthB
271: && !('0' <= (chA = versionA.charAt(indexA)) && chA <= '9')
272: && !('0' <= (chB = versionB.charAt(indexB)) && chB <= '9')) {
273:
274: if (chA < chB)
275: return 1;
276: else if (chB < chA)
277: return -1;
278:
279: indexA++;
280: indexB++;
281: }
282:
283: if (indexA < lengthA
284: && !('0' <= (chA = versionA.charAt(indexA)) && chA <= '9'))
285: return 1;
286: else if (indexB < lengthB
287: && !('0' <= (chB = versionB.charAt(indexB)) && chB <= '9'))
288: return -1;
289: }
290:
291: if (indexA != lengthA)
292: return 1;
293: else if (indexB != lengthB)
294: return -1;
295: else
296: return 0;
297: }
298: }
299: }
|