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.deploy;
031:
032: import com.caucho.lifecycle.Lifecycle;
033: import com.caucho.loader.Environment;
034: import com.caucho.make.CachedDependency;
035: import com.caucho.util.L10N;
036: import com.caucho.vfs.Dependency;
037:
038: import javax.annotation.PostConstruct;
039: import java.util.*;
040: import java.util.logging.Logger;
041:
042: /**
043: * A container of deploy objects.
044: */
045: public class DeployContainer<C extends DeployController> extends
046: CachedDependency implements Dependency {
047: private static final L10N L = new L10N(DeployContainer.class);
048: private static final Logger log = Logger
049: .getLogger(DeployContainer.class.getName());
050:
051: private final DeployListGenerator<C> _deployListGenerator = new DeployListGenerator<C>(
052: this );
053:
054: private final ArrayList<C> _controllerList = new ArrayList<C>();
055:
056: private final Lifecycle _lifecycle = new Lifecycle();
057:
058: /**
059: * Creates the deploy container.
060: */
061: public DeployContainer() {
062: setCheckInterval(Environment.getDependencyCheckInterval());
063: }
064:
065: /**
066: * Adds a deploy generator.
067: */
068: public void add(DeployGenerator<C> generator) {
069: Set<String> names = new TreeSet<String>();
070: generator.fillDeployedKeys(names);
071:
072: _deployListGenerator.add(generator);
073:
074: if (_lifecycle.isActive())
075: update(names);
076: }
077:
078: /**
079: * Removes a deploy.
080: */
081: public void remove(DeployGenerator<C> generator) {
082: Set<String> names = new TreeSet<String>();
083: generator.fillDeployedKeys(names);
084:
085: _deployListGenerator.remove(generator);
086:
087: if (_lifecycle.isActive())
088: update(names);
089: }
090:
091: /**
092: * Returns true if the deployment has modified.
093: */
094: public boolean isModifiedImpl() {
095: return _deployListGenerator.isModified();
096: }
097:
098: /**
099: * Logs the reason for modification.
100: */
101: public boolean logModified(Logger log) {
102: return _deployListGenerator.logModified(log);
103: }
104:
105: /**
106: * Forces updates.
107: */
108: public void update() {
109: _deployListGenerator.update();
110: }
111:
112: /**
113: * Initialize the container.
114: */
115: @PostConstruct
116: public void init() {
117: if (!_lifecycle.toInit())
118: return;
119: }
120:
121: /**
122: * Start the container.
123: */
124: public void start() {
125: init();
126:
127: if (!_lifecycle.toActive())
128: return;
129:
130: _deployListGenerator.start();
131:
132: HashSet<String> keys = new LinkedHashSet<String>();
133:
134: _deployListGenerator.fillDeployedKeys(keys);
135: for (String key : keys) {
136: startImpl(key);
137: }
138:
139: ArrayList<C> controllerList;
140:
141: synchronized (_controllerList) {
142: controllerList = new ArrayList<C>(_controllerList);
143:
144: Collections.sort(controllerList,
145: new StartupPriorityComparator());
146: }
147:
148: for (int i = 0; i < controllerList.size(); i++) {
149: C controller = controllerList.get(i);
150:
151: controller.startOnInit();
152: }
153: }
154:
155: /**
156: * Returns the matching entry.
157: */
158: public C findController(String name) {
159: C controller = findDeployedController(name);
160:
161: if (controller != null)
162: return controller;
163:
164: controller = generateController(name);
165:
166: if (controller == null)
167: return null;
168: // server/10tm
169: else if (controller.isNameMatch(name)) {
170: return controller;
171: } else {
172: return null;
173: }
174: }
175:
176: /**
177: * Returns the deployed entries.
178: */
179: public ArrayList<C> getControllers() {
180: ArrayList<C> list = new ArrayList<C>();
181:
182: synchronized (_controllerList) {
183: list.addAll(_controllerList);
184: }
185:
186: return list;
187: }
188:
189: /**
190: * Updates all the names.
191: */
192: private void update(Set<String> names) {
193: Iterator<String> iter = names.iterator();
194: while (iter.hasNext()) {
195: String name = iter.next();
196:
197: update(name);
198: }
199: }
200:
201: /**
202: * Callback from the DeployGenerator when the deployment changes.
203: * <code>update</code> is only called when a deployment is added
204: * or removed, e.g. with a new .war file.
205: *
206: * The entry handles its own internal changes, e.g. a modification to
207: * a web.xml file.
208: */
209: public C update(String name) {
210: C newController = updateImpl(name);
211:
212: if (_lifecycle.isActive() && newController != null)
213: newController.startOnInit();
214:
215: return newController;
216: }
217:
218: /**
219: * Callback from the DeployGenerator when the deployment changes.
220: * <code>update</code> is only called when a deployment is added
221: * or removed, e.g. with a new .war file.
222: *
223: * The entry handles its own internal changes, e.g. a modification to
224: * a web.xml file.
225: */
226: C updateImpl(String name) {
227: C oldController = null;
228:
229: synchronized (_controllerList) {
230: oldController = findDeployedController(name);
231:
232: if (oldController != null)
233: _controllerList.remove(oldController);
234: }
235:
236: if (oldController != null)
237: oldController.destroy();
238:
239: // destroy must be before generate because of JMX unregistration
240:
241: C newController = generateController(name);
242:
243: return newController;
244: }
245:
246: /**
247: * Starts a particular controller.
248: *
249: * @param name the domain-specified name matching the controller, e.g. the
250: * hostname or the context-path.
251: */
252: private C startImpl(String name) {
253: C oldController = null;
254:
255: synchronized (_controllerList) {
256: oldController = findDeployedController(name);
257: }
258:
259: if (oldController != null)
260: return oldController;
261:
262: return generateController(name);
263: }
264:
265: /**
266: * Called to explicitly remove an entry from the cache.
267: */
268: public void remove(String name) {
269: C oldController = null;
270:
271: synchronized (_controllerList) {
272: oldController = findDeployedController(name);
273:
274: if (oldController != null)
275: _controllerList.remove(oldController);
276: }
277:
278: if (oldController != null)
279: oldController.destroy();
280: }
281:
282: /**
283: * Generates the controller.
284: */
285: private C generateController(String name) {
286: if (!_lifecycle.isActive())
287: return null;
288:
289: C newController = _deployListGenerator.generateController(name);
290:
291: // server/1h00,13g4
292: // generated controller might match the name, e.g.
293: // when webapps deploy has an overriding explicit <web-app>
294: if (newController == null)
295: return null;
296:
297: // the new entry might already be generated by another thread
298: synchronized (_controllerList) {
299: C controller = findDeployedController(newController.getId());
300:
301: if (controller != null)
302: return controller;
303:
304: _controllerList.add(newController);
305: }
306:
307: init(newController);
308:
309: return newController;
310: }
311:
312: private void init(C controller) {
313: Thread thread = Thread.currentThread();
314: ClassLoader oldLoader = thread.getContextClassLoader();
315:
316: try {
317: thread.setContextClassLoader(controller
318: .getParentClassLoader());
319:
320: controller.init();
321: } finally {
322: thread.setContextClassLoader(oldLoader);
323: }
324: }
325:
326: /**
327: * Returns an already deployed entry.
328: */
329: private C findDeployedController(String name) {
330: synchronized (_controllerList) {
331: for (int i = 0; i < _controllerList.size(); i++) {
332: C controller = _controllerList.get(i);
333:
334: if (controller.isNameMatch(name)) {
335: return controller;
336: }
337: }
338: }
339:
340: return null;
341: }
342:
343: /**
344: * Closes the stop.
345: */
346: public void stop() {
347: if (!_lifecycle.toStop())
348: return;
349:
350: ArrayList<C> controllers;
351:
352: synchronized (_controllerList) {
353: controllers = new ArrayList<C>(_controllerList);
354:
355: Collections.sort(controllers,
356: new StartupPriorityComparator());
357: }
358:
359: for (int i = controllers.size() - 1; i >= 0; i--)
360: controllers.get(i).stop();
361: }
362:
363: /**
364: * Closes the deploys.
365: */
366: public void destroy() {
367: stop();
368:
369: if (!_lifecycle.toDestroy())
370: return;
371:
372: _deployListGenerator.destroy();
373:
374: ArrayList<C> controllerList;
375:
376: synchronized (_controllerList) {
377: controllerList = new ArrayList<C>(_controllerList);
378: _controllerList.clear();
379:
380: Collections.sort(controllerList,
381: new StartupPriorityComparator());
382: }
383:
384: for (int i = controllerList.size() - 1; i >= 0; i--) {
385: C controller = controllerList.get(i);
386:
387: controller.destroy();
388: }
389: }
390:
391: public String toString() {
392: return "DeployContainer$" + System.identityHashCode(this )
393: + "[]";
394: }
395:
396: public class StartupPriorityComparator implements Comparator<C> {
397: public int compare(C a, C b) {
398: if (a.getStartupPriority() == b.getStartupPriority())
399: return 0;
400: else if (a.getStartupPriority() < b.getStartupPriority())
401: return -1;
402: else
403: return 1;
404: }
405: }
406: }
|