View Javadoc

1   /*
2    * Copyright (C) 2006  Tom Gibara
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17   */
18  package com.tomgibara.pronto.config.impl;
19  
20  import java.util.HashMap;
21  
22  /**
23   * This class can be used to create canonical ConfigKey instances. Factories
24   * guarantee that object equality implies referential equality for all keys
25   * created by a factory or obtained as parents to such keys. Creating new keys
26   * from a factory may be slower than constructing them directly.
27   * 
28   * Unless read-only, use of this class must be externally synchronized.
29   * 
30   * Note the present implementation maintains a map of configuration key
31   * instances that prevents them from being garbage collected. This means that
32   * the map will grow without bound under some circumstances.
33   * 
34   * @author Tom Gibara
35   * 
36   */
37  
38  class ConfigKeyFactory {
39  
40      /**
41       * Maps paths to key instances with matching paths.
42       */
43  
44      private final HashMap<String, ConfigKey> keys = new HashMap<String, ConfigKey>();
45  
46      /**
47       * Indicates that the factory should not create any more keys. This field is
48       * volatile so that a previously read-only factory can be made read/write
49       * while threads concurrently call the newKey method.
50       */
51  
52      private volatile boolean readOnly = false;
53  
54      // accessors
55  
56      /**
57       * Whether the factory is in a read-only state. Read-only factories will not
58       * create new keys and as a result may return null from the newKey method.
59       * Conversely, read-only factories are safe for concurrent use.
60       * 
61       * @return true if the factory will not create any new keys, false otherwise
62       */
63  
64      public boolean isReadOnly() {
65          return readOnly;
66      }
67  
68      /**
69       * Changes the read-only status of the factory.
70       * 
71       * @param readOnly
72       *            whether the factory should be read-only or not
73       */
74  
75      public void setReadOnly(final boolean readOnly) {
76          this.readOnly = readOnly;
77      }
78  
79      // methods
80  
81      /**
82       * Creates a new key, or returns a previously created one. If the factory is
83       * in a read-only state, then existing keys will be returned from this
84       * method, but new keys are never created.
85       * 
86       * @param path
87       *            the path of the key to create, never null
88       * @return a key with that path, or null
89       */
90  
91      public ConfigKey newKey(final String path) {
92          // test for read-only status first to avoid possible dirty get on map
93          if (readOnly) return keys.get(path);
94  
95          ConfigKey key = keys.get(path);
96          if (key == null) {
97              key = new ConfigKey(this, path);
98              keys.put(path, key);
99          }
100         return key;
101     }
102 
103     /**
104      * Resets the factory to its original state. This means that the factory is
105      * not read-only and has no record of any keys it has previously generated.
106      * 
107      * Calls to this method must be externally synchronized in all cases.
108      */
109 
110     public void reset() {
111         readOnly = false;
112         keys.clear();
113     }
114 
115 }