1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.types.selectors;
  18. import java.io.File;
  19. import java.text.DateFormat;
  20. import java.text.SimpleDateFormat;
  21. import java.text.ParseException;
  22. import java.util.Locale;
  23. import org.apache.tools.ant.Project;
  24. import org.apache.tools.ant.taskdefs.condition.Os;
  25. import org.apache.tools.ant.types.EnumeratedAttribute;
  26. import org.apache.tools.ant.types.Parameter;
  27. /**
  28. * Selector that chooses files based on their last modified date.
  29. *
  30. * @since 1.5
  31. */
  32. public class DateSelector extends BaseExtendSelector {
  33. private long millis = -1;
  34. private String dateTime = null;
  35. private boolean includeDirs = false;
  36. private int granularity = 0;
  37. private int cmp = 2;
  38. private String pattern;
  39. /** Key to used for parameterized custom selector */
  40. public static final String MILLIS_KEY = "millis";
  41. /** Key to used for parameterized custom selector */
  42. public static final String DATETIME_KEY = "datetime";
  43. /** Key to used for parameterized custom selector */
  44. public static final String CHECKDIRS_KEY = "checkdirs";
  45. /** Key to used for parameterized custom selector */
  46. public static final String GRANULARITY_KEY = "granularity";
  47. /** Key to used for parameterized custom selector */
  48. public static final String WHEN_KEY = "when";
  49. /** Key to used for parameterized custom selector */
  50. public static final String PATTERN_KEY = "pattern";
  51. /**
  52. * Creates a new <code>DateSelector</code> instance.
  53. *
  54. */
  55. public DateSelector() {
  56. if (Os.isFamily("dos")) {
  57. granularity = 2000;
  58. }
  59. }
  60. /**
  61. * @return a string describing this object
  62. */
  63. public String toString() {
  64. StringBuffer buf = new StringBuffer("{dateselector date: ");
  65. buf.append(dateTime);
  66. buf.append(" compare: ");
  67. if (cmp == 0) {
  68. buf.append("before");
  69. } else if (cmp == 1) {
  70. buf.append("after");
  71. } else {
  72. buf.append("equal");
  73. }
  74. buf.append(" granularity: ");
  75. buf.append(granularity);
  76. if (pattern != null) {
  77. buf.append(" pattern: ").append(pattern);
  78. }
  79. buf.append("}");
  80. return buf.toString();
  81. }
  82. /**
  83. * For users that prefer to express time in milliseconds since 1970
  84. *
  85. * @param millis the time to compare file's last modified date to,
  86. * expressed in milliseconds
  87. */
  88. public void setMillis(long millis) {
  89. this.millis = millis;
  90. }
  91. /**
  92. * Returns the millisecond value the selector is set for.
  93. * @return the millisecond value
  94. */
  95. public long getMillis() {
  96. if (dateTime != null) {
  97. validate();
  98. }
  99. return millis;
  100. }
  101. /**
  102. * Sets the date. The user must supply it in MM/DD/YYYY HH:MM AM_PM
  103. * format
  104. *
  105. * @param dateTime a string in MM/DD/YYYY HH:MM AM_PM format
  106. */
  107. public void setDatetime(String dateTime) {
  108. this.dateTime = dateTime;
  109. }
  110. /**
  111. * Should we be checking dates on directories?
  112. *
  113. * @param includeDirs whether to check the timestamp on directories
  114. */
  115. public void setCheckdirs(boolean includeDirs) {
  116. this.includeDirs = includeDirs;
  117. }
  118. /**
  119. * Sets the number of milliseconds leeway we will give before we consider
  120. * a file not to have matched a date.
  121. * @param granularity the number of milliconds leeway
  122. */
  123. public void setGranularity(int granularity) {
  124. this.granularity = granularity;
  125. }
  126. /**
  127. * Sets the type of comparison to be done on the file's last modified
  128. * date.
  129. *
  130. * @param cmp The comparison to perform, an EnumeratedAttribute
  131. */
  132. public void setWhen(TimeComparisons cmp) {
  133. this.cmp = cmp.getIndex();
  134. }
  135. /**
  136. * Sets the pattern to be used for the SimpleDateFormat
  137. *
  138. * @param pattern the pattern that defines the date format
  139. */
  140. public void setPattern(String pattern) {
  141. this.pattern = pattern;
  142. }
  143. /**
  144. * When using this as a custom selector, this method will be called.
  145. * It translates each parameter into the appropriate setXXX() call.
  146. *
  147. * @param parameters the complete set of parameters for this selector
  148. */
  149. public void setParameters(Parameter[] parameters) {
  150. super.setParameters(parameters);
  151. if (parameters != null) {
  152. for (int i = 0; i < parameters.length; i++) {
  153. String paramname = parameters[i].getName();
  154. if (MILLIS_KEY.equalsIgnoreCase(paramname)) {
  155. try {
  156. setMillis(new Long(parameters[i].getValue()
  157. ).longValue());
  158. } catch (NumberFormatException nfe) {
  159. setError("Invalid millisecond setting "
  160. + parameters[i].getValue());
  161. }
  162. } else if (DATETIME_KEY.equalsIgnoreCase(paramname)) {
  163. setDatetime(parameters[i].getValue());
  164. } else if (CHECKDIRS_KEY.equalsIgnoreCase(paramname)) {
  165. setCheckdirs(Project.toBoolean(parameters[i].getValue()));
  166. } else if (GRANULARITY_KEY.equalsIgnoreCase(paramname)) {
  167. try {
  168. setGranularity(new Integer(parameters[i].getValue()
  169. ).intValue());
  170. } catch (NumberFormatException nfe) {
  171. setError("Invalid granularity setting "
  172. + parameters[i].getValue());
  173. }
  174. } else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
  175. TimeComparisons cmp = new TimeComparisons();
  176. cmp.setValue(parameters[i].getValue());
  177. setWhen(cmp);
  178. } else if (PATTERN_KEY.equalsIgnoreCase(paramname)) {
  179. setPattern(parameters[i].getValue());
  180. } else {
  181. setError("Invalid parameter " + paramname);
  182. }
  183. }
  184. }
  185. }
  186. /**
  187. * This is a consistency check to ensure the selector's required
  188. * values have been set.
  189. */
  190. public void verifySettings() {
  191. if (dateTime == null && millis < 0) {
  192. setError("You must provide a datetime or the number of "
  193. + "milliseconds.");
  194. } else if (millis < 0 && dateTime != null) {
  195. // check millis and only set it once.
  196. DateFormat df = ((pattern == null)
  197. ? DateFormat.getDateTimeInstance(
  198. DateFormat.SHORT, DateFormat.SHORT, Locale.US)
  199. : new SimpleDateFormat(pattern));
  200. try {
  201. setMillis(df.parse(dateTime).getTime());
  202. if (millis < 0) {
  203. setError("Date of " + dateTime
  204. + " results in negative milliseconds value"
  205. + " relative to epoch (January 1, 1970, 00:00:00 GMT).");
  206. }
  207. } catch (ParseException pe) {
  208. setError("Date of " + dateTime
  209. + " Cannot be parsed correctly. It should be in"
  210. + ((pattern == null)
  211. ? " MM/DD/YYYY HH:MM AM_PM" : pattern) + " format.");
  212. }
  213. }
  214. }
  215. /**
  216. * The heart of the matter. This is where the selector gets to decide
  217. * on the inclusion of a file in a particular fileset.
  218. *
  219. * @param basedir the base directory the scan is being done from
  220. * @param filename is the name of the file to check
  221. * @param file is a java.io.File object the selector can use
  222. * @return whether the file should be selected or not
  223. */
  224. public boolean isSelected(File basedir, String filename, File file) {
  225. validate();
  226. if (file.isDirectory() && (!includeDirs)) {
  227. return true;
  228. }
  229. if (cmp == 0) {
  230. return ((file.lastModified() - granularity) < millis);
  231. } else if (cmp == 1) {
  232. return ((file.lastModified() + granularity) > millis);
  233. } else {
  234. return (Math.abs(file.lastModified() - millis) <= granularity);
  235. }
  236. }
  237. /**
  238. * Enumerated attribute with the values for time comparison.
  239. * <p>
  240. */
  241. public static class TimeComparisons extends EnumeratedAttribute {
  242. /**
  243. * @return the values as an array of strings
  244. */
  245. public String[] getValues() {
  246. return new String[]{"before", "after", "equal"};
  247. }
  248. }
  249. }