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