1 /*
2 * JBoss, the OpenSource J2EE webOS
3 *
4 * Distributable under LGPL license.
5 * See terms of license at gnu.org.
6 */
7 package net.sf.panoptes.model.component.registry;
8
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import java.util.Hashtable;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.Map;
15
16 import net.sf.panoptes.model.component.Component;
17 import net.sf.panoptes.model.node.Node;
18
19 import org.apache.log4j.Logger;
20
21 /***
22 * The registry for component name - component reference mapping. Original code
23 * from JBoss.
24 *
25 * @see net.sf.panoptes.model.component.IComponent
26 * @see net.sf.panoptes.model.component.registry.ComponentEntry
27 *
28 */
29 public class ComponentRegistry {
30 // Attributes ----------------------------------------------------
31
32 /***
33 * A map of domain name to another map containing object name canonical
34 * key properties to registry entries.
35 * domain -> canonicalKeyProperties -> MBeanEntry
36 */
37 private Map domainMap = new HashMap();
38
39 /***
40 * The default domain for this registry
41 */
42 private String defaultDomain;
43
44 /***
45 * Sequence number for the MBeanComponent server registration notifications.
46 */
47 private long registrationNotificationSequence = 1;
48
49 /***
50 * Sequence number for the MBeanComponent server unregistration notifications.
51 */
52 private long unregistrationNotificationSequence = 1;
53
54 // Static --------------------------------------------------------
55
56 /***
57 * The logger
58 */
59 private static Logger log = Logger.getLogger(ComponentRegistry.class);
60
61 // Constructors --------------------------------------------------
62
63 /***
64 * Constructs a new ComponentRegistry.<p>
65 *
66 */
67 public ComponentRegistry() {
68 }
69
70 // MBeanRegistry Implementation ----------------------------------
71
72 public void registerComponent(Component component, ComponentName name)
73 throws ComponentAlreadyExistsException {
74 boolean registrationDone = true;
75 ComponentName regName = name;
76 try {
77 regName = validateAndQualifyName(regName);
78
79 try {
80
81 ComponentEntry entry = new ComponentEntry(regName, component);
82 add(entry);
83 component.setComponentName(name);
84 component.setComponentRegistry(this);
85 component.init();
86
87 try {
88 long sequence;
89 synchronized (this) {
90 sequence = registrationNotificationSequence++;
91 }
92
93 } catch (Throwable t) {
94 // Problem, remove the mbean from the registry
95 remove(regName);
96
97 throw t;
98 }
99 }
100 // Thrown by the registry
101 catch (ComponentAlreadyExistsException e) {
102 throw e;
103 } catch (Throwable t) {
104 // Something is broken
105 log.error("Unexpected Exception:", t);
106
107 throw t;
108 }
109 } catch (ComponentAlreadyExistsException e) {
110 // It was already registered
111 registrationDone = false;
112 throw e;
113 } catch (Throwable t) {
114 // Some other error
115 registrationDone = false;
116 }
117 }
118
119 public void unregisterMBean(ComponentName name) throws ComponentNotFoundException {
120 ComponentEntry entry = get(name);
121 Object resource = entry.getComponent();
122
123 // It is no longer registered
124 remove(name);
125 }
126
127 public synchronized ComponentEntry get(ComponentName name) throws ComponentNotFoundException {
128 if (name == null)
129 throw new ComponentNotFoundException("null object name");
130
131 // Determine the domain and retrieve its entries
132 String domain = name.getDomain();
133
134 if (domain.length() == 0)
135 domain = defaultDomain;
136
137 String props = name.getCanonicalKeyPropertyListString();
138 Map mbeanMap = (Map) domainMap.get(domain);
139
140 // Retrieve the mbean entry
141 Object o = null;
142 if (null == mbeanMap || null == (o = mbeanMap.get(props)))
143 throw new ComponentNotFoundException(name + " is not registered.");
144
145 // We are done
146 return (ComponentEntry) o;
147 }
148
149 public String getDefaultDomain() {
150 return defaultDomain;
151 }
152
153 public synchronized Node getObjectInstance(ComponentName name) throws ComponentNotFoundException {
154 if (!contains(name))
155 throw new ComponentNotFoundException(name + " not registered.");
156
157 return get(name).getComponent();
158 }
159
160
161 public synchronized boolean contains(ComponentName name) {
162 // null safety check
163 if (name == null)
164 return false;
165
166 // Determine the domain and retrieve its entries
167 String domain = name.getDomain();
168
169 if (domain.length() == 0)
170 domain = defaultDomain;
171
172 String props = name.getCanonicalKeyPropertyListString();
173 Map mbeanMap = (Map) domainMap.get(domain);
174
175 // Return the result
176 return (null != mbeanMap && mbeanMap.containsKey(props));
177 }
178
179 public synchronized int getSize() {
180 int retval = 0;
181
182 for (Iterator iterator = domainMap.values().iterator(); iterator.hasNext();) {
183 retval += ((Map) iterator.next()).size();
184 }
185 return retval;
186 }
187
188 public synchronized List findEntries(ComponentName pattern) {
189 ArrayList retval = new ArrayList();
190
191 // There are a couple of shortcuts we can employ to make this a
192 // bit faster - they're commented.
193
194 // First, if pattern == null or pattern.getCanonicalName() == "*:*" we want the
195 // set of all MBeans.
196 if (pattern == null || pattern.getCanonicalName().equals("*:*")) {
197 for (Iterator domainIter = domainMap.values().iterator(); domainIter.hasNext();) {
198 for (Iterator mbeanIter = ((Map) domainIter.next()).values().iterator(); mbeanIter.hasNext();) {
199 retval.add(mbeanIter.next());
200 }
201 }
202 }
203 // Next, if !pattern.isPattern() then we are doing a simple get (maybe defaultDomain).
204 else if (!pattern.isPattern()) {
205 // simple get
206 try {
207 retval.add(get(pattern));
208 } catch (ComponentNotFoundException e) {
209 // we don't care
210 }
211 }
212 // Now we have to do a brute force, oh well.
213 else {
214 String patternDomain = pattern.getDomain();
215 if (patternDomain.length() == 0)
216 patternDomain = defaultDomain;
217 boolean patternIsPropertyPattern = true; pattern.isPropertyPattern();
218 String patternCanonicalKPS = pattern.getCanonicalKeyPropertyListString();
219 Object[] propkeys = null;
220 Object[] propvals = null;
221
222 // prebuild arrays of keys and values for quick comparison
223 // when isPropertyPattern().
224 if (patternIsPropertyPattern) {
225 Hashtable patternKPList = pattern.getKeyPropertyList();
226 propkeys = new Object[patternKPList.size()];
227 propvals = new Object[propkeys.length];
228
229 int i = 0;
230 for (Iterator iterator = patternKPList.entrySet().iterator(); iterator.hasNext(); i++) {
231 Map.Entry mapEntry = (Map.Entry) iterator.next();
232 propkeys[i] = mapEntry.getKey();
233 propvals[i] = mapEntry.getValue();
234 }
235 }
236
237 // Here we go, step through every domain and see if our pattern matches before optionally checking
238 // each ObjectName's properties for a match.
239 for (Iterator domainIter = domainMap.entrySet().iterator(); domainIter.hasNext();) {
240 Map.Entry mapEntry = (Map.Entry) domainIter.next();
241 if (domainMatches((String) mapEntry.getKey(), patternDomain)) {
242 // yes it's a label, sue me.
243 CHOOSE_MBEAN : for (
244 Iterator mbeanIter = ((Map) mapEntry.getValue()).values().iterator(); mbeanIter.hasNext();) {
245 ComponentEntry entry = (ComponentEntry) mbeanIter.next();
246 ComponentName name = entry.getComponentName();
247
248 if (patternIsPropertyPattern) {
249 // another shortcut - we only compare the key properties list of the registered MBeanComponent
250 // if properties have been specifed in the pattern (i.e. something other than just "*")
251 if (propkeys.length > 0) {
252 Hashtable nameKPList = name.getKeyPropertyList();
253
254 for (int i = 0; i < propkeys.length; i++) {
255 // skip the current MBeanComponent if there isn't a match
256 if (!propvals[i].equals(nameKPList.get(propkeys[i]))) {
257 continue CHOOSE_MBEAN;
258 }
259 }
260 }
261 retval.add(entry);
262 } else {
263 // Ok, it's a like-for-like comparison of the keyProperties.
264 // Knowing how our implementation of ObjectName works, it's *much*
265 // faster to compare the canonicalKeyProperties strings than it
266 // is to compare the two hashtables.
267 if (patternCanonicalKPS.equals(name.getCanonicalKeyPropertyListString())) {
268 retval.add(entry);
269 }
270 }
271 }
272 }
273 }
274 }
275
276 return retval;
277 }
278
279 /***
280 * Compare the src and pat strings where ? and * chars are significant.
281 *
282 * @author <a href="mailto:trevor@protocool.com">Trevor Squires</a>.
283 */
284 protected boolean domainMatches(String src, String pat) {
285 if (src.equals("*")) // no point doing more that we have to...
286 {
287 return true;
288 }
289 return domainMatches(src.toCharArray(), 0, pat.toCharArray(), 0);
290 }
291
292 /***
293 * Compare the src and pat char arrays where ? and * chars are significant.
294 *
295 * I arrived at this solution after quite a bit of trial and error - it's
296 * all a bit interwoven. Obviously I'm no good at parsers and there must
297 * be a clearer or more elegant way to do this. I'm suitably in awe of
298 * the perl regex hackers now.
299 *
300 * @author <a href="mailto:trevor@protocool.com">Trevor Squires</a>.
301 */
302 protected boolean domainMatches(char[] src, int spos, char[] pat, int ppos) {
303 int slen = src.length;
304 int plen = pat.length;
305
306 while (ppos < plen) {
307 char c = pat[ppos++];
308 if ('?' == c) {
309 // eat a src character and make sure we're not
310 // already at the end
311 if (spos++ == slen) {
312 return false;
313 }
314 } else if ('*' == c) {
315 if (ppos == plen) // shortcut - * at the end of the pattern
316 {
317 return true;
318 }
319
320 // hammer the src chars recursively until we
321 // get a match or we drop off the end of src
322 do {
323 if (domainMatches(src, spos, pat, ppos)) {
324 return true;
325 }
326 } while (++spos < slen);
327 } else if (spos == slen || c != src[spos++]) {
328 return false;
329 }
330 }
331 // fell through with no falses so make sure all of src was examined
332 return (spos == slen);
333 }
334
335 /***
336 * Adds an MBeanComponent entry<p>
337 *
338 * WARNING: The object name should be fully qualified.
339 *
340 * @param entry the MBeanComponent entry to add
341 * @exception InstanceAlreadyExistsException when the MBeanComponent's object name
342 * is already registered
343 */
344 protected synchronized void add(ComponentEntry entry) throws ComponentAlreadyExistsException {
345 // Determine the components's name and properties
346 ComponentName name = entry.getComponentName();
347 String domain = name.getDomain();
348 String props = name.getCanonicalKeyPropertyListString();
349
350 // Create a properties -> entry map if we don't have one
351 Map mbeanMap = (Map) domainMap.get(domain);
352 if (mbeanMap == null) {
353 mbeanMap = new HashMap();
354 domainMap.put(domain, mbeanMap);
355 }
356
357 // Make sure we aren't already registered
358 if (mbeanMap.get(props) != null)
359 throw new ComponentAlreadyExistsException(name + " already registered.");
360
361 // Ok, we are registered
362 mbeanMap.put(props, entry);
363 }
364
365 /***
366 * Removes an MBeanComponent entry
367 *
368 * WARNING: The object name should be fully qualified.
369 *
370 * @param name the object name of the entry to remove
371 * @exception InstanceNotFoundException when the object name is not
372 * registered
373 */
374 protected synchronized void remove(ComponentName name) throws ComponentNotFoundException {
375 // Determine the MBeanComponent's name and properties
376 String domain = name.getDomain();
377 String props = name.getCanonicalKeyPropertyListString();
378 Map mbeanMap = (Map) domainMap.get(domain);
379
380 // Remove the entry, raise an exception when it didn't exist
381 if (null == mbeanMap || null == mbeanMap.remove(props))
382 throw new ComponentNotFoundException(name + " not registered.");
383 }
384
385 /***
386 * Validates and qualifies an MBeanComponent<p>
387 *
388 * Validates the name is not a pattern.<p>
389 *
390 * Adds the default domain if no domain is specified.<p>
391 *
392 * Checks the name is not in the reserved domain JMImplementation when
393 * the magicToken is not {@link org.jboss.mx.server.ServerConstants#JMI_DOMAIN JMI_DOMAIN}
394 *
395 * @param name the name to validate
396 * @param magicToken used to get access to the reserved domain
397 * @return the original name or the name prepended with the default domain
398 * if no domain is specified.
399 * @exception RuntimeOperationException containing an
400 * IllegalArgumentException for a problem with the name
401 */
402 protected ComponentName validateAndQualifyName(ComponentName name) {
403 // Check for qualification
404 ComponentName result = qualifyName(name);
405 return result;
406 }
407
408 protected ComponentName qualifyName(ComponentName name) {
409 try {
410 if (name.getDomain().length() == 0)
411 return new ComponentName(defaultDomain + ":" + name.getCanonicalKeyPropertyListString());
412 else
413 return name;
414 } catch (MalformedComponentNameException e) {
415 throw new IllegalArgumentException(e.toString());
416 }
417 }
418
419 }
This page was automatically generated by Maven