001: /*
002: * This file is part of DrFTPD, Distributed FTP Daemon.
003: *
004: * DrFTPD is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * DrFTPD is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with DrFTPD; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018: package org.drftpd.sections.conf;
019:
020: import java.io.FileNotFoundException;
021: import java.text.SimpleDateFormat;
022: import java.util.Calendar;
023: import java.util.Collection;
024: import java.util.Date;
025: import java.util.GregorianCalendar;
026: import java.util.Locale;
027: import java.util.Properties;
028: import java.util.TimeZone;
029: import java.util.TimerTask;
030:
031: import org.apache.log4j.Logger;
032: import org.drftpd.GlobalContext;
033: import org.drftpd.PropertyHelper;
034: import org.drftpd.remotefile.FileUtils;
035: import org.drftpd.remotefile.LinkedRemoteFile;
036: import org.drftpd.remotefile.LinkedRemoteFileInterface;
037: import org.drftpd.remotefile.StaticRemoteFile;
038: import org.drftpd.sections.SectionInterface;
039:
040: /**
041: * @author mog
042: * @version $Id: DatedSection.java 1185 2005-05-01 16:43:54Z zubov $
043: */
044: public class DatedSection implements SectionInterface {
045: // The code assumes that the following constants are in a increasing
046: // sequence.
047: static final int TOP_OF_TROUBLE = -1;
048: static final int TOP_OF_MINUTE = 0;
049: static final int TOP_OF_HOUR = 1;
050: static final int HALF_DAY = 2;
051: static final int TOP_OF_DAY = 3;
052: static final int TOP_OF_WEEK = 4;
053: static final int TOP_OF_MONTH = 5;
054:
055: // The gmtTimeZone is used only in computeCheckPeriod() method.
056: static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
057: private static final Logger logger = Logger
058: .getLogger(DatedSection.class);
059: private String _basePath;
060: private SimpleDateFormat _dateFormat;
061: private SectionManager _mgr;
062: private String _name;
063: private String _now;
064: private RollingCalendar rc = new RollingCalendar();
065:
066: public DatedSection(SectionManager mgr, int i, Properties p) {
067: _mgr = mgr;
068: _name = PropertyHelper.getProperty(p, i + ".name");
069: _basePath = PropertyHelper.getProperty(p, i + ".path");
070: _now = PropertyHelper.getProperty(p, i + ".now");
071:
072: if (!_basePath.endsWith("/")) {
073: _basePath += "/";
074: }
075:
076: _dateFormat = new SimpleDateFormat(PropertyHelper.getProperty(
077: p, i + ".dated"), Locale.getDefault());
078:
079: //rollingcalendar...
080: int type = computeCheckPeriod();
081: printPeriodicity(type);
082: rc.setType(type);
083:
084: //end rollingcalendar...
085: logger.debug("Rolling at " + rc.getNextCheckDate(new Date()));
086: getGlobalContext().getTimer().schedule(new TimerTask() {
087: public void run() {
088: try {
089: getFile();
090: } catch (Throwable t) {
091: logger
092: .error(
093: "Catching Throwable in DatedSection TimerTask",
094: t);
095: }
096: }
097: }, rc.getNextCheckDate(new Date()));
098: getFile();
099: }
100:
101: private GlobalContext getGlobalContext() {
102: return _mgr.getGlobalContext();
103: }
104:
105: public LinkedRemoteFileInterface getBaseFile() {
106: try {
107: return _mgr.getConnectionManager().getGlobalContext()
108: .getRoot().lookupFile(_basePath);
109: } catch (FileNotFoundException e) {
110: return _mgr.getConnectionManager().getGlobalContext()
111: .getRoot().createDirectories(_basePath);
112: }
113: }
114:
115: public LinkedRemoteFileInterface getFile() {
116: String dateDirPath = _dateFormat.format(new Date());
117: //System.out.println(new Date());
118: //System.out.println(dateDirPath);
119: //System.out.println(_dateFormat.getCalendar());
120: //System.out.println(_dateFormat.getTimeZone());
121: _dateFormat.setTimeZone(TimeZone.getDefault());
122: //System.out.println(_dateFormat.getTimeZone());
123:
124: try {
125: return getBaseFile().lookupFile(dateDirPath);
126: } catch (FileNotFoundException e) {
127: LinkedRemoteFileInterface base = getBaseFile();
128: LinkedRemoteFile dateDir = base
129: .createDirectories(dateDirPath);
130:
131: try {
132: base = base.getParentFile();
133: } catch (FileNotFoundException e1) {
134: }
135:
136: try {
137: base.getFile(getName() + _now).delete();
138: } catch (FileNotFoundException e2) {
139: }
140:
141: base.addFile(new StaticRemoteFile(getName() + _now, null,
142: dateDir.getPath()));
143: logger.info("Created " + dateDir.getPath()
144: + " and created symlink");
145:
146: return dateDir;
147: }
148: }
149:
150: public Collection getFiles() {
151: return getBaseFile().getDirectories();
152: }
153:
154: public LinkedRemoteFileInterface getFirstDirInSection(
155: LinkedRemoteFileInterface dir) {
156: try {
157: return FileUtils.getSubdirOfDirectory(getFile(), dir);
158: } catch (FileNotFoundException e) {
159: return dir;
160: }
161: }
162:
163: public String getName() {
164: return _name;
165: }
166:
167: public String getPath() {
168: return getFile().getPath();
169: }
170:
171: // This method computes the roll over period by looping over the
172: // periods, starting with the shortest, and stopping when the r0 is
173: // different from from r1, where r0 is the epoch formatted according
174: // the datePattern (supplied by the user) and r1 is the
175: // epoch+nextMillis(i) formatted according to datePattern. All date
176: // formatting is done in GMT and not local format because the test
177: // logic is based on comparisons relative to 1970-01-01 00:00:00
178: // GMT (the epoch).
179: int computeCheckPeriod() {
180: RollingCalendar rollingCalendar = new RollingCalendar(
181: gmtTimeZone, Locale.ENGLISH);
182:
183: // set sate to 1970-01-01 00:00:00 GMT
184: Date epoch = new Date(0);
185: /*if(datePattern != null) */{
186: for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
187: SimpleDateFormat simpleDateFormat = (SimpleDateFormat) _dateFormat
188: .clone();
189: simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT
190:
191: String r0 = simpleDateFormat.format(epoch);
192: rollingCalendar.setType(i);
193:
194: Date next = new Date(rollingCalendar
195: .getNextCheckMillis(epoch));
196: String r1 = simpleDateFormat.format(next);
197:
198: //System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
199: if ((r0 != null) && (r1 != null) && !r0.equals(r1)) {
200: return i;
201: }
202: }
203: }
204:
205: return TOP_OF_TROUBLE; // Deliberately head for trouble...
206: }
207:
208: void printPeriodicity(int type) {
209: switch (type) {
210: case TOP_OF_MINUTE:
211: logger.debug("DatedSection [" + _name
212: + "] to be rolled every minute.");
213:
214: break;
215:
216: case TOP_OF_HOUR:
217: logger.debug("DatedSection [" + _name
218: + "] to be rolled on top of every hour.");
219:
220: break;
221:
222: case HALF_DAY:
223: logger.debug("DatedSection [" + _name
224: + "] to be rolled at midday and midnight.");
225:
226: break;
227:
228: case TOP_OF_DAY:
229: logger.debug("DatedSection [" + _name
230: + "] to be rolled at midnight.");
231:
232: break;
233:
234: case TOP_OF_WEEK:
235: logger.debug("DatedSection [" + _name
236: + "] to be rolled at start of week.");
237:
238: break;
239:
240: case TOP_OF_MONTH:
241: logger.debug("DatedSection [" + _name
242: + "] to be rolled at start of every month.");
243:
244: break;
245:
246: default:
247: logger.warn("Unknown periodicity for DatedSection ["
248: + _name + "].");
249: }
250: }
251:
252: public String getBasePath() {
253: return _basePath;
254: }
255: }
256:
257: /**
258: * RollingCalendar is a helper class to DailyRollingFileAppender.
259: * Given a periodicity type and the current time, it computes the
260: * start of the next interval.
261: * */
262: class RollingCalendar extends GregorianCalendar {
263: int _type = DatedSection.TOP_OF_TROUBLE;
264:
265: RollingCalendar() {
266: super ();
267: }
268:
269: RollingCalendar(TimeZone tz, Locale locale) {
270: super (tz, locale);
271: }
272:
273: void setType(int type) {
274: _type = type;
275: }
276:
277: public long getNextCheckMillis(Date now) {
278: return getNextCheckDate(now).getTime();
279: }
280:
281: public Date getNextCheckDate(Date now) {
282: this .setTime(now);
283:
284: switch (_type) {
285: case DatedSection.TOP_OF_MINUTE:
286: this .set(Calendar.SECOND, 0);
287: this .set(Calendar.MILLISECOND, 0);
288: this .add(Calendar.MINUTE, 1);
289:
290: break;
291:
292: case DatedSection.TOP_OF_HOUR:
293: this .set(Calendar.MINUTE, 0);
294: this .set(Calendar.SECOND, 0);
295: this .set(Calendar.MILLISECOND, 0);
296: this .add(Calendar.HOUR_OF_DAY, 1);
297:
298: break;
299:
300: case DatedSection.HALF_DAY:
301: this .set(Calendar.MINUTE, 0);
302: this .set(Calendar.SECOND, 0);
303: this .set(Calendar.MILLISECOND, 0);
304:
305: int hour = get(Calendar.HOUR_OF_DAY);
306:
307: if (hour < 12) {
308: this .set(Calendar.HOUR_OF_DAY, 12);
309: } else {
310: this .set(Calendar.HOUR_OF_DAY, 0);
311: this .add(Calendar.DAY_OF_MONTH, 1);
312: }
313:
314: break;
315:
316: case DatedSection.TOP_OF_DAY:
317: this .set(Calendar.HOUR_OF_DAY, 0);
318: this .set(Calendar.MINUTE, 0);
319: this .set(Calendar.SECOND, 0);
320: this .set(Calendar.MILLISECOND, 0);
321: this .add(Calendar.DATE, 1);
322:
323: break;
324:
325: case DatedSection.TOP_OF_WEEK:
326: this .set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
327: this .set(Calendar.HOUR_OF_DAY, 0);
328: this .set(Calendar.SECOND, 0);
329: this .set(Calendar.MILLISECOND, 0);
330: this .add(Calendar.WEEK_OF_YEAR, 1);
331:
332: break;
333:
334: case DatedSection.TOP_OF_MONTH:
335: this .set(Calendar.DATE, 1);
336: this .set(Calendar.HOUR_OF_DAY, 0);
337: this .set(Calendar.SECOND, 0);
338: this .set(Calendar.MILLISECOND, 0);
339: this .add(Calendar.MONTH, 1);
340:
341: break;
342:
343: default:
344: throw new IllegalStateException("Unknown periodicity type.");
345: }
346:
347: return getTime();
348: }
349: }
|