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
23 import net.sf.ehcache.CacheException;
24 import net.sf.ehcache.search.Query;
25 import net.sf.ehcache.search.attribute.KeyObjectAttributeExtractor;
26 import net.sf.ehcache.search.attribute.ValueObjectAttributeExtractor;
27
28 /***
29 * Search configuration for a Cache
30 *
31 * @author teck
32 */
33 public class Searchable {
34
35 /***
36 * Default for auto-searchable keys
37 */
38 public static final boolean KEYS_DEFAULT = true;
39
40 /***
41 * Default for auto-searchable values
42 */
43 public static final boolean VALUES_DEFAULT = true;
44
45 /***
46 * The defined search attributes (if any) indexed by name
47 */
48 private final Map<String, SearchAttribute> searchAttributes = new HashMap<String, SearchAttribute>();
49 private boolean frozen;
50 private boolean keys;
51 private boolean values;
52
53 /***
54 * Constructor
55 */
56 public Searchable() {
57 setKeys(KEYS_DEFAULT);
58 setValues(VALUES_DEFAULT);
59 }
60
61 /***
62 * Add the given search attribute
63 *
64 * @throws InvalidConfigurationException if an attribute already exists for the same name
65 * @param searchAttribute to add
66 */
67 public void addSearchAttribute(SearchAttribute searchAttribute) throws InvalidConfigurationException {
68 checkDynamicChange();
69
70 String attributeName = searchAttribute.getName();
71
72 if (attributeName == null) {
73 throw new InvalidConfigurationException("Search attribute has null name");
74 }
75
76 disallowBuiltins(attributeName);
77
78 if (searchAttributes.containsKey(attributeName)) {
79 throw new InvalidConfigurationException("Repeated searchAttribute name: " + attributeName);
80 }
81
82 searchAttributes.put(attributeName, searchAttribute);
83 }
84
85 private void disallowBuiltins(String attributeName) {
86 if (Query.KEY.getAttributeName().equals(attributeName) || Query.VALUE.getAttributeName().equals(attributeName)) {
87 throw new InvalidConfigurationException("\"" + attributeName + "\" is a reserved attribute name");
88 }
89 }
90
91 private void checkDynamicChange() {
92 if (frozen) {
93 throw new CacheException("Dynamic configuration changes are disabled for this cache");
94 }
95 }
96
97 /***
98 * Get the defined search attributes indexed by attribute name
99 *
100 * @return search attributes
101 */
102 public Map<String, SearchAttribute> getSearchAttributes() {
103 return Collections.unmodifiableMap(searchAttributes);
104 }
105
106 /***
107 * Add a search attribute
108 *
109 * @param searchAttribute attribute to add
110 * @return this
111 */
112 public Searchable searchAttribute(SearchAttribute searchAttribute) {
113 addSearchAttribute(searchAttribute);
114 return this;
115 }
116
117 /***
118 * Freeze this configuration. Any subsequent changes will throw a CacheException
119 */
120 public void freezeConfiguration() {
121 frozen = true;
122 }
123
124 /***
125 * Get the defined search attributes indexed by attribute name *excluding* any search attributes that are automatically/implicitly
126 * defined (eg. key and value attributes)
127 *
128 * @return search attributes
129 */
130 public Map<String, SearchAttribute> getUserDefinedSearchAttributes() {
131 Map<String, SearchAttribute> copy = new HashMap<String, SearchAttribute>(searchAttributes);
132 copy.remove(Query.KEY.getAttributeName());
133 copy.remove(Query.VALUE.getAttributeName());
134 return copy;
135 }
136
137 /***
138 * Are keys searchable?
139 *
140 * @return true if keys are searchable
141 */
142 public boolean keys() {
143 return keys;
144 }
145
146 /***
147 * Are values searchable?
148 *
149 * @return true if values are searchable
150 */
151 public boolean values() {
152 return values;
153 }
154
155 /***
156 * Toggle searchable values
157 *
158 * @param b
159 */
160 public void values(boolean b) {
161 setValues(b);
162 }
163
164 /***
165 * Toggle searchable keys
166 *
167 * @param b
168 */
169 public void keys(boolean b) {
170 setKeys(b);
171 }
172
173 /***
174 * Toggle searchable keys
175 *
176 * @param keys
177 */
178 public void setKeys(boolean keys) {
179 checkDynamicChange();
180 this.keys = keys;
181 if (!keys) {
182 searchAttributes.remove(Query.KEY.getAttributeName());
183 } else {
184 String keyAttr = Query.KEY.getAttributeName();
185 searchAttributes.put(keyAttr, new SearchAttribute().name(keyAttr).className(KeyObjectAttributeExtractor.class.getName()));
186 }
187 }
188
189 /***
190 * Toggle searchable values
191 *
192 * @param values
193 */
194 public void setValues(boolean values) {
195 checkDynamicChange();
196 this.values = values;
197 if (!values) {
198 searchAttributes.remove(Query.VALUE.getAttributeName());
199 } else {
200 String valueAttr = Query.VALUE.getAttributeName();
201 searchAttributes.put(valueAttr, new SearchAttribute().name(valueAttr).className(ValueObjectAttributeExtractor.class.getName()));
202 }
203 }
204 }