001: /**
002: * EasyBeans
003: * Copyright (C) 2006-2007 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: ContainersMonitor.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.server;
025:
026: import static org.ow2.easybeans.util.url.URLUtils.urlToFile;
027:
028: import java.io.File;
029: import java.net.URL;
030: import java.util.List;
031: import java.util.Map;
032: import java.util.WeakHashMap;
033:
034: import org.ow2.easybeans.api.EZBContainer;
035: import org.ow2.easybeans.api.EZBContainerException;
036: import org.ow2.util.ee.deploy.api.archive.ArchiveException;
037: import org.ow2.util.ee.deploy.api.archive.IArchive;
038: import org.ow2.util.ee.deploy.impl.archive.ArchiveManager;
039: import org.ow2.util.log.Log;
040: import org.ow2.util.log.LogFactory;
041:
042: /**
043: * This class monitors the archives managed by containers and reload them if the
044: * archive is changed.
045: * @author Florent Benoit
046: */
047: public class ContainersMonitor extends Thread {
048:
049: /**
050: * Sleep time for the thread of the cleaner (5s).
051: */
052: private static final int SLEEP_TIME = 5000;
053:
054: /**
055: * Logger.
056: */
057: private Log logger = LogFactory.getLog(ContainersMonitor.class);
058:
059: /**
060: * Map between container and the last updated file.
061: */
062: private Map<EZBContainer, Long> modifiedFiles = null;
063:
064: /**
065: * Embedded server which is monitored.
066: */
067: private Embedded embedded = null;
068:
069: /**
070: * Initializing period ?.
071: */
072: private boolean bootInProgress = false;
073:
074: /**
075: * Stop order received ?
076: */
077: private boolean stopped = false;
078:
079: /**
080: * Builds a new monitor by initializing lists.
081: * @param embedded the embedded server which is monitored.
082: */
083: public ContainersMonitor(final Embedded embedded) {
084: this .embedded = embedded;
085: this .modifiedFiles = new WeakHashMap<EZBContainer, Long>();
086: }
087:
088: /**
089: * Init containers (call at startup).
090: */
091: public void init() {
092: // Start the boot process.
093: bootInProgress = true;
094:
095: // Initialize containers
096: scanNewContainers();
097:
098: // No more in the boot process.
099: bootInProgress = false;
100: }
101:
102: /**
103: * Start the thread of this class It will clean all the work entries.
104: */
105: @Override
106: public void run() {
107:
108: for (;;) {
109: // Stop the thread
110: if (stopped) {
111: return;
112: }
113:
114: // Check existing container is not modified ?
115: for (EZBContainer container : embedded.getContainers()
116: .values()) {
117: if (container.isAvailable()) {
118: checkContainer(container);
119: }
120: }
121:
122: // Check new containers to start
123: scanNewContainers();
124:
125: try {
126: Thread.sleep(SLEEP_TIME);
127: } catch (InterruptedException e) {
128: throw new RuntimeException("Thread fail to sleep");
129: }
130: }
131: }
132:
133: /**
134: * Scan all files present in the ejb3 directory and create container for
135: * each one.
136: */
137: private void scanNewContainers() {
138:
139: // Get the list of deploy directories
140: List<File> deployDirectories = embedded.getServerConfig()
141: .getDeployDirectories();
142:
143: for (File deployDirectory : deployDirectories) {
144: // get files
145: File[] files = deployDirectory.listFiles();
146:
147: // next directory if there are no files to scan.
148: if (files == null) {
149: continue;
150: }
151:
152: // analyze each file.
153: for (File f : files) {
154: if (f.getName().toLowerCase().endsWith(".jar")) {
155: IArchive archive = ArchiveManager.getInstance()
156: .getArchive(f);
157:
158: // check that no container already exist for this archive
159: boolean alreadyExist = false;
160: for (EZBContainer container : embedded
161: .getContainers().values()) {
162: if (container.getArchive().equals(archive)) {
163: alreadyExist = true;
164: }
165:
166: }
167: if (!alreadyExist) {
168: if (!bootInProgress) {
169: // wait that files are copied before creating/starting
170: // the container
171: try {
172: Thread.sleep(SLEEP_TIME);
173: } catch (InterruptedException e) {
174: throw new RuntimeException(
175: "Thread fail to sleep");
176: }
177: }
178: logger.info(
179: "Creating container for archive {0}.",
180: f);
181:
182: EZBContainer container = embedded
183: .createContainer(archive);
184: try {
185: container.start();
186: } catch (EZBContainerException e) {
187: logger.error("Cannot start container {0}",
188: container.getName(), e);
189: }
190: }
191: }
192: }
193: }
194: }
195:
196: /**
197: * Check a container (and its archive) and see if there is a need to reload
198: * the container.
199: * @param container the container to monitor.
200: */
201: protected void checkContainer(final EZBContainer container) {
202: // get lastmodified for this container (any ?)
203: long previousLastModified = 0;
204: Long l = modifiedFiles.get(container);
205: if (l != null) {
206: previousLastModified = l.longValue();
207: }
208:
209: // get archive
210: IArchive archive = container.getArchive();
211:
212: // Get URL
213: URL url = null;
214: try {
215: url = archive.getURL();
216: } catch (ArchiveException e1) {
217: logger.warn("Cannot get URL on the container {0}", archive
218: .getName());
219: return;
220: }
221: File file = urlToFile(url);
222: // No file archive, abort.
223: if (!file.exists()) {
224: return;
225: }
226:
227: long updatedModified = getLastModified(file);
228: modifiedFiles.put(container, Long.valueOf(updatedModified));
229:
230: // first check. nothing to do
231: if (previousLastModified == 0) {
232: return;
233: }
234: // container was modified, need to relaunch it
235: if (updatedModified > previousLastModified) {
236: logger
237: .info(
238: "Container with archive {0} was modified. Reloading...",
239: archive.getName());
240: container.stop();
241: try {
242: container.start();
243: } catch (EZBContainerException e) {
244: e.printStackTrace();
245: }
246: }
247:
248: }
249:
250: /**
251: * Gets the last modified attribute of a given archive.<br> If it is a
252: * directory, returns the last modified file of the archive.
253: * @param archive the archive to monitor.
254: * @return the last modified version of the given archive.
255: */
256: protected long getLastModified(final File archive) {
257: if (archive.isFile()) {
258: return archive.lastModified();
259: }
260: // else
261: File[] files = archive.listFiles();
262: long last = 0;
263: if (files != null) {
264: for (File f : files) {
265: last = Math.max(last, getLastModified(f));
266: }
267: }
268: return last;
269: }
270:
271: /**
272: * Receives a stop order.
273: */
274: public void stopOrder() {
275: this .stopped = true;
276: }
277:
278: /**
279: * Gets the embedded object.
280: * @return embedded object
281: */
282: public Embedded getEmbedded() {
283: return embedded;
284: }
285: }
|