1 /*****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20 package org.apache.mailet.dates;
21
22 import java.text.DateFormat;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25 import java.util.Date;
26 import java.util.Locale;
27 import java.util.TimeZone;
28
29
30 /***
31 * This class is designed to be a synchronized wrapper for a
32 * <code>java.text.DateFormat</code> subclass. In general,
33 * these subclasses (most notably the <code>java.text.SimpleDateFormat</code>
34 * classes are not thread safe, so we need to synchronize on the
35 * internal DateFormat for all delegated calls.
36 *
37 */
38 public class SynchronizedDateFormat implements SimplifiedDateFormat {
39 private final DateFormat internalDateFormat;
40
41 /***
42 * Public constructor that mimics that of SimpleDateFormat. See
43 * java.text.SimpleDateFormat for more details.
44 *
45 * @param pattern the pattern that defines this DateFormat
46 * @param locale the locale
47 */
48 public SynchronizedDateFormat(String pattern, Locale locale) {
49 internalDateFormat = new SimpleDateFormat(pattern, locale);
50 }
51
52 /***
53 * <p>Wrapper method to allow child classes to synchronize a preexisting
54 * DateFormat.</p>
55 *
56 * <p>TODO: Investigate replacing this with a factory method.</p>
57 *
58 * @param the DateFormat to synchronize
59 */
60 protected SynchronizedDateFormat(DateFormat theDateFormat) {
61 internalDateFormat = theDateFormat;
62 }
63
64 /***
65 * SimpleDateFormat will handle most of this for us, but we
66 * want to ensure thread safety, so we wrap the call in a
67 * synchronized block.
68 *
69 * @return java.lang.String
70 * @param d Date
71 */
72 public String format(Date d) {
73 synchronized (internalDateFormat) {
74 return internalDateFormat.format(d);
75 }
76 }
77
78 /***
79 * Parses text from the beginning of the given string to produce a date.
80 * The method may not use the entire text of the given string.
81 * <p>
82 * This method is designed to be thread safe, so we wrap our delegated
83 * parse method in an appropriate synchronized block.
84 *
85 * @param source A <code>String</code> whose beginning should be parsed.
86 * @return A <code>Date</code> parsed from the string.
87 * @throws ParseException if the beginning of the specified string
88 * cannot be parsed.
89 */
90 public Date parse(String source) throws ParseException {
91 synchronized (internalDateFormat) {
92 return internalDateFormat.parse(source);
93 }
94 }
95
96 /***
97 * Sets the time zone of this SynchronizedDateFormat object.
98 * @param zone the given new time zone.
99 */
100 public void setTimeZone(TimeZone zone) {
101 synchronized(internalDateFormat) {
102 internalDateFormat.setTimeZone(zone);
103 }
104 }
105
106 /***
107 * Gets the time zone.
108 * @return the time zone associated with this SynchronizedDateFormat.
109 */
110 public TimeZone getTimeZone() {
111 synchronized(internalDateFormat) {
112 return internalDateFormat.getTimeZone();
113 }
114 }
115
116 /***
117 * Specify whether or not date/time parsing is to be lenient. With
118 * lenient parsing, the parser may use heuristics to interpret inputs that
119 * do not precisely match this object's format. With strict parsing,
120 * inputs must match this object's format.
121 * @param lenient when true, parsing is lenient
122 * @see java.util.Calendar#setLenient
123 */
124 public void setLenient(boolean lenient)
125 {
126 synchronized(internalDateFormat) {
127 internalDateFormat.setLenient(lenient);
128 }
129 }
130
131 /***
132 * Tell whether date/time parsing is to be lenient.
133 * @return whether this SynchronizedDateFormat is lenient.
134 */
135 public boolean isLenient()
136 {
137 synchronized(internalDateFormat) {
138 return internalDateFormat.isLenient();
139 }
140 }
141
142 /***
143 * Overrides hashCode
144 */
145 public int hashCode() {
146 synchronized(internalDateFormat) {
147 return internalDateFormat.hashCode();
148 }
149 }
150
151 /***
152 * Overrides equals
153 */
154 public boolean equals(Object obj) {
155 if (this == obj) {
156 return true;
157 }
158 if (obj == null || getClass() != obj.getClass()) {
159 return false;
160 }
161 synchronized(internalDateFormat) {
162 return internalDateFormat.equals(obj);
163 }
164 }
165
166 }