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 ****************************************************************/
019
020
021 package org.apache.mailet.base;
022
023 import java.text.DateFormat;
024 import java.text.ParseException;
025 import java.text.SimpleDateFormat;
026 import java.util.Date;
027 import java.util.Locale;
028 import java.util.TimeZone;
029
030
031 /**
032 * This class is designed to be a synchronized wrapper for a
033 * <code>java.text.DateFormat</code> subclass. In general,
034 * these subclasses (most notably the <code>java.text.SimpleDateFormat</code>
035 * classes are not thread safe, so we need to synchronize on the
036 * internal DateFormat for all delegated calls.
037 *
038 */
039 public class SynchronizedDateFormat implements SimplifiedDateFormat {
040 private final DateFormat internalDateFormat;
041
042 /**
043 * Public constructor that mimics that of SimpleDateFormat. See
044 * java.text.SimpleDateFormat for more details.
045 *
046 * @param pattern the pattern that defines this DateFormat
047 * @param locale the locale
048 */
049 public SynchronizedDateFormat(String pattern, Locale locale) {
050 internalDateFormat = new SimpleDateFormat(pattern, locale);
051 }
052
053 /**
054 * <p>Wrapper method to allow child classes to synchronize a preexisting
055 * DateFormat.</p>
056 *
057 * <p>TODO: Investigate replacing this with a factory method.</p>
058 *
059 * @param theDateFormat the DateFormat to synchronize
060 */
061 protected SynchronizedDateFormat(DateFormat theDateFormat) {
062 internalDateFormat = theDateFormat;
063 }
064
065 /**
066 * SimpleDateFormat will handle most of this for us, but we
067 * want to ensure thread safety, so we wrap the call in a
068 * synchronized block.
069 *
070 * @return java.lang.String
071 * @param d Date
072 */
073 public String format(Date d) {
074 synchronized (internalDateFormat) {
075 return internalDateFormat.format(d);
076 }
077 }
078
079 /**
080 * Parses text from the beginning of the given string to produce a date.
081 * The method may not use the entire text of the given string.
082 * <p>
083 * This method is designed to be thread safe, so we wrap our delegated
084 * parse method in an appropriate synchronized block.
085 *
086 * @param source A <code>String</code> whose beginning should be parsed.
087 * @return A <code>Date</code> parsed from the string.
088 * @throws ParseException if the beginning of the specified string
089 * cannot be parsed.
090 */
091 public Date parse(String source) throws ParseException {
092 synchronized (internalDateFormat) {
093 return internalDateFormat.parse(source);
094 }
095 }
096
097 /**
098 * Sets the time zone of this SynchronizedDateFormat object.
099 * @param zone the given new time zone.
100 */
101 public void setTimeZone(TimeZone zone) {
102 synchronized(internalDateFormat) {
103 internalDateFormat.setTimeZone(zone);
104 }
105 }
106
107 /**
108 * Gets the time zone.
109 * @return the time zone associated with this SynchronizedDateFormat.
110 */
111 public TimeZone getTimeZone() {
112 synchronized(internalDateFormat) {
113 return internalDateFormat.getTimeZone();
114 }
115 }
116
117 /**
118 * Specify whether or not date/time parsing is to be lenient. With
119 * lenient parsing, the parser may use heuristics to interpret inputs that
120 * do not precisely match this object's format. With strict parsing,
121 * inputs must match this object's format.
122 * @param lenient when true, parsing is lenient
123 * @see java.util.Calendar#setLenient
124 */
125 public void setLenient(boolean lenient)
126 {
127 synchronized(internalDateFormat) {
128 internalDateFormat.setLenient(lenient);
129 }
130 }
131
132 /**
133 * Tell whether date/time parsing is to be lenient.
134 * @return whether this SynchronizedDateFormat is lenient.
135 */
136 public boolean isLenient()
137 {
138 synchronized(internalDateFormat) {
139 return internalDateFormat.isLenient();
140 }
141 }
142
143 /**
144 * Overrides hashCode
145 */
146 public int hashCode() {
147 synchronized(internalDateFormat) {
148 return internalDateFormat.hashCode();
149 }
150 }
151
152 /**
153 * Overrides equals
154 */
155 public boolean equals(Object obj) {
156 if (this == obj) {
157 return true;
158 }
159 if (obj == null || getClass() != obj.getClass()) {
160 return false;
161 }
162 synchronized(internalDateFormat) {
163 return internalDateFormat.equals(obj);
164 }
165 }
166
167 }