1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.config;
18
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Properties;
23
24 import net.sf.ehcache.CacheException;
25 import net.sf.ehcache.constructs.nonstop.NonstopTimeoutBehaviorFactory;
26 import net.sf.ehcache.constructs.nonstop.store.ExceptionOnTimeoutStore;
27 import net.sf.ehcache.constructs.nonstop.store.LocalReadsOnTimeoutStore;
28 import net.sf.ehcache.constructs.nonstop.store.NoOpOnTimeoutStore;
29 import net.sf.ehcache.util.ClassLoaderUtil;
30
31 /***
32 * Configuration element for configuring timeoutBehavior for nonstop
33 *
34 * @author Abhishek Sanoujam
35 *
36 */
37 public class TimeoutBehaviorConfiguration implements Cloneable {
38 /***
39 * Type name for {@link TimeoutBehaviorType#EXCEPTION}
40 */
41 public static final String EXCEPTION_TYPE_NAME = "exception";
42 /***
43 * Type name for {@link TimeoutBehaviorType#LOCAL_READS}
44 */
45 public static final String LOCAL_READS_TYPE_NAME = "localReads";
46 /***
47 * Type name for {@link TimeoutBehaviorType#NOOP}
48 */
49 public static final String NOOP_TYPE_NAME = "noop";
50 /***
51 * Type name for {@link TimeoutBehaviorType#CUSTOM}
52 */
53 public static final String CUSTOM_TYPE_NAME = "custom";
54
55 /***
56 * Property name used to configure the class name of the factory class used by {@link TimeoutBehaviorType#CUSTOM}
57 */
58 public static final String CUSTOM_TYPE_FACTORY_PROPERTY_NAME = "customFactoryClassName";
59
60 /***
61 * Enum encapsulating type of TimeoutBehavior
62 *
63 * @author Abhishek Sanoujam
64 *
65 */
66 public static enum TimeoutBehaviorType {
67 /***
68 * Timeout behavior type that throws exception on timeout
69 */
70 EXCEPTION() {
71
72 /***
73 * {@inheritDoc}
74 */
75 @Override
76 public String getTypeName() {
77 return EXCEPTION_TYPE_NAME;
78 }
79
80 /***
81 * {@inheritDoc}
82 */
83 @Override
84 public NonstopTimeoutBehaviorFactory getTimeoutBehaviorFactory(Properties properties) {
85 return ExceptionOnTimeoutStore.FACTORY;
86 }
87
88 },
89 /***
90 * Timeout behavior type that returns null and does nothing on timeout
91 */
92 NOOP() {
93
94 /***
95 * {@inheritDoc}
96 */
97 @Override
98 public String getTypeName() {
99 return NOOP_TYPE_NAME;
100 }
101
102 /***
103 * {@inheritDoc}
104 */
105 @Override
106 public NonstopTimeoutBehaviorFactory getTimeoutBehaviorFactory(Properties properties) {
107 return NoOpOnTimeoutStore.FACTORY;
108 }
109
110 },
111 /***
112 * Timeout behavior type that returns local values present in the VM or otherwise null on timeout
113 */
114 LOCAL_READS() {
115
116 /***
117 * {@inheritDoc}
118 */
119 @Override
120 public String getTypeName() {
121 return LOCAL_READS_TYPE_NAME;
122 }
123
124 /***
125 * {@inheritDoc}
126 */
127 @Override
128 public NonstopTimeoutBehaviorFactory getTimeoutBehaviorFactory(Properties properties) {
129 return LocalReadsOnTimeoutStore.FACTORY;
130 }
131 },
132 /***
133 * Timeout behavior type that uses a custom factory to create the actual timeout behavior on timeout. The custom factory has to be
134 * configured using properties otherwise an exception will be thrown. There must be a property named
135 * {@link TimeoutBehaviorConfiguration#CUSTOM_TYPE_FACTORY_PROPERTY_NAME} whose value is the
136 * fully qualified name of a class that implements {@link NonstopTimeoutBehaviorFactory} having no-args constructor.
137 */
138 CUSTOM() {
139
140 /***
141 * {@inheritDoc}
142 */
143 @Override
144 public String getTypeName() {
145 return CUSTOM_TYPE_NAME;
146 }
147
148 /***
149 * {@inheritDoc}
150 */
151 @Override
152 public NonstopTimeoutBehaviorFactory getTimeoutBehaviorFactory(Properties properties) {
153 if (properties == null || !properties.containsKey(CUSTOM_TYPE_FACTORY_PROPERTY_NAME)) {
154 throw new CacheException("When using " + getTypeName() + " timeout behavior type, need to set properties with key '"
155 + CUSTOM_TYPE_FACTORY_PROPERTY_NAME + "', specified properties: " + (properties == null ? "NULL" : properties));
156 }
157 final String customFactoryClassName = properties.getProperty(CUSTOM_TYPE_FACTORY_PROPERTY_NAME);
158 Object factory = ClassLoaderUtil.createNewInstance(customFactoryClassName);
159 if (!(factory instanceof NonstopTimeoutBehaviorFactory)) {
160 throw new CacheException("The factory '" + customFactoryClassName + "' is NOT an instance of "
161 + NonstopTimeoutBehaviorFactory.class.getName());
162 }
163 return (NonstopTimeoutBehaviorFactory) factory;
164 }
165 };
166
167 /***
168 * Returns a String signifying this type
169 *
170 * @return the string name for this type
171 */
172 public abstract String getTypeName();
173
174 /***
175 * Get the {@link NonstopTimeoutBehaviorFactory} for this type
176 *
177 * @param properties The configured properties
178 * @return the factory to create timeout behaviors for this type
179 */
180 public abstract NonstopTimeoutBehaviorFactory getTimeoutBehaviorFactory(Properties properties);
181
182 private static final Map<String, TimeoutBehaviorType> TYPE_MAP;
183 static {
184 Map<String, TimeoutBehaviorType> validTypes = new HashMap<String, TimeoutBehaviorType>();
185 for (TimeoutBehaviorType timeoutBehaviorType : TimeoutBehaviorType.values()) {
186 validTypes.put(timeoutBehaviorType.getTypeName(), timeoutBehaviorType);
187 }
188 TYPE_MAP = Collections.unmodifiableMap(validTypes);
189 }
190
191 /***
192 * Find out if a string is a valid timeoutBehavior type or not
193 *
194 * @param type the string name
195 * @return true if its valid, otherwise false
196 */
197 public static boolean isValidTimeoutBehaviorType(String type) {
198 TimeoutBehaviorType timeoutBehaviorType = TYPE_MAP.get(type);
199 return timeoutBehaviorType != null;
200 }
201
202 /***
203 * Get the {@link TimeoutBehaviorType} corresponding to a name
204 *
205 * @param typeName the type name
206 * @return the {@link TimeoutBehaviorType}
207 */
208 public static TimeoutBehaviorType getTimeoutBehaviorTypeFromName(String typeName) {
209 return TYPE_MAP.get(typeName);
210 }
211 }
212
213 /***
214 * Default value for timeout behavior
215 */
216 public static final TimeoutBehaviorType DEFAULT_TIMEOUT_BEHAVIOR_TYPE = TimeoutBehaviorType.EXCEPTION;
217
218 /***
219 * Default value for properties.
220 */
221 public static final String DEFAULT_PROPERTIES = "";
222
223 /***
224 * Default value for property separator
225 */
226 public static final String DEFAULT_PROPERTY_SEPARATOR = ",";
227
228 /***
229 * Default value for timeout behavior
230 */
231 public static final String DEFAULT_VALUE = DEFAULT_TIMEOUT_BEHAVIOR_TYPE.getTypeName();
232
233 private volatile TimeoutBehaviorType type = DEFAULT_TIMEOUT_BEHAVIOR_TYPE;
234 private volatile String properties = DEFAULT_PROPERTIES;
235 private volatile String propertySeparator = DEFAULT_PROPERTY_SEPARATOR;
236
237 /***
238 * Returns the type of timeout behavior configured
239 *
240 * @return the configured type
241 */
242 public String getType() {
243 return type.getTypeName();
244 }
245
246 /***
247 * Returns the type of timeout behavior configured
248 *
249 * @return the configured type
250 */
251 public TimeoutBehaviorType getTimeoutBehaviorType() {
252 return type;
253 }
254
255 /***
256 * Set the type of timeout behavior
257 *
258 * @param type
259 */
260 public void setType(String type) {
261 if (!TimeoutBehaviorType.isValidTimeoutBehaviorType(type)) {
262 throw new CacheException("Invalid value for timeoutBehavior type - '" + type + "'. Valid values are: '"
263 + TimeoutBehaviorType.EXCEPTION.getTypeName() + "', '" + TimeoutBehaviorType.NOOP.getTypeName() + "', '"
264 + TimeoutBehaviorType.LOCAL_READS.getTypeName());
265 }
266 this.type = TimeoutBehaviorType.getTimeoutBehaviorTypeFromName(type);
267 }
268
269 /***
270 * Set the type of timeout behavior
271 *
272 * @param type
273 * @return this instance
274 */
275 public TimeoutBehaviorConfiguration type(String type) {
276 this.setType(type);
277 return this;
278 }
279
280 /***
281 * Get the properties
282 *
283 * @return properties
284 */
285 public String getProperties() {
286 return properties;
287 }
288
289 /***
290 * Set the properties
291 *
292 * @param properties
293 */
294 public void setProperties(String properties) {
295 this.properties = properties;
296 }
297
298 /***
299 * Set the properties
300 *
301 * @param value
302 * @return this instance
303 */
304 public TimeoutBehaviorConfiguration properties(String value) {
305 this.setProperties(value);
306 return this;
307 }
308
309 /***
310 * Get the property separator
311 *
312 * @return the propery separator
313 */
314 public String getPropertySeparator() {
315 return propertySeparator;
316 }
317
318 /***
319 * Set the property separator
320 *
321 * @param propertySeparator
322 */
323 public void setPropertySeparator(String propertySeparator) {
324 this.propertySeparator = propertySeparator;
325 }
326
327 /***
328 * Set the property separator
329 *
330 * @param value
331 * @return this instance
332 */
333 public TimeoutBehaviorConfiguration propertySeparator(String value) {
334 this.setPropertySeparator(value);
335 return this;
336 }
337
338 /***
339 * {@inheritDoc}
340 */
341 @Override
342 public Object clone() throws CloneNotSupportedException {
343 return super.clone();
344 }
345
346 /***
347 * Get the {@link NonstopTimeoutBehaviorFactory} according to the active config
348 *
349 * @return the nonstopTimeoutBehaviorFactory
350 */
351 public NonstopTimeoutBehaviorFactory getNonstopTimeoutBehaviorFactory() {
352 switch (type) {
353 case EXCEPTION:
354 case NOOP:
355 case LOCAL_READS:
356
357 return type.getTimeoutBehaviorFactory(null);
358 case CUSTOM:
359 return type.getTimeoutBehaviorFactory(extractProperties());
360 default:
361 throw new CacheException("Unknown timeout behavior type - " + type);
362 }
363 }
364
365 private Properties extractProperties() {
366 final Properties rv = new Properties();
367 final String propertiesString = this.properties;
368 final String sep = this.propertySeparator;
369 String[] props = propertiesString.split(propertySeparator);
370 for (String prop : props) {
371 String[] nvPair = prop.split("=");
372 if (nvPair == null || nvPair.length != 2) {
373 throw new InvalidConfigurationException("Property not specified correctly. Failed to parse: " + prop);
374 }
375 rv.setProperty(nvPair[0], nvPair[1]);
376 }
377 return rv;
378 }
379
380 }