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 }