> getResultDataList() {
208 | return resultDataList;
209 | }
210 |
211 | public Users getUsers() {
212 | return users;
213 | }
214 |
215 | public WirelessNetworkGroup getWirelessNetworkGroup() {
216 | return wirelessNetworkGroup;
217 | }
218 |
219 | public StateQueue getStateQueue() {
220 | return stateQueue;
221 | }
222 |
223 | public LocalHobby getOriginalContent() {
224 | return originalContent;
225 | }
226 |
227 | public void setOriginalContent(LocalHobby originalContent) {
228 | this.originalContent = originalContent;
229 | }
230 |
231 |
232 |
233 | }
234 |
--------------------------------------------------------------------------------
/src/main/java/cn/edu/tju/simulation/logger/CustomDailyRollingFileAppender.java:
--------------------------------------------------------------------------------
1 | package cn.edu.tju.simulation.logger;
2 |
3 | import java.io.File;
4 | import java.io.FilenameFilter;
5 | import java.io.IOException;
6 | import java.io.InterruptedIOException;
7 | import java.io.Serializable;
8 | import java.net.URI;
9 | import java.text.SimpleDateFormat;
10 | import java.util.ArrayList;
11 | import java.util.Calendar;
12 | import java.util.Collections;
13 | import java.util.Date;
14 | import java.util.GregorianCalendar;
15 | import java.util.List;
16 | import java.util.Locale;
17 | import java.util.TimeZone;
18 |
19 | import org.apache.log4j.FileAppender;
20 | import org.apache.log4j.Layout;
21 | import org.apache.log4j.helpers.LogLog;
22 | import org.apache.log4j.spi.LoggingEvent;
23 |
24 | /**
25 | *
26 | * @author Wenkai Li ,School of Computer Science and Technology ,Tianjin University
27 | *
28 | */
29 | public class CustomDailyRollingFileAppender extends FileAppender {
30 | // The code assumes that the following constants are in a increasing
31 | // sequence.
32 | static final int TOP_OF_TROUBLE = -1;
33 | static final int TOP_OF_MINUTE = 0;
34 | static final int TOP_OF_HOUR = 1;
35 | static final int HALF_DAY = 2;
36 | static final int TOP_OF_DAY = 3;
37 | static final int TOP_OF_WEEK = 4;
38 | static final int TOP_OF_MONTH = 5;
39 |
40 | /**
41 | The date pattern. By default, the pattern is set to
42 | "'.'yyyy-MM-dd" meaning daily rollover.
43 | */
44 | private String datePattern = "'.'yyyy-MM-dd";
45 | /**
46 | There is one backup file by default.
47 | */
48 | protected int maxBackupIndex = 1;
49 |
50 | /**
51 | The log file will be renamed to the value of the
52 | scheduledFilename variable when the next interval is entered. For
53 | example, if the rollover period is one hour, the log file will be
54 | renamed to the value of "scheduledFilename" at the beginning of
55 | the next hour.
56 |
57 | The precise time when a rollover occurs depends on logging
58 | activity.
59 | */
60 | private String scheduledFilename;
61 |
62 | /**
63 | The next time we estimate a rollover should occur.
64 | */
65 | private long nextCheck = System.currentTimeMillis() - 1;
66 |
67 | Date now = new Date();
68 |
69 | SimpleDateFormat sdf;
70 |
71 | RollingCalendar rc = new RollingCalendar();
72 |
73 | int checkPeriod = TOP_OF_TROUBLE;
74 |
75 | // The gmtTimeZone is used only in computeCheckPeriod() method.
76 | static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
77 |
78 | /**
79 | The default constructor does nothing. */
80 | public CustomDailyRollingFileAppender() {
81 | }
82 |
83 | /**
84 | Instantiate a DailyRollingFileAppender and open the
85 | file designated by filename. The opened filename will
86 | become the ouput destination for this appender.
87 |
88 | */
89 | public CustomDailyRollingFileAppender(Layout layout, String filename, String datePattern) throws IOException {
90 | super(layout, filename, true);
91 | this.datePattern = datePattern;
92 | activateOptions();
93 | }
94 |
95 | /**
96 | The DatePattern takes a string in the same format as
97 | expected by {@link SimpleDateFormat}. This options determines the
98 | rollover schedule.
99 | */
100 | public void setDatePattern(String pattern) {
101 | datePattern = pattern;
102 | }
103 |
104 | /**
105 | Set the maximum number of backup files to keep around.
106 |
107 | The MaxBackupIndex option determines how many backup
108 | files are kept before the oldest is erased. This option takes
109 | a positive integer value. If set to zero, then there will be no
110 | backup files and the log file will be truncated when it reaches
111 | MaxFileSize.
112 | */
113 | public void setMaxBackupIndex(int maxBackups) {
114 | this.maxBackupIndex = maxBackups;
115 | }
116 |
117 | /**
118 | Returns the value of the MaxBackupIndex option.
119 | */
120 | public int getMaxBackupIndex() {
121 | return maxBackupIndex;
122 | }
123 |
124 | /** Returns the value of the DatePattern option. */
125 | public String getDatePattern() {
126 | return datePattern;
127 | }
128 |
129 | @Override
130 | public void activateOptions() {
131 | super.activateOptions();
132 | if (datePattern != null && fileName != null) {
133 | now.setTime(System.currentTimeMillis());
134 | sdf = new SimpleDateFormat(datePattern);
135 | int type = computeCheckPeriod();
136 | printPeriodicity(type);
137 | rc.setType(type);
138 | File file = new File(fileName);
139 | scheduledFilename = fileName
140 | + sdf.format(new Date(file.lastModified()));
141 |
142 | } else {
143 | LogLog.error("Either File or DatePattern options are not set for appender ["+ name + "].");
144 | }
145 | }
146 |
147 | void printPeriodicity(int type) {
148 | switch (type) {
149 | case TOP_OF_MINUTE:
150 | LogLog.debug("Appender [" + name + "] to be rolled every minute.");
151 | break;
152 | case TOP_OF_HOUR:
153 | LogLog.debug("Appender [" + name + "] to be rolled on top of every hour.");
154 | break;
155 | case HALF_DAY:
156 | LogLog.debug("Appender [" + name + "] to be rolled at midday and midnight.");
157 | break;
158 | case TOP_OF_DAY:
159 | LogLog.debug("Appender [" + name + "] to be rolled at midnight.");
160 | break;
161 | case TOP_OF_WEEK:
162 | LogLog.debug("Appender [" + name + "] to be rolled at start of week.");
163 | break;
164 | case TOP_OF_MONTH:
165 | LogLog.debug("Appender [" + name + "] to be rolled at start of every month.");
166 | break;
167 | default:
168 | LogLog.warn("Unknown periodicity for appender [" + name + "].");
169 | }
170 | }
171 |
172 | // This method computes the roll over period by looping over the
173 | // periods, starting with the shortest, and stopping when the r0 is
174 | // different from from r1, where r0 is the epoch formatted according
175 | // the datePattern (supplied by the user) and r1 is the
176 | // epoch+nextMillis(i) formatted according to datePattern. All date
177 | // formatting is done in GMT and not local format because the test
178 | // logic is based on comparisons relative to 1970-01-01 00:00:00
179 | // GMT (the epoch).
180 |
181 | int computeCheckPeriod() {
182 | RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone,
183 | Locale.getDefault());
184 | // set sate to 1970-01-01 00:00:00 GMT
185 | Date epoch = new Date(0);
186 | if (datePattern != null) {
187 | for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
188 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
189 | datePattern);
190 | simpleDateFormat.setTimeZone(gmtTimeZone); // do all date
191 | // formatting in GMT
192 | String r0 = simpleDateFormat.format(epoch);
193 | rollingCalendar.setType(i);
194 | Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
195 | String r1 = simpleDateFormat.format(next);
196 | // System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
197 | if (r0 != null && r1 != null && !r0.equals(r1)) {
198 | return i;
199 | }
200 | }
201 | }
202 | return TOP_OF_TROUBLE; // Deliberately head for trouble...
203 | }
204 |
205 | /**
206 | Rollover the current file to a new file.
207 | */
208 | void rollOver() throws IOException {
209 |
210 | List files = getAllFiles();
211 | Collections.sort(files);
212 | if (files.size() >= maxBackupIndex) {
213 | int index = 0;
214 | int diff = files.size() - (maxBackupIndex - 1);
215 | for (ModifiedTimeSortableFile file : files) {
216 | if (index >= diff)
217 | break;
218 |
219 | file.delete();
220 | index++;
221 | }
222 | }
223 |
224 | /* Compute filename, but only if datePattern is specified */
225 | if (datePattern == null) {
226 | errorHandler.error("Missing DatePattern option in rollOver().");
227 | return;
228 | }
229 | LogLog.debug("maxBackupIndex=" + maxBackupIndex);
230 |
231 | String datedFilename = fileName + sdf.format(now);
232 | // It is too early to roll over because we are still within the
233 | // bounds of the current interval. Rollover will occur once the
234 | // next interval is reached.
235 | if (scheduledFilename.equals(datedFilename)) {
236 | return;
237 | }
238 |
239 | // close current file, and rename it to datedFilename
240 | this.closeFile();
241 |
242 | File target = new File(scheduledFilename);
243 | if (target.exists()) {
244 | target.delete();
245 | }
246 |
247 | File file = new File(fileName);
248 | boolean result = file.renameTo(target);
249 | if (result) {
250 | LogLog.debug(fileName + " -> " + scheduledFilename);
251 | } else {
252 | LogLog.error("Failed to rename [" + fileName + "] to ["
253 | + scheduledFilename + "].");
254 | }
255 |
256 | try {
257 | // This will also close the file. This is OK since multiple
258 | // close operations are safe.
259 | this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
260 | } catch (IOException e) {
261 | errorHandler.error("setFile(" + fileName + ", true) call failed.");
262 | }
263 | scheduledFilename = datedFilename;
264 | }
265 |
266 | /**
267 | * This method differentiates DailyRollingFileAppender from its
268 | * super class.
269 | *
270 | * Before actually logging, this method will check whether it is
271 | * time to do a rollover. If it is, it will schedule the next
272 | * rollover time and then rollover.
273 | * */
274 | @Override
275 | protected void subAppend(LoggingEvent event) {
276 | long n = System.currentTimeMillis();
277 | if (n >= nextCheck) {
278 | now.setTime(n);
279 | nextCheck = rc.getNextCheckMillis(now);
280 | try {
281 | rollOver();
282 | } catch (IOException ioe) {
283 | if (ioe instanceof InterruptedIOException) {
284 | Thread.currentThread().interrupt();
285 | }
286 | LogLog.error("rollOver() failed.", ioe);
287 | }
288 | }
289 | super.subAppend(event);
290 | }
291 |
292 | /**
293 | * This method searches list of log files
294 | * based on the pattern given in the log4j configuration file
295 | * and returns a collection
296 | * @return List<ModifiedTimeSortableFile>
297 | */
298 | private List getAllFiles() {
299 | List files = new ArrayList();
300 | FilenameFilter filter = new FilenameFilter() {
301 | public boolean accept(File dir, String name) {
302 | String directoryName = dir.getPath();
303 | LogLog.debug("directory name: " + directoryName);
304 | File file = new File(fileName);
305 | String perentDirectory = file.getParent();
306 | if (perentDirectory != null)
307 | {
308 | String localFile = fileName.substring(directoryName.length());
309 | return name.startsWith(localFile);
310 | }
311 | return name.startsWith(fileName);
312 | }
313 | };
314 | File file = new File(fileName);
315 | String perentDirectory = file.getParent();
316 | if (file.exists()) {
317 | if (file.getParent() == null) {
318 | String absolutePath = file.getAbsolutePath();
319 | perentDirectory = absolutePath.substring(0, absolutePath.lastIndexOf(fileName));
320 |
321 | }
322 | }
323 | File dir = new File(perentDirectory);
324 | String[] names = dir.list(filter);
325 |
326 | for (int i = 0; i < names.length; i++) {
327 | files.add(new ModifiedTimeSortableFile(dir + System.getProperty("file.separator") + names[i]));
328 | }
329 | return files;
330 | }
331 | }
332 |
333 | /**
334 | * The Class ModifiedTimeSortableFile extends java.io.File class and
335 | * implements Comparable to sort files list based upon their modified date
336 | */
337 | class ModifiedTimeSortableFile extends File implements Serializable, Comparable {
338 | private static final long serialVersionUID = 1373373728209668895L;
339 |
340 | public ModifiedTimeSortableFile(String parent, String child) {
341 | super(parent, child);
342 | // TODO Auto-generated constructor stub
343 | }
344 |
345 | public ModifiedTimeSortableFile(URI uri) {
346 | super(uri);
347 | // TODO Auto-generated constructor stub
348 | }
349 |
350 | public ModifiedTimeSortableFile(File parent, String child) {
351 | super(parent, child);
352 | }
353 |
354 | public ModifiedTimeSortableFile(String string) {
355 | super(string);
356 | }
357 |
358 | @Override
359 | public int compareTo(File anotherPathName) {
360 | long thisVal = this.lastModified();
361 | long anotherVal = anotherPathName.lastModified();
362 | return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));
363 | }
364 | }
365 |
366 | /**
367 | * RollingCalendar is a helper class to DailyRollingFileAppender.
368 | * Given a periodicity type and the current time, it computes the
369 | * start of the next interval.
370 | * */
371 | class RollingCalendar extends GregorianCalendar {
372 | private static final long serialVersionUID = -3560331770601814177L;
373 |
374 | int type = CustomDailyRollingFileAppender.TOP_OF_TROUBLE;
375 |
376 | RollingCalendar() {
377 | super();
378 | }
379 |
380 | RollingCalendar(TimeZone tz, Locale locale) {
381 | super(tz, locale);
382 | }
383 |
384 | void setType(int type) {
385 | this.type = type;
386 | }
387 |
388 | public long getNextCheckMillis(Date now) {
389 | return getNextCheckDate(now).getTime();
390 | }
391 |
392 | public Date getNextCheckDate(Date now) {
393 | this.setTime(now);
394 |
395 | switch (type) {
396 | case CustomDailyRollingFileAppender.TOP_OF_MINUTE:
397 | this.set(Calendar.SECOND, 0);
398 | this.set(Calendar.MILLISECOND, 0);
399 | this.add(Calendar.MINUTE, 1);
400 | break;
401 | case CustomDailyRollingFileAppender.TOP_OF_HOUR:
402 | this.set(Calendar.MINUTE, 0);
403 | this.set(Calendar.SECOND, 0);
404 | this.set(Calendar.MILLISECOND, 0);
405 | this.add(Calendar.HOUR_OF_DAY, 1);
406 | break;
407 | case CustomDailyRollingFileAppender.HALF_DAY:
408 | this.set(Calendar.MINUTE, 0);
409 | this.set(Calendar.SECOND, 0);
410 | this.set(Calendar.MILLISECOND, 0);
411 | int hour = get(Calendar.HOUR_OF_DAY);
412 | if (hour < 12) {
413 | this.set(Calendar.HOUR_OF_DAY, 12);
414 | } else {
415 | this.set(Calendar.HOUR_OF_DAY, 0);
416 | this.add(Calendar.DAY_OF_MONTH, 1);
417 | }
418 | break;
419 | case CustomDailyRollingFileAppender.TOP_OF_DAY:
420 | this.set(Calendar.HOUR_OF_DAY, 0);
421 | this.set(Calendar.MINUTE, 0);
422 | this.set(Calendar.SECOND, 0);
423 | this.set(Calendar.MILLISECOND, 0);
424 | this.add(Calendar.DATE, 1);
425 | break;
426 | case CustomDailyRollingFileAppender.TOP_OF_WEEK:
427 | this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
428 | this.set(Calendar.HOUR_OF_DAY, 0);
429 | this.set(Calendar.MINUTE, 0);
430 | this.set(Calendar.SECOND, 0);
431 | this.set(Calendar.MILLISECOND, 0);
432 | this.add(Calendar.WEEK_OF_YEAR, 1);
433 | break;
434 | case CustomDailyRollingFileAppender.TOP_OF_MONTH:
435 | this.set(Calendar.DATE, 1);
436 | this.set(Calendar.HOUR_OF_DAY, 0);
437 | this.set(Calendar.MINUTE, 0);
438 | this.set(Calendar.SECOND, 0);
439 | this.set(Calendar.MILLISECOND, 0);
440 | this.add(Calendar.MONTH, 1);
441 | break;
442 | default:
443 | throw new IllegalStateException("Unknown periodicity type.");
444 | }
445 | return getTime();
446 | }
447 |
448 | }
449 |
--------------------------------------------------------------------------------