KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > mbeanserver > RepositorySupport


1 /*
2  * @(#)RepositorySupport.java 1.65 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.jmx.mbeanserver;
9
10
11 // java import
12
import java.util.Hashtable JavaDoc;
13 import java.util.Enumeration JavaDoc;
14 import java.util.Set JavaDoc;
15 import java.util.ArrayList JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Vector JavaDoc;
18
19 // RI import
20
import javax.management.* ;
21 import com.sun.jmx.defaults.ServiceName;
22 import com.sun.jmx.trace.Trace;
23
24 /**
25  * The RepositorySupport implements the Repository interface.
26  * This repository does not support persistency.
27  *
28  * @since 1.5
29  */

30 public class RepositorySupport implements Repository {
31     
32     // Private fields -------------------------------------------->
33

34     /**
35      * An object name for query describing the whole set of mbeans.
36      * Optimization helper for queries.
37      */

38     private final static ObjectName _WholeWordQueryObjectName;
39     static {
40     try {
41         _WholeWordQueryObjectName = new ObjectName("*:*");
42     } catch (MalformedObjectNameException e) {
43         throw new UnsupportedOperationException JavaDoc(e.getMessage());
44     }
45     }
46     
47     /**
48      * two int utilities to minimize wildmatch method stack frame overhead
49      * during recursions.
50      */

51     private static int _slen;
52     private static int _plen;
53
54     /**
55      * The structure for storing the objects is very basic .
56      * A Hashtable is used for storing the different domains
57      * For each domain, a hashtable contains the instances with
58      * canonical key property list string as key and named object
59      * aggregated from given object name and mbean instance as value.
60      */

61     private final Hashtable JavaDoc domainTb;
62     
63     /**
64      * Number of elements contained in the Repository
65      */

66     private int nbElements = 0;
67   
68     /**
69      * Domain name of the server the repository is attached to.
70      * It is quicker to store the information in the repository rather
71      * than querying the framework each time the info is required.
72      */

73     private final String JavaDoc domain;
74     
75     /** The name of this class to be used for tracing */
76     private final static String JavaDoc dbgTag = "Repository";
77
78     // Private fields <=============================================
79

80
81     // Private methods --------------------------------------------->
82

83     // TRACES & DEBUG
84
//---------------
85

86     private final static boolean isTraceOn() {
87     return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER);
88     }
89     
90     private final static void trace(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
91     Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER, clz, func,
92            info);
93     }
94     
95     private final static void trace(String JavaDoc func, String JavaDoc info) {
96         trace(dbgTag, func, info);
97     }
98     
99     private final static boolean isDebugOn() {
100         return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER);
101     }
102     
103     private final static void debug(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
104         Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER, clz, func,
105            info);
106     }
107     
108     private final static void debug(String JavaDoc func, String JavaDoc info) {
109         debug(dbgTag, func, info);
110     }
111     
112     /* This class is used to match an ObjectName against a pattern. */
113     private final static class ObjectNamePattern {
114         private final char[] domain;
115         private final String JavaDoc[] keys;
116         private final String JavaDoc[] values;
117         private final String JavaDoc properties;
118         private final boolean isPropertyPattern;
119         
120         /**
121          * The ObjectName pattern against which ObjectNames are matched.
122          **/

123         public final ObjectName pattern;
124         
125         /**
126          * Builds a new ObjectNamePattern object from an ObjectName pattern.
127          * @param pattern The ObjectName pattern under examination.
128          **/

129         public ObjectNamePattern(ObjectName pattern) {
130             this(pattern.isPattern(),pattern.getDomain(),
131                  pattern.isPropertyPattern(),
132                  pattern.getCanonicalKeyPropertyListString(),
133                  pattern.getKeyPropertyList(),pattern);
134         }
135
136         /**
137          * Builds a new ObjectNamePattern object from an ObjectName pattern
138          * constituents.
139          * @param domainPattern pattern.isPattern().
140          * @param domain pattern.getDomain().
141          * @param propertyPattern pattern.isPropertyPattern().
142          * @param canonicalProps pattern.getCanonicalKeyPropertyListString()
143          * @param keyPropertyList pattern.getKeyPropertyList()
144          * @param pattern The ObjectName pattern under examination.
145          **/

146         ObjectNamePattern(boolean domainPattern, String JavaDoc domain,
147                           boolean propertyPattern, String JavaDoc canonicalProps,
148                           Hashtable JavaDoc keyPropertyList, ObjectName pattern) {
149             final int len = (keyPropertyList==null?0:keyPropertyList.size());
150             final Enumeration JavaDoc e =
151                 (keyPropertyList==null?null:keyPropertyList.keys());
152             this.domain = (domain == null?null:domain.toCharArray());
153             this.keys = new String JavaDoc[len];
154             this.values = new String JavaDoc[len];
155             for (int i = 0 ; i < len ; i++ ) {
156                 final String JavaDoc k = (String JavaDoc)e.nextElement();
157                 keys[i] = k;
158                 values[i] = (String JavaDoc)keyPropertyList.get(k);
159             }
160             this.properties = canonicalProps;
161             this.isPropertyPattern = propertyPattern;
162             this.pattern = pattern;
163         }
164
165         /**
166          * Return true if the given ObjectName matches the ObjectName pattern
167          * for which this object has been built.
168          * WARNING: domain name is not considered here because it is supposed
169          * not to be wildcard when called. PropertyList is also
170      * supposed not to be zero-length.
171          * @param name The ObjectName we want to match against the pattern.
172          * @return true if <code>name</code> matches the pattern.
173          **/

174         public boolean matchKeys(ObjectName name) {
175             if (isPropertyPattern) {
176                 // Every property inside pattern should exist in name
177
for (int i= keys.length -1; i >= 0 ; i--) {
178
179                     // find value in given object name for key at current
180
// index in receiver
181
String JavaDoc v = name.getKeyProperty(keys[i]);
182
183                     // did we find a value for this key ?
184
if (v == null) return false;
185                     
186                     // if this property is ok (same key, same value),
187
// go to next
188
if (v.equals(values[i])) continue;
189                     return false;
190                 }
191                 return true;
192             } else {
193                 if (keys.length != name.getKeyPropertyList().size())
194             return false;
195                 final String JavaDoc p1 = name.getCanonicalKeyPropertyListString();
196                 final String JavaDoc p2 = properties;
197                 // if (p1 == null) return (p2 == null);
198
// if (p2 == null) return p1.equals("");
199
return (p1.equals(p2));
200             }
201         }
202     }
203
204     /**
205      * Add all the matching objects from the given hashtable in the
206      * result set for the given ObjectNamePattern
207      * Do not check whether the domains match (only check for matching
208      * key property lists - see <i>matchKeys()</i>)
209      **/

210     private final void addAllMatching(final Hashtable JavaDoc moiTb, final Set JavaDoc result,
211                       final ObjectNamePattern pattern) {
212     synchronized (moiTb) {
213         for (Enumeration JavaDoc e = moiTb.elements(); e.hasMoreElements();) {
214         final NamedObject no = (NamedObject) e.nextElement();
215                 final ObjectName on = no.getName();
216
217         // if all couples (property, value) are contained
218
if (pattern.matchKeys(on)) result.add(no);
219         }
220     }
221     }
222     
223     private final void addNewDomMoi(final Object JavaDoc object, final String JavaDoc dom,
224                     final ObjectName name) {
225     final Hashtable JavaDoc moiTb= new Hashtable JavaDoc();
226     domainTb.put(dom, moiTb);
227     moiTb.put(name.getCanonicalKeyPropertyListString(),
228           new NamedObject(name, object));
229     nbElements++;
230     }
231     
232     /*
233      * Tests whether string s is matched by pattern p.
234      * Supports "?", "*" each of which may be escaped with "\";
235      * Not yet supported: internationalization; "\" inside brackets.<P>
236      * Wildcard matching routine by Karl Heuer. Public Domain.<P>
237      */

238     private static boolean wildmatch(char[] s, char[] p, int si, int pi) {
239         char c;
240     // Be careful: this is dangerous: it works because wildmatch
241
// is protected by a synchronized block on domainTb
242
_slen = s.length;
243         _plen = p.length;
244     // end of comment.
245

246         while (pi < _plen) { // While still string
247
c = p[pi++];
248             if (c == '?') {
249                 if (++si > _slen) return false;
250             } else if (c == '*') { // Wildcard
251
if (pi >= _plen) return true;
252                 do {
253                     if (wildmatch(s,p,si,pi)) return true;
254                 } while (++si < _slen);
255                 return false;
256             } else {
257                 if (si >= _slen || c != s[si++]) return false;
258             }
259         }
260         return (si == _slen);
261     }
262
263     /**
264      * Retrieves the named object contained in repository
265      * from the given objectname.
266      */

267     private NamedObject retrieveNamedObject(ObjectName name) {
268
269         // No patterns inside reposit
270
if (name.isPattern() == true) return null;
271
272     // Extract the domain name.
273
String JavaDoc dom= name.getDomain().intern();
274
275         // Default domain case
276
if (dom.length() == 0) {
277             dom = domain;
278         }
279
280         Object JavaDoc tmp_object = domainTb.get(dom);
281     if (tmp_object == null) {
282             return null; // No domain containing registered object names
283
}
284
285         // If name exists in repository, we will get it now
286
Hashtable JavaDoc moiTb= (Hashtable JavaDoc) tmp_object;
287             
288         Object JavaDoc o = moiTb.get(name.getCanonicalKeyPropertyListString());
289         if (o != null ) {
290             return (NamedObject) o;
291         }
292         else return null;
293     }
294
295     // Private methods <=============================================
296

297     // Protected methods --------------------------------------------->
298
// Protected methods <=============================================
299

300
301     // Public methods --------------------------------------------->
302

303     /**
304      * Construct a new repository with the given default domain.
305      *
306      */

307     public RepositorySupport(String JavaDoc domain) {
308     domainTb= new Hashtable JavaDoc(5);
309         
310     if (domain != null && domain.length() != 0)
311         this.domain = domain;
312     else
313         this.domain = ServiceName.DOMAIN;
314
315         // Creates an new hastable for the default domain
316
domainTb.put(this.domain.intern(), new Hashtable JavaDoc());
317
318     // ------------------------------
319
// ------------------------------
320
}
321     
322     /**
323      * The purpose of this method is to provide a unified way to provide
324      * whatever configuration information is needed by the specific
325      * underlying implementation of the repository.
326      *
327      * @param configParameters An list containing the configuration
328      * parameters needed by the specific Repository Service
329      * implementation.
330      */

331     public void setConfigParameters(ArrayList JavaDoc configParameters) {
332     return;
333     }
334
335     /**
336      * Returns the list of domains in which any MBean is currently
337      * registered.
338      *
339      * @since.unbundled JMX RI 1.2
340      */

341     public String JavaDoc[] getDomains() {
342     final ArrayList JavaDoc result;
343     synchronized(domainTb) {
344         // Temporary list
345
result = new ArrayList JavaDoc(domainTb.size());
346
347         // Loop over all domains
348
for (Enumeration JavaDoc e = domainTb.keys();e.hasMoreElements();) {
349         // key = domain name
350
final String JavaDoc key = (String JavaDoc)e.nextElement();
351         if (key == null) continue;
352
353         // If no MBean in domain continue
354
final Hashtable JavaDoc t = (Hashtable JavaDoc)domainTb.get(key);
355         if (t == null || t.size()==0) continue;
356
357         // Some MBean are registered => add to result.
358
result.add(key);
359         }
360     }
361
362     // Make an array from result.
363
return (String JavaDoc[]) result.toArray(new String JavaDoc[result.size()]);
364     
365     }
366
367
368   
369     /**
370      * Indicates whether or not the Repository Service supports filtering. If
371      * the Repository Service does not support filtering, the MBean Server
372      * will perform filtering.
373      *
374      * @return true if filtering is supported, false otherwise.
375      */

376     public boolean isFiltering() {
377     // Let the MBeanServer perform the filtering !
378
return false;
379     }
380     
381     /**
382      * Stores an MBean associated with its object name in the repository.
383      *
384      *@param object MBean to be stored in the repository.
385      *@param name MBean object name.
386      *
387      */

388     public void addMBean(final Object JavaDoc object, ObjectName name)
389     throws InstanceAlreadyExistsException {
390     
391     if (isTraceOn()) {
392         trace("addMBean", "name=" + name);
393     }
394
395     // Extract the domain name.
396
String JavaDoc dom = name.getDomain().intern();
397     boolean to_default_domain = false;
398
399         // Set domain to default if domain is empty and not already set
400
if (dom.length() == 0) {
401
402          try {
403                 name = new ObjectName(domain + name.toString());
404
405             } catch (MalformedObjectNameException e) {
406
407                 if (isDebugOn()) {
408                     debug("addMBean",
409               "Unexpected MalformedObjectNameException");
410                 }
411             }
412     }
413     
414     // Do we have default domain ?
415
if (dom == domain) {
416         to_default_domain = true;
417         dom = domain;
418     } else {
419         to_default_domain = false;
420     }
421
422     // ------------------------------
423
// ------------------------------
424

425     // Validate name for an object
426
if (name.isPattern() == true) {
427         throw new RuntimeOperationsException(
428          new IllegalArgumentException JavaDoc("Repository: cannot add mbean for pattern name " + name.toString()));
429     }
430
431         // Domain cannot be JMImplementation if entry does not exists
432
if ( !to_default_domain &&
433              dom.equals("JMImplementation") &&
434              domainTb.containsKey("JMImplementation")) {
435
436         throw new RuntimeOperationsException(
437           new IllegalArgumentException JavaDoc(
438                       "Repository: domain name cannot be JMImplementation"));
439         }
440
441     // If domain not already exists, add it to the hash table
442
final Hashtable JavaDoc moiTb= (Hashtable JavaDoc) domainTb.get(dom);
443     if (moiTb == null) {
444         addNewDomMoi(object, dom, name);
445         return;
446     }
447         else {
448             // Add instance if not already present
449
String JavaDoc cstr = name.getCanonicalKeyPropertyListString();
450             Object JavaDoc elmt= moiTb.get(cstr);
451             if (elmt != null) {
452                 throw new InstanceAlreadyExistsException(name.toString());
453             } else {
454                 nbElements++;
455                 moiTb.put(cstr, new NamedObject(name, object));
456             }
457         }
458     }
459     
460     /**
461      * Checks whether an MBean of the name specified is already stored in
462      * the repository.
463      *
464      * @param name name of the MBean to find.
465      *
466      * @return true if the MBean is stored in the repository,
467      * false otherwise.
468      *
469      */

470     public boolean contains(ObjectName name) {
471     
472     if (isTraceOn()) {
473         trace("contains", "name=" + name);
474     }
475     return (retrieveNamedObject(name) != null);
476     }
477     
478     /**
479      * Retrieves the MBean of the name specified from the repository. The
480      * object name must match exactly.
481      *
482      * @param name name of the MBean to retrieve.
483      *
484      * @return The retrieved MBean if it is contained in the repository,
485      * null otherwise.
486      *
487      */

488     public Object JavaDoc retrieve(ObjectName name) {
489     
490     // ------------------------------
491
// ------------------------------
492
if (isTraceOn()) {
493         trace("retrieve", "name=" + name);
494     }
495
496         // Calls internal retrieve method to get the named object
497
NamedObject no = retrieveNamedObject(name);
498         if (no == null) return null;
499         else return no.getObject();
500
501     }
502
503     
504     /**
505      * Selects and retrieves the list of MBeans whose names match the specified
506      * object name pattern and which match the specified query expression
507      * (optionally).
508      *
509      * @param pattern The name of the MBean(s) to retrieve - may be a specific
510      * object or a name pattern allowing multiple MBeans to be selected.
511      * @param query query expression to apply when selecting objects - this
512      * parameter will be ignored when the Repository Service does not
513      * support filtering.
514      *
515      * @return The list of MBeans selected. There may be zero, one or many
516      * MBeans returned in the set.
517      *
518      */

519     public Set JavaDoc query(ObjectName pattern, QueryExp query) {
520     
521     // ------------------------------
522
// ------------------------------
523
ObjectNamePattern on_pattern = null; // intermediate Object name pattern for performance
524
final HashSet JavaDoc result = new HashSet JavaDoc();
525     
526     // The following filter cases are considered :
527
// null, "", "*:*"" : names in all domains
528
// ":*" : names in defaultDomain
529
// "domain:*" : names in the specified domain
530
// "domain:[key=value], *"
531

532         // Surely one of the most frequent case ... query on the whole world
533
ObjectName name = null;
534         if (pattern == null ||
535             pattern.getCanonicalName().length() == 0 ||
536             pattern.equals(_WholeWordQueryObjectName))
537            name = _WholeWordQueryObjectName;
538         else name = pattern;
539     
540     // If pattern is not a pattern, retrieve this mbean !
541
if (!name.isPattern()) {
542         final NamedObject no = retrieveNamedObject(name);
543         if (no != null) result.add(no);
544         return result;
545     }
546     
547     // all names in all domains
548
if (name == _WholeWordQueryObjectName) {
549         synchronized(domainTb) {
550         for(final Enumeration JavaDoc e = domainTb.elements();
551             e.hasMoreElements();) {
552             final Hashtable JavaDoc moiTb = (Hashtable JavaDoc) e.nextElement();
553                     result.addAll(moiTb.values());
554         }
555         }
556         return result;
557     }
558
559         String JavaDoc canonical_key_property_list_string = name.getCanonicalKeyPropertyListString();
560
561     // all names in default domain
562
//
563
// DF: fix 4618986 - take into account the case where the
564
// property list is not empty.
565
//
566
if (name.getDomain().length() == 0) {
567         final Hashtable JavaDoc moiTb = (Hashtable JavaDoc) domainTb.get(domain);
568         if (canonical_key_property_list_string.length() == 0) {
569                 result.addAll(moiTb.values());
570         } else {
571                 if (on_pattern == null)
572             on_pattern = new ObjectNamePattern(name);
573         addAllMatching(moiTb,result,on_pattern);
574         }
575         return result;
576     }
577     
578     // Pattern matching in the domain name (*, ?)
579
synchronized (domainTb) {
580             char[] dom2Match = name.getDomain().toCharArray();
581             String JavaDoc nextDomain;
582             char [] theDom;
583             for (final Enumeration JavaDoc enumi = domainTb.keys(); enumi.hasMoreElements();) {
584                 nextDomain = (String JavaDoc) enumi.nextElement();
585                 theDom = nextDomain.toCharArray();
586
587                 if (wildmatch(theDom, dom2Match, 0, 0)) {
588                     final Hashtable JavaDoc moiTb =
589             (Hashtable JavaDoc) domainTb.get(nextDomain);
590
591                     if (canonical_key_property_list_string.length() == 0)
592                         result.addAll(moiTb.values());
593                     else {
594                         if (on_pattern == null)
595                 on_pattern = new ObjectNamePattern(name);
596                         addAllMatching(moiTb,result,on_pattern);
597                     }
598                 }
599             }
600         }
601     return result;
602     }
603     
604     /**
605      * Removes an MBean from the repository.
606      *
607      * @param name name of the MBean to remove.
608      *
609      * @exception InstanceNotFoundException The MBean does not exist in
610      * the repository.
611      */

612     public void remove(final ObjectName name)
613     throws InstanceNotFoundException {
614
615         // Debugging stuff
616
if (isTraceOn()) {
617         trace("remove", "name=" + name);
618     }
619
620     // Extract domain name.
621
String JavaDoc dom= name.getDomain().intern();
622
623         // Default domain case
624
if (dom.length() == 0) dom = domain;
625
626         // Find the domain subtable
627
Object JavaDoc tmp_object = domainTb.get(dom);
628     if (tmp_object == null) {
629         throw new InstanceNotFoundException(name.toString());
630     }
631
632         // Remove the corresponding element
633
Hashtable JavaDoc moiTb= (Hashtable JavaDoc) tmp_object;
634     if (moiTb.remove(name.getCanonicalKeyPropertyListString()) == null) {
635         throw new InstanceNotFoundException(name.toString());
636     }
637
638         // We removed it !
639
nbElements--;
640         
641         // No more object for this domain, we remove this domain hashtable
642
if (moiTb.isEmpty()) {
643             domainTb.remove(dom);
644
645             // set a new default domain table (always present)
646
// need to reinstantiate a hashtable because of possible
647
// big buckets array size inside table, never cleared,
648
// thus the new !
649
if (dom == domain)
650         domainTb.put(domain, new Hashtable JavaDoc());
651         }
652     }
653     
654     /**
655      * Gets the number of MBeans stored in the repository.
656      *
657      * @return Number of MBeans.
658      */

659     
660     public Integer JavaDoc getCount() {
661     return new Integer JavaDoc(nbElements);
662     }
663     
664     /**
665      * Gets the name of the domain currently used by default in the
666      * repository.
667      *
668      * @return A string giving the name of the default domain name.
669      */

670     public String JavaDoc getDefaultDomain() {
671     return domain;
672     }
673
674 }
675
676
677
678
Popular Tags