File Source: ConfigManager.java
1 /*
2 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 package com.dmdirc.config;
24
25 import com.dmdirc.interfaces.ConfigChangeListener;
26 import com.dmdirc.util.MapList;
27
28 import java.io.Serializable;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import java.util.TreeMap;
37
38 /**
39 * The config manager manages the various config sources for each entity.
40 *
41 * @author chris
42 */
43 public class ConfigManager extends ConfigSource implements Serializable,
44 ConfigChangeListener {
45
46 /**
47 * A version number for this class. It should be changed whenever the class
48 * structure is changed (or anything else that would prevent serialized
49 * objects being unserialized with the new class).
50 */
51 private static final long serialVersionUID = 4;
52
53 /** Temporary map for lookup stats. */
/*
P/P * Method: com.dmdirc.config.ConfigManager__static_init
*
* Postconditions:
* stats == &new TreeMap(ConfigManager__static_init#1)
* new TreeMap(ConfigManager__static_init#1) num objects == 1
*/
54 private static final Map<String, Integer> stats = new TreeMap<String, Integer>();
55
56 /** A list of sources for this config manager. */
57 private final List<Identity> sources;
58
59 /** The listeners registered for this manager. */
60 private final MapList<String, ConfigChangeListener> listeners
61 = new MapList<String, ConfigChangeListener>();
62
63 /** The ircd this manager is for. */
64 private String ircd;
65 /** The network this manager is for. */
66 private String network;
67 /** The server this manager is for. */
68 private String server;
69 /** The channel this manager is for. */
70 private String channel;
71
72 /**
73 * Creates a new instance of ConfigManager.
74 *
75 * @param ircd The name of the ircd for this manager
76 * @param network The name of the network for this manager
77 * @param server The name of the server for this manager
78 */
79 public ConfigManager(final String ircd, final String network,
80 final String server) {
/*
P/P * Method: void com.dmdirc.config.ConfigManager(String, String, String)
*
* Preconditions:
* (soft) init'ed(com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...])
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == network._tainted
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* this.channel == &java.lang.StringBuilder:toString(...)
* this.ircd == ircd
* init'ed(this.ircd)
* this.listeners == &new MapList(ConfigManager#1)
* this.network == network
* init'ed(this.network)
* this.server == server
* init'ed(this.server)
* ...
*/
81 this(ircd, network, server, "<Unknown>");
82 }
83
84 /**
85 * Creates a new instance of ConfigManager.
86 *
87 * @param ircd The name of the ircd for this manager
88 * @param network The name of the network for this manager
89 * @param server The name of the server for this manager
90 * @param channel The name of the channel for this manager
91 */
92 public ConfigManager(final String ircd, final String network,
/*
P/P * Method: void com.dmdirc.config.ConfigManager(String, String, String, String)
*
* Preconditions:
* (soft) init'ed(com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...])
*
* Presumptions:
* identity.listeners@102 != null
* java.util.Iterator:next(...)@102 != null
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == channel._tainted | network._tainted
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* this.channel == &java.lang.StringBuilder:toString(...)
* this.ircd == ircd
* init'ed(this.ircd)
* this.listeners == &new MapList(ConfigManager#1)
* this.network == network
* init'ed(this.network)
* this.server == server
* init'ed(this.server)
* ...
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@102: {0}, {1}
*/
93 final String server, final String channel) {
94 final String chanName = channel + "@" + network;
95 this.ircd = ircd;
96 this.network = network;
97 this.server = server;
98 this.channel = chanName;
99
100 sources = IdentityManager.getSources(this);
101
102 for (Identity identity : sources) {
103 identity.addListener(this);
104 }
105
106 IdentityManager.addConfigManager(this);
107 }
108
109 /** {@inheritDoc} */
110 @Override
111 public String getOption(final String domain, final String option) {
/*
P/P * Method: String getOption(String, String)
*
* Preconditions:
* this.sources != null
*
* Presumptions:
* java.util.Iterator:hasNext(...)@115 == 1
* java.util.Iterator:next(...)@115 != null
* source.file@115 != null
*
* Postconditions:
* init'ed(return_value)
*/
112 doStats(domain, option);
113
114 synchronized (sources) {
115 for (Identity source : sources) {
116 if (source.hasOption(domain, option)) {
117 return source.getOption(domain, option);
118 }
119 }
120 }
121
122 throw new IllegalArgumentException("Config option not found: " + domain + "." + option);
123 }
124
125 /** {@inheritDoc} */
126 @Override
127 protected boolean hasOption(final String domain, final String option) {
/*
P/P * Method: bool hasOption(String, String)
*
* Preconditions:
* this.sources != null
*
* Presumptions:
* java.util.Iterator:next(...)@131 != null
* source.file@131 != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@131: {1}, {0}
*/
128 doStats(domain, option);
129
130 synchronized (sources) {
131 for (Identity source : sources) {
132 if (source.hasOption(domain, option)) {
133 return true;
134 }
135 }
136 }
137
138 return false;
139 }
140
141 /**
142 * Returns the name of all the options in the specified domain. If the
143 * domain doesn't exist, an empty list is returned.
144 *
145 * @param domain The domain to search
146 * @return A list of options in the specified domain
147 */
148 public Map<String, String> getOptions(final String domain) {
/*
P/P * Method: Map getOptions(String)
*
* Preconditions:
* this.sources != null
*
* Presumptions:
* java.util.List:get(...).file@153 != null
* java.util.List:get(...)@153 != null
* java.util.List:size(...)@152 >= -231+1
*
* Postconditions:
* return_value == &new HashMap(getOptions#1)
* new HashMap(getOptions#1) num objects == 1
*/
149 final Map<String, String> res = new HashMap<String, String>();
150
151 synchronized (sources) {
152 for (int i = sources.size() - 1; i >= 0; i--) {
153 res.putAll(sources.get(i).getOptions(domain));
154 }
155 }
156
157 return res;
158 }
159
160 /**
161 * Removes the specified identity from this manager.
162 *
163 * @param identity The identity to be removed
164 */
165 public void removeIdentity(final Identity identity) {
/*
P/P * Method: void removeIdentity(Identity)
*
* Preconditions:
* this.sources != null
* (soft) identity != null
* (soft) identity.file != null
* (soft) identity.listeners != null
* (soft) this.listeners != null
*
* Presumptions:
* java.util.Iterator:next(...)@187 != null
* java.util.Map:keySet(...)@174 != null
* setting.length@187 >= 2
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@173: {0}, {1}
* java.util.Iterator:hasNext(...)@174: {0}, {1}
* java.util.Iterator:hasNext(...)@187: {0}, {1}
* java.util.List:contains(...)@166: {1}, {0}
*/
166 if (!sources.contains(identity)) {
167 return;
168 }
169
170 final List<String[]> changed = new ArrayList<String[]>();
171
172 // Determine which settings will have changed
173 for (String domain : identity.getDomains()) {
174 for (String option : identity.getOptions(domain).keySet()) {
175 if (identity.equals(getScope(domain, option))) {
176 changed.add(new String[]{domain, option});
177 }
178 }
179 }
180
181 synchronized (sources) {
182 identity.removeListener(this);
183 sources.remove(identity);
184 }
185
186 // Fire change listeners
187 for (String[] setting : changed) {
188 configChanged(setting[0], setting[1]);
189 }
190 }
191
192 /**
193 * Retrieves the identity that currently defines the specified domain and
194 * option.
195 *
196 * @param domain The domain to search for
197 * @param option The option to search for
198 * @return The identity that defines that setting, or null on failure
199 */
200 protected Identity getScope(final String domain, final String option) {
/*
P/P * Method: Identity getScope(String, String)
*
* Preconditions:
* this.sources != null
*
* Presumptions:
* java.util.Iterator:next(...)@202 != null
* source.file@202 != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@202: {1}, {0}
*/
201 synchronized (sources) {
202 for (Identity source : sources) {
203 if (source.hasOption(domain, option)) {
204 return source;
205 }
206 }
207 }
208
209 return null;
210 }
211
212 /**
213 * Checks whether the specified identity applies to this config manager.
214 *
215 * @param identity The identity to test
216 * @return True if the identity applies, false otherwise
217 */
218 public boolean identityApplies(final Identity identity) {
219 String comp;
220
/*
P/P * Method: bool identityApplies(Identity)
*
* Preconditions:
* identity != null
* identity.myTarget != null
* identity.myTarget.type != null
* (soft) init'ed(com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...])
* (soft) init'ed(identity.myTarget.data)
* (soft) init'ed(this.channel)
* (soft) init'ed(this.ircd)
* (soft) init'ed(this.network)
* (soft) init'ed(this.server)
*
* Presumptions:
* com.dmdirc.config.ConfigTarget_TYPE:ordinal(...)@221 in {0..7}
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...]: {1}, {2}, {3}, {4}, {5}, {-231..0, 6..232-1}
*/
221 switch (identity.getTarget().getType()) {
222 case IRCD:
223 comp = ircd;
224 break;
225 case NETWORK:
226 comp = network;
227 break;
228 case SERVER:
229 comp = server;
230 break;
231 case CHANNEL:
232 comp = channel;
233 break;
234 case PROFILE:
235 // We don't want profiles
236 comp = null;
237 break;
238 default:
239 comp = "";
240 break;
241 }
242
243 return comp != null && comp.equalsIgnoreCase(identity.getTarget().getData());
244 }
245
246 /**
247 * Called whenever there is a new identity available. Checks if the
248 * identity is relevant for this manager, and adds it if it is.
249 *
250 * @param identity The identity to be checked
251 */
252 public void checkIdentity(final Identity identity) {
/*
P/P * Method: void checkIdentity(Identity)
*
* Preconditions:
* this.sources != null
* (soft) init'ed(com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...])
* (soft) identity != null
* (soft) identity.file != null
* (soft) identity.listeners != null
* (soft) identity.myTarget != null
* (soft) init'ed(identity.myTarget.data)
* (soft) identity.myTarget.type != null
* (soft) init'ed(this.channel)
* (soft) init'ed(this.ircd)
* ...
*
* Presumptions:
* java.util.Map:keySet(...)@262 != null
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@261: {0}, {1}
* java.util.Iterator:hasNext(...)@262: {0}, {1}
* java.util.List:contains(...)@253: {1}, {0}
*/
253 if (!sources.contains(identity) && identityApplies(identity)) {
254 synchronized (sources) {
255 sources.add(identity);
256 identity.addListener(this);
257 Collections.sort(sources);
258 }
259
260 // Determine which settings will have changed
261 for (String domain : identity.getDomains()) {
262 for (String option : identity.getOptions(domain).keySet()) {
263 if (identity.equals(getScope(domain, option))) {
264 configChanged(domain, option);
265 }
266 }
267 }
268 }
269 }
270
271 /**
272 * Returns the name of all domains known by this manager.
273 *
274 * @return A list of domains known to this manager
275 */
276 public Set<String> getDomains() {
/*
P/P * Method: Set getDomains()
*
* Preconditions:
* this.sources != null
*
* Presumptions:
* java.util.Iterator:next(...)@280 != null
* source.file@280 != null
*
* Postconditions:
* return_value == &new HashSet(getDomains#1)
* new HashSet(getDomains#1) num objects == 1
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@280: {1}, {0}
*/
277 final Set<String> res = new HashSet<String>();
278
279 synchronized (sources) {
280 for (Identity source : sources) {
281 res.addAll(source.getDomains());
282 }
283 }
284
285 return res;
286 }
287
288 /**
289 * Retrieves a list of sources for this config manager.
290 * @return This config manager's sources.
291 */
292 public List<Identity> getSources() {
/*
P/P * Method: List getSources()
*
* Postconditions:
* return_value == &new ArrayList(getSources#1)
* new ArrayList(getSources#1) num objects == 1
*/
293 return new ArrayList<Identity>(sources);
294 }
295
296 /**
297 * Migrates this ConfigManager from its current configuration to the
298 * appropriate one for the specified new parameters, firing listeners where
299 * settings have changed.
300 *
301 * @param ircd The new name of the ircd for this manager
302 * @param network The new name of the network for this manager
303 * @param server The new name of the server for this manager
304 */
305 public void migrate(final String ircd, final String network, final String server) {
/*
P/P * Method: void migrate(String, String, String)
*
* Preconditions:
* (soft) init'ed(com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...])
* (soft) this.listeners != null
* (soft) this.sources != null
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == network._tainted
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* this.channel == &java.lang.StringBuilder:toString(...)
* this.ircd == ircd
* init'ed(this.ircd)
* this.network == network
* init'ed(this.network)
* this.server == server
* init'ed(this.server)
*/
306 migrate(ircd, network, server, "<Unknown>");
307 }
308
309 /**
310 * Migrates this ConfigManager from its current configuration to the
311 * appropriate one for the specified new parameters, firing listeners where
312 * settings have changed.
313 *
314 * @param ircd The new name of the ircd for this manager
315 * @param network The new name of the network for this manager
316 * @param server The new name of the server for this manager
317 * @param channel The new name of the channel for this manager
318 */
319 public void migrate(final String ircd, final String network, final String server,
320 final String channel) {
/*
P/P * Method: void migrate(String, String, String, String)
*
* Preconditions:
* (soft) init'ed(com.dmdirc.config.ConfigManager$1__static_init.new int[](ConfigManager$1__static_init#1)[...])
* (soft) this.listeners != null
* (soft) this.sources != null
*
* Presumptions:
* identity.file@326 != null
* identity.file@333 != null
* identity.listeners@326 != null
* identity.listeners@333 != null
* identity.myTarget.type@326 != null
* ...
*
* Postconditions:
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* this.channel == &java.lang.StringBuilder:toString(...)
* this.ircd == ircd
* init'ed(this.ircd)
* this.network == network
* init'ed(this.network)
* this.server == server
* init'ed(this.server)
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@326: {0}, {1}
* java.util.Iterator:hasNext(...)@333: {0}, {1}
*/
321 this.ircd = ircd;
322 this.network = network;
323 this.server = server;
324 this.channel = channel + "@" + network;
325
326 for (Identity identity : new ArrayList<Identity>(sources)) {
327 if (!identityApplies(identity)) {
328 removeIdentity(identity);
329 }
330 }
331
332 final List<Identity> newSources = IdentityManager.getSources(this);
333 for (Identity identity : newSources) {
334 checkIdentity(identity);
335 }
336 }
337
338 /**
339 * Records the lookup request for the specified domain & option.
340 *
341 * @param domain The domain that is being looked up
342 * @param option The option that is being looked up
343 */
344 protected static void doStats(final String domain, final String option) {
/*
P/P * Method: void doStats(String, String)
*
* Presumptions:
* java.lang.Integer:intValue(...)@348 <= 232-2
* java.util.Map:get(...)@348 != null
*/
345 final String key = domain + "." + option;
346
347 try {
348 stats.put(key, 1 + (stats.containsKey(key) ? stats.get(key) : 0));
349 } catch (NullPointerException ex) {
350 // JVM bugs ftl.
351 }
352 }
353
354 /**
355 * Retrieves the statistic map.
356 *
357 * @return A map of config options to lookup counts
358 */
359 public static Map<String, Integer> getStats() {
/*
P/P * Method: Map getStats()
*
* Postconditions:
* return_value == &new TreeMap(ConfigManager__static_init#1)
*/
360 return stats;
361 }
362
363 /**
364 * Adds a change listener for the specified domain.
365 *
366 * @param domain The domain to be monitored
367 * @param listener The listener to register
368 */
369 public void addChangeListener(final String domain,
370 final ConfigChangeListener listener) {
/*
P/P * Method: void addChangeListener(String, ConfigChangeListener)
*
* Preconditions:
* this.listeners != null
*/
371 addListener(domain, listener);
372 }
373
374 /**
375 * Adds a change listener for the specified domain and key.
376 *
377 * @param domain The domain of the option
378 * @param key The option to be monitored
379 * @param listener The listener to register
380 */
381 public void addChangeListener(final String domain, final String key,
382 final ConfigChangeListener listener) {
/*
P/P * Method: void addChangeListener(String, String, ConfigChangeListener)
*
* Preconditions:
* this.listeners != null
*/
383 addListener(domain + "." + key, listener);
384 }
385
386 /**
387 * Removes the specified listener for all domains and options.
388 *
389 * @param listener The listener to be removed
390 */
391 public void removeListener(final ConfigChangeListener listener) {
/*
P/P * Method: void removeListener(ConfigChangeListener)
*
* Preconditions:
* this.listeners != null
*/
392 synchronized (listeners) {
393 listeners.removeFromAll(listener);
394 }
395 }
396
397 /**
398 * Adds the specified listener to the internal map/list.
399 *
400 * @param key The key to use (domain or domain.key)
401 * @param listener The listener to register
402 */
403 private void addListener(final String key,
404 final ConfigChangeListener listener) {
/*
P/P * Method: void addListener(String, ConfigChangeListener)
*
* Preconditions:
* this.listeners != null
*/
405 synchronized (listeners) {
406 listeners.add(key, listener);
407 }
408 }
409
410 /** {@inheritDoc} */
411 @Override
412 public void configChanged(final String domain, final String key) {
/*
P/P * Method: void configChanged(String, String)
*
* Preconditions:
* this.listeners != null
*
* Presumptions:
* java.util.Iterator:next(...)@424 != null
*
* Test Vectors:
* com.dmdirc.util.MapList:containsKey(...)@416: {0}, {1}
* com.dmdirc.util.MapList:containsKey(...)@420: {0}, {1}
* java.util.Iterator:hasNext(...)@424: {0}, {1}
*/
413 final List<ConfigChangeListener> targets
414 = new ArrayList<ConfigChangeListener>();
415
416 if (listeners.containsKey(domain)) {
417 targets.addAll(listeners.get(domain));
418 }
419
420 if (listeners.containsKey(domain + "." + key)) {
421 targets.addAll(listeners.get(domain + "." + key));
422 }
423
424 for (ConfigChangeListener listener : targets) {
425 listener.configChanged(domain, key);
426 }
427 }
428 }
SofCheck Inspector Build Version : 2.17854
| ConfigManager.java |
2009-Jun-25 01:54:24 |
| ConfigManager.class |
2009-Sep-02 17:04:17 |
| ConfigManager$1.class |
2009-Sep-02 17:04:17 |