001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.mailet.dates;
019:
020: import java.text.DateFormat;
021: import java.text.ParseException;
022: import java.text.SimpleDateFormat;
023: import java.util.Date;
024: import java.util.Locale;
025: import java.util.TimeZone;
026:
027: /**
028: * This class is designed to be a synchronized wrapper for a
029: * <code>java.text.DateFormat</code> subclass. In general,
030: * these subclasses (most notably the <code>java.text.SimpleDateFormat</code>
031: * classes are not thread safe, so we need to synchronize on the
032: * internal DateFormat for all delegated calls.
033: *
034: */
035: public class SynchronizedDateFormat implements SimplifiedDateFormat {
036: private final DateFormat internalDateFormat;
037:
038: /**
039: * Public constructor that mimics that of SimpleDateFormat. See
040: * java.text.SimpleDateFormat for more details.
041: *
042: * @param pattern the pattern that defines this DateFormat
043: * @param locale the locale
044: */
045: public SynchronizedDateFormat(String pattern, Locale locale) {
046: internalDateFormat = new SimpleDateFormat(pattern, locale);
047: }
048:
049: /**
050: * <p>Wrapper method to allow child classes to synchronize a preexisting
051: * DateFormat.</p>
052: *
053: * <p>TODO: Investigate replacing this with a factory method.</p>
054: *
055: * @param the DateFormat to synchronize
056: */
057: protected SynchronizedDateFormat(DateFormat theDateFormat) {
058: internalDateFormat = theDateFormat;
059: }
060:
061: /**
062: * SimpleDateFormat will handle most of this for us, but we
063: * want to ensure thread safety, so we wrap the call in a
064: * synchronized block.
065: *
066: * @return java.lang.String
067: * @param d Date
068: */
069: public String format(Date d) {
070: synchronized (internalDateFormat) {
071: return internalDateFormat.format(d);
072: }
073: }
074:
075: /**
076: * Parses text from the beginning of the given string to produce a date.
077: * The method may not use the entire text of the given string.
078: * <p>
079: * This method is designed to be thread safe, so we wrap our delegated
080: * parse method in an appropriate synchronized block.
081: *
082: * @param source A <code>String</code> whose beginning should be parsed.
083: * @return A <code>Date</code> parsed from the string.
084: * @throws ParseException if the beginning of the specified string
085: * cannot be parsed.
086: */
087: public Date parse(String source) throws ParseException {
088: synchronized (internalDateFormat) {
089: return internalDateFormat.parse(source);
090: }
091: }
092:
093: /**
094: * Sets the time zone of this SynchronizedDateFormat object.
095: * @param zone the given new time zone.
096: */
097: public void setTimeZone(TimeZone zone) {
098: synchronized (internalDateFormat) {
099: internalDateFormat.setTimeZone(zone);
100: }
101: }
102:
103: /**
104: * Gets the time zone.
105: * @return the time zone associated with this SynchronizedDateFormat.
106: */
107: public TimeZone getTimeZone() {
108: synchronized (internalDateFormat) {
109: return internalDateFormat.getTimeZone();
110: }
111: }
112:
113: /**
114: * Specify whether or not date/time parsing is to be lenient. With
115: * lenient parsing, the parser may use heuristics to interpret inputs that
116: * do not precisely match this object's format. With strict parsing,
117: * inputs must match this object's format.
118: * @param lenient when true, parsing is lenient
119: * @see java.util.Calendar#setLenient
120: */
121: public void setLenient(boolean lenient) {
122: synchronized (internalDateFormat) {
123: internalDateFormat.setLenient(lenient);
124: }
125: }
126:
127: /**
128: * Tell whether date/time parsing is to be lenient.
129: * @return whether this SynchronizedDateFormat is lenient.
130: */
131: public boolean isLenient() {
132: synchronized (internalDateFormat) {
133: return internalDateFormat.isLenient();
134: }
135: }
136:
137: /**
138: * Overrides hashCode
139: */
140: public int hashCode() {
141: synchronized (internalDateFormat) {
142: return internalDateFormat.hashCode();
143: }
144: }
145:
146: /**
147: * Overrides equals
148: */
149: public boolean equals(Object obj) {
150: if (this == obj) {
151: return true;
152: }
153: if (obj == null || getClass() != obj.getClass()) {
154: return false;
155: }
156: synchronized (internalDateFormat) {
157: return internalDateFormat.equals(obj);
158: }
159: }
160:
161: }
|