1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You 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 implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef _LOG4CXX_HELPERS_CACHED_DATE_FORMAT_H
19 #define _LOG4CXX_HELPERS_CACHED_DATE_FORMAT_H
20 
21 #include <log4cxx/helpers/dateformat.h>
22 
23 #if defined(_MSC_VER)
24 	#pragma warning ( push )
25 	#pragma warning ( disable: 4251 )
26 #endif
27 
28 namespace log4cxx
29 {
30 namespace pattern
31 {
32 class LOG4CXX_EXPORT CachedDateFormat : public log4cxx::helpers::DateFormat
33 {
34 	public:
35 		enum
36 		{
37 			/*
38 			 *  Constant used to represent that there was no change
39 			 *  observed when changing the millisecond count.
40 			 */
41 			NO_MILLISECONDS = -2,
42 			/*
43 			 *  Constant used to represent that there was an
44 			 *  observed change, but was an expected change.
45 			 */
46 			UNRECOGNIZED_MILLISECONDS = -1
47 		};
48 
49 	private:
50 		/**
51 		 *  Supported digit set.  If the wrapped DateFormat uses
52 		 *  a different unit set, the millisecond pattern
53 		 *  will not be recognized and duplicate requests
54 		 *  will use the cache.
55 		 */
56 		static const logchar digits[];
57 
58 
59 		/**
60 		 * First magic number (in microseconds) used to detect
61 		 * the millisecond position.
62 		 */
63 		static const int magic1;
64 
65 
66 		/**
67 		 *  Expected representation of first magic number in milliseconds.
68 		 */
69 		static const logchar magicString1[];
70 
71 
72 		/**
73 		 * Second magic number (in microseconds) used to detect
74 		 * the millisecond position.
75 		 */
76 		static const int magic2;
77 
78 
79 		/**
80 		 *  Expected representation of second magic number in milliseconds.
81 		 */
82 		static const logchar magicString2[];
83 
84 
85 		/**
86 		 *  Expected representation of 0 milliseconds.
87 		 */
88 		static const logchar zeroString[];
89 
90 		/**
91 		 *   Wrapped formatter.
92 		 */
93 		log4cxx::helpers::DateFormatPtr formatter;
94 
95 		/**
96 		 *  Index of initial digit of millisecond pattern or
97 		 *   UNRECOGNIZED_MILLISECONDS or NO_MILLISECONDS.
98 		 */
99 		mutable int millisecondStart;
100 
101 		/**
102 		 *  Integral second preceding the previous convered Date.
103 		 */
104 		mutable log4cxx_time_t slotBegin;
105 
106 
107 		/**
108 		 *  Cache of previous conversion.
109 		 */
110 		mutable LogString cache;
111 
112 
113 		/**
114 		 *  Maximum validity period for the cache.
115 		 *  Typically 1, use cache for duplicate requests only, or
116 		 *  1000000, use cache for requests within the same integral second.
117 		 */
118 		const int expiration;
119 
120 		/**
121 		 *  Date requested in previous conversion.
122 		 */
123 		mutable log4cxx_time_t previousTime;
124 
125 	public:
126 		/**
127 		 *  Creates a new CachedDateFormat object.
128 		 *  @param dateFormat Date format, may not be null.
129 		 *  @param expiration maximum cached range in microseconds.
130 		 *    If the dateFormat is known to be incompatible with the
131 		 *      caching algorithm, use a value of 0 to totally disable
132 		 *      caching or 1 to only use cache for duplicate requests.
133 		 */
134 		CachedDateFormat(const log4cxx::helpers::DateFormatPtr& dateFormat, int expiration);
135 
136 		/**
137 		 * Finds start of millisecond field in formatted time.
138 		 * @param time long time, must be integral number of seconds
139 		 * @param formatted String corresponding formatted string
140 		 * @param formatter DateFormat date format
141 		 * @param pool pool.
142 		 * @return int position in string of first digit of milliseconds,
143 		 *    -1 indicates no millisecond field, -2 indicates unrecognized
144 		 *    field (likely RelativeTimeDateFormat)
145 		 */
146 		static int findMillisecondStart(
147 			log4cxx_time_t time, const LogString& formatted,
148 			const log4cxx::helpers::DateFormatPtr& formatter,
149 			log4cxx::helpers::Pool& pool);
150 
151 		/**
152 		 * Formats a Date into a date/time string.
153 		 *
154 		 *  @param date the date to format.
155 		 *  @param sbuf the string buffer to write to.
156 		 *  @param p memory pool.
157 		 */
158 		virtual void format(LogString& sbuf,
159 			log4cxx_time_t date,
160 			log4cxx::helpers::Pool& p) const;
161 
162 	private:
163 		/**
164 		 *   Formats a count of milliseconds (0-999) into a numeric representation.
165 		 *   @param millis Millisecond coun between 0 and 999.
166 		 *   @buf String buffer, may not be null.
167 		 *   @offset Starting position in buffer, the length of the
168 		 *       buffer must be at least offset + 3.
169 		 */
170 		static void millisecondFormat(int millis,
171 			LogString& buf,
172 			int offset);
173 
174 
175 	public:
176 		/**
177 		 * Set timezone.
178 		 *
179 		 * @remarks Setting the timezone using getCalendar().setTimeZone()
180 		 * will likely cause caching to misbehave.
181 		 * @param zone TimeZone new timezone
182 		 */
183 		virtual void setTimeZone(const log4cxx::helpers::TimeZonePtr& zone);
184 
185 		/**
186 		* Format an integer consistent with the format method.
187 		* @param s string to which the numeric string is appended.
188 		* @param n integer value.
189 		* @param p memory pool used during formatting.
190 		*/
191 		virtual void numberFormat(LogString& s,
192 			int n,
193 			log4cxx::helpers::Pool& p) const;
194 
195 		/**
196 		 * Gets maximum cache validity for the specified SimpleDateTime
197 		 *    conversion pattern.
198 		 *  @param pattern conversion pattern, may not be null.
199 		 *  @returns Duration in microseconds from an integral second
200 		 *      that the cache will return consistent results.
201 		 */
202 		static int getMaximumCacheValidity(const LogString& pattern);
203 
204 	private:
205 		CachedDateFormat(const CachedDateFormat&);
206 		CachedDateFormat& operator=(const CachedDateFormat&);
207 
208 		/**
209 		* Tests if two string regions are equal.
210 		* @param target target string.
211 		* @param toffset character position in target to start comparison.
212 		* @param other other string.
213 		* @param ooffset character position in other to start comparison.
214 		* @param len length of region.
215 		* @return true if regions are equal.
216 		*/
217 		static bool regionMatches(
218 			const LogString& target,
219 			size_t toffset,
220 			const LogString& other,
221 			size_t ooffset,
222 			size_t len);
223 
224 };
225 
226 
227 
228 }  // namespace helpers
229 } // namespace log4cxx
230 
231 #if defined(_MSC_VER)
232 	#pragma warning (pop)
233 #endif
234 
235 #endif // _LOG4CXX_HELPERS_SIMPLE_DATE_FORMAT_H
236