001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.cluster.deploy;
018:
019: import java.io.File;
020: import java.util.HashMap;
021: import java.util.Map;
022: import java.util.Iterator;
023:
024: /**
025: * <p>The <b>WarWatcher</b> watches the deployDir for changes made to
026: * the directory (adding new WAR files->deploy or remove WAR files->undeploy)
027: * And notifies a listener of the changes made</p>
028: *
029: * @author Filip Hanik
030: * @version 1.0
031: */
032:
033: public class WarWatcher implements Runnable {
034:
035: /*--Static Variables----------------------------------------*/
036: public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
037: .getLog(WarWatcher.class);
038:
039: /*--Instance Variables--------------------------------------*/
040: /**
041: * Directory to watch for war files
042: */
043: protected File deployDir = null;
044:
045: /**
046: * Parent to be notified of changes
047: */
048: protected FileChangeListener listener = null;
049:
050: /**
051: *
052: * Check interval
053: */
054: protected long interval = 5000; //5 seconds
055:
056: /**
057: * Run status
058: */
059: protected boolean alive = true;
060:
061: /**
062: * Currently deployed files
063: */
064: protected Map currentStatus = new HashMap();
065:
066: /*--Constructor---------------------------------------------*/
067:
068: public WarWatcher(FileChangeListener listener, File deployDir,
069: long interval) {
070: this .listener = listener;
071: this .deployDir = deployDir;
072: this .interval = interval;
073: }
074:
075: /*--Logic---------------------------------------------------*/
076:
077: public void run() {
078: while (alive) {
079: try {
080: File[] list = deployDir.listFiles(new WarFilter());
081: if (list == null)
082: list = new File[0];
083: //first make sure all the files are listed in our current status
084: for (int i = 0; i < list.length; i++) {
085: addWarInfo(list[i]);
086: }//for
087:
088: //check all the status codes and update the FarmDeployer
089: for (Iterator i = currentStatus.entrySet().iterator(); i
090: .hasNext();) {
091: Map.Entry entry = (Map.Entry) i.next();
092: WarInfo info = (WarInfo) entry.getValue();
093: int check = info.check();
094: if (check == 1) {
095: listener.fileModified(info.getWar());
096: } else if (check == -1) {
097: listener.fileRemoved(info.getWar());
098: //no need to keep in memory
099: currentStatus.remove(info.getWar());
100: }//end if
101: }//for
102:
103: //sleep for the set interval
104: Thread.sleep(interval);
105: } catch (Exception x) {
106: log
107: .error(
108: "Unable to watch for WAR deployments in cluster.",
109: x);
110: }
111: }//while
112: }//run
113:
114: protected void addWarInfo(File f) {
115: WarInfo info = (WarInfo) currentStatus.get(f.getAbsolutePath());
116: if (info == null) {
117: info = new WarInfo(f);
118: info.setLastState(-1); //assume file is non existent
119: currentStatus.put(f.getAbsolutePath(), info);
120: }
121: }
122:
123: public void stop() {
124: alive = false;
125: currentStatus.clear();
126: listener = null;
127: }
128:
129: /*--Inner classes-------------------------------------------*/
130:
131: /**
132: * File name filter for war files
133: */
134: protected class WarFilter implements java.io.FilenameFilter {
135: public boolean accept(File path, String name) {
136: if (name == null)
137: return false;
138: return name.endsWith(".war");
139: }
140: }
141:
142: /**
143: * File information on existing WAR files
144: */
145: protected class WarInfo {
146: protected File war = null;
147: protected long lastChecked = 0;
148: protected long lastState = 0;
149:
150: public WarInfo(File war) {
151: this .war = war;
152: this .lastChecked = war.lastModified();
153: if (!war.exists())
154: lastState = -1;
155: }
156:
157: public boolean modified() {
158: return war.exists() && war.lastModified() > lastChecked;
159: }
160:
161: public boolean exists() {
162: return war.exists();
163: }
164:
165: /**
166: * Returns
167: * 1 if the file has been added/modified,
168: * 0 if the file is unchanged and
169: * -1 if the file has been removed
170: * @return int 1=file added; 0=unchanged; -1=file removed
171: */
172: public int check() {
173: //file unchanged by default
174: int result = 0;
175:
176: if (modified()) {
177: //file has changed - timestamp
178: result = 1;
179: lastState = result;
180: } else if ((!exists()) && (!(lastState == -1))) {
181: //file was removed
182: result = -1;
183: lastState = result;
184: } else if ((lastState == -1) && exists()) {
185: //file was added
186: result = 1;
187: lastState = result;
188: }
189: this .lastChecked = System.currentTimeMillis();
190: return result;
191: }
192:
193: public File getWar() {
194: return war;
195: }
196:
197: public int hashCode() {
198: return war.getAbsolutePath().hashCode();
199: }
200:
201: public boolean equals(Object other) {
202: if (other instanceof WarInfo) {
203: WarInfo wo = (WarInfo) other;
204: return wo.getWar().equals(getWar());
205: } else {
206: return false;
207: }
208: }
209:
210: protected void setLastState(int lastState) {
211: this.lastState = lastState;
212: }
213:
214: }
215:
216: }
|