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