View Javadoc

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                 // no need to parse properties as not used (for now at least)
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 }