1. /*
  2. * Copyright 2000-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.taskdefs;
  18. import java.text.SimpleDateFormat;
  19. import java.util.Calendar;
  20. import java.util.Date;
  21. import java.util.Enumeration;
  22. import java.util.Hashtable;
  23. import java.util.Locale;
  24. import java.util.NoSuchElementException;
  25. import java.util.StringTokenizer;
  26. import java.util.TimeZone;
  27. import java.util.Vector;
  28. import org.apache.tools.ant.BuildException;
  29. import org.apache.tools.ant.Location;
  30. import org.apache.tools.ant.Project;
  31. import org.apache.tools.ant.Task;
  32. import org.apache.tools.ant.types.EnumeratedAttribute;
  33. /**
  34. * Sets properties to the current time, or offsets from the current time.
  35. * The default properties are TSTAMP, DSTAMP and TODAY;
  36. *
  37. * @since Ant 1.1
  38. * @ant.task category="utility"
  39. */
  40. public class Tstamp extends Task {
  41. private Vector customFormats = new Vector();
  42. private String prefix = "";
  43. /**
  44. * Set a prefix for the properties. If the prefix does not end with a "."
  45. * one is automatically added
  46. * @since Ant 1.5
  47. */
  48. public void setPrefix(String prefix) {
  49. this.prefix = prefix;
  50. if (!this.prefix.endsWith(".")) {
  51. this.prefix += ".";
  52. }
  53. }
  54. /**
  55. * create the timestamps. Custom ones are done before
  56. * the standard ones, to get their retaliation in early.
  57. * @throws BuildException
  58. */
  59. public void execute() throws BuildException {
  60. try {
  61. Date d = new Date();
  62. Enumeration i = customFormats.elements();
  63. while (i.hasMoreElements()) {
  64. CustomFormat cts = (CustomFormat) i.nextElement();
  65. cts.execute(getProject(), d, getLocation());
  66. }
  67. SimpleDateFormat dstamp = new SimpleDateFormat ("yyyyMMdd");
  68. setProperty("DSTAMP", dstamp.format(d));
  69. SimpleDateFormat tstamp = new SimpleDateFormat ("HHmm");
  70. setProperty("TSTAMP", tstamp.format(d));
  71. SimpleDateFormat today
  72. = new SimpleDateFormat ("MMMM d yyyy", Locale.US);
  73. setProperty("TODAY", today.format(d));
  74. } catch (Exception e) {
  75. throw new BuildException(e);
  76. }
  77. }
  78. /**
  79. * create a custom format with the current prefix.
  80. * @return a ready to fill-in format
  81. */
  82. public CustomFormat createFormat() {
  83. CustomFormat cts = new CustomFormat();
  84. customFormats.addElement(cts);
  85. return cts;
  86. }
  87. /**
  88. * helper that encapsulates prefix logic and property setting
  89. * policy (i.e. we use setNewProperty instead of setProperty).
  90. */
  91. private void setProperty(String name, String value) {
  92. getProject().setNewProperty(prefix + name, value);
  93. }
  94. /**
  95. * This nested element that allows a property to be set
  96. * to the current date and time in a given format.
  97. * The date/time patterns are as defined in the
  98. * Java SimpleDateFormat class.
  99. * The format element also allows offsets to be applied to
  100. * the time to generate different time values.
  101. * @todo consider refactoring out into a re-usable element.
  102. */
  103. public class CustomFormat {
  104. private TimeZone timeZone;
  105. private String propertyName;
  106. private String pattern;
  107. private String language;
  108. private String country;
  109. private String variant;
  110. private int offset = 0;
  111. private int field = Calendar.DATE;
  112. /**
  113. * Create a format
  114. */
  115. public CustomFormat() {
  116. }
  117. /**
  118. * The property to receive the date/time string in the given pattern
  119. * @param propertyName
  120. */
  121. public void setProperty(String propertyName) {
  122. this.propertyName = propertyName;
  123. }
  124. /**
  125. * The date/time pattern to be used. The values are as
  126. * defined by the Java SimpleDateFormat class.
  127. * @param pattern
  128. * @see java.text.SimpleDateFormat
  129. */
  130. public void setPattern(String pattern) {
  131. this.pattern = pattern;
  132. }
  133. /**
  134. * The locale used to create date/time string.
  135. * The general form is "language, country, variant" but
  136. * either variant or variant and country may be omitted.
  137. * For more information please refer to documentation
  138. * for the java.util.Locale class.
  139. * @param locale
  140. * @see java.util.Locale
  141. */
  142. public void setLocale(String locale) {
  143. StringTokenizer st = new StringTokenizer(locale, " \t\n\r\f,");
  144. try {
  145. language = st.nextToken();
  146. if (st.hasMoreElements()) {
  147. country = st.nextToken();
  148. if (st.hasMoreElements()) {
  149. variant = st.nextToken();
  150. if (st.hasMoreElements()) {
  151. throw new BuildException("bad locale format",
  152. getLocation());
  153. }
  154. }
  155. } else {
  156. country = "";
  157. }
  158. } catch (NoSuchElementException e) {
  159. throw new BuildException("bad locale format", e,
  160. getLocation());
  161. }
  162. }
  163. /**
  164. * The timezone to use for displaying time.
  165. * The values are as defined by the Java TimeZone class.
  166. * @param id
  167. * @see java.util.TimeZone
  168. */
  169. public void setTimezone(String id) {
  170. timeZone = TimeZone.getTimeZone(id);
  171. }
  172. /**
  173. * The numeric offset to the current time.
  174. * @param offset
  175. */
  176. public void setOffset(int offset) {
  177. this.offset = offset;
  178. }
  179. /**
  180. * @deprecated setUnit(String) is deprecated and is replaced with
  181. * setUnit(Tstamp.Unit) to make Ant's
  182. * Introspection mechanism do the work and also to
  183. * encapsulate operations on the unit in its own
  184. * class.
  185. */
  186. public void setUnit(String unit) {
  187. log("DEPRECATED - The setUnit(String) method has been deprecated."
  188. + " Use setUnit(Tstamp.Unit) instead.");
  189. Unit u = new Unit();
  190. u.setValue(unit);
  191. field = u.getCalendarField();
  192. }
  193. /**
  194. * The unit of the offset to be applied to the current time.
  195. * Valid Values are
  196. * <ul>
  197. * <li>millisecond</li>
  198. * <li>second</li>
  199. * <li>minute</li>
  200. * <li>hour</li>
  201. * <li>day</li>
  202. * <li>week</li>
  203. * <li>month</li>
  204. * <li>year</li>
  205. * </ul>
  206. * The default unit is day.
  207. * @param unit
  208. */
  209. public void setUnit(Unit unit) {
  210. field = unit.getCalendarField();
  211. }
  212. /**
  213. * validate parameter and execute the format
  214. * @param project project to set property in
  215. * @param date date to use as a starting point
  216. * @param location line in file (for errors)
  217. */
  218. public void execute(Project project, Date date, Location location) {
  219. if (propertyName == null) {
  220. throw new BuildException("property attribute must be provided",
  221. location);
  222. }
  223. if (pattern == null) {
  224. throw new BuildException("pattern attribute must be provided",
  225. location);
  226. }
  227. SimpleDateFormat sdf;
  228. if (language == null) {
  229. sdf = new SimpleDateFormat(pattern);
  230. } else if (variant == null) {
  231. sdf = new SimpleDateFormat(pattern,
  232. new Locale(language, country));
  233. } else {
  234. sdf = new SimpleDateFormat(pattern,
  235. new Locale(language, country,
  236. variant));
  237. }
  238. if (offset != 0) {
  239. Calendar calendar = Calendar.getInstance();
  240. calendar.setTime(date);
  241. calendar.add(field, offset);
  242. date = calendar.getTime();
  243. }
  244. if (timeZone != null) {
  245. sdf.setTimeZone(timeZone);
  246. }
  247. Tstamp.this.setProperty(propertyName, sdf.format(date));
  248. }
  249. }
  250. /**
  251. * set of valid units to use for time offsets.
  252. */
  253. public static class Unit extends EnumeratedAttribute {
  254. private static final String MILLISECOND = "millisecond";
  255. private static final String SECOND = "second";
  256. private static final String MINUTE = "minute";
  257. private static final String HOUR = "hour";
  258. private static final String DAY = "day";
  259. private static final String WEEK = "week";
  260. private static final String MONTH = "month";
  261. private static final String YEAR = "year";
  262. private static final String[] units = {
  263. MILLISECOND,
  264. SECOND,
  265. MINUTE,
  266. HOUR,
  267. DAY,
  268. WEEK,
  269. MONTH,
  270. YEAR
  271. };
  272. private Hashtable calendarFields = new Hashtable();
  273. public Unit() {
  274. calendarFields.put(MILLISECOND,
  275. new Integer(Calendar.MILLISECOND));
  276. calendarFields.put(SECOND, new Integer(Calendar.SECOND));
  277. calendarFields.put(MINUTE, new Integer(Calendar.MINUTE));
  278. calendarFields.put(HOUR, new Integer(Calendar.HOUR_OF_DAY));
  279. calendarFields.put(DAY, new Integer(Calendar.DATE));
  280. calendarFields.put(WEEK, new Integer(Calendar.WEEK_OF_YEAR));
  281. calendarFields.put(MONTH, new Integer(Calendar.MONTH));
  282. calendarFields.put(YEAR, new Integer(Calendar.YEAR));
  283. }
  284. public int getCalendarField() {
  285. String key = getValue().toLowerCase();
  286. Integer i = (Integer) calendarFields.get(key);
  287. return i.intValue();
  288. }
  289. public String[] getValues() {
  290. return units;
  291. }
  292. }
  293. }