1   /*
2    */
3   package net.sf.panoptes.model.component.registry;
4   
5   import java.util.ArrayList;
6   import java.util.Collections;
7   import java.util.Enumeration;
8   import java.util.Hashtable;
9   import java.util.Iterator;
10  
11  /***
12   * Represents the IComponent reference. Original code from JBoss.
13   *
14   * @see net.sf.panoptes.model.component.registry.ComponentRegistry
15   *
16   * @author  dag@liodden.no
17   * @version 0.1
18   *
19   */
20  public class ComponentName implements java.io.Serializable {
21  
22  	public static final String DOMAIN_COMPONENT_QUERY = "query";
23  	public static final String DOMAIN_MBEAN_DOMAIN = "jmx.domain";
24  	public static final String DOMAIN_MBEAN_SERVER = "jmx.server";
25  	public static final String DOMAIN_MBEAN = "jmx.mbean";
26  	public static final String DOMAIN_LOGGER = "logger";
27  
28  	// Attributes ----------------------------------------------------
29  	private transient boolean hasPattern = false;
30  	private transient boolean hasPropertyPattern = false;
31  	private transient boolean hasDomainPattern = false;
32  	private transient Hashtable propertiesHash = null;
33  
34  	private transient String domain = null;
35  	private transient String kProps = null;
36  	private transient String ckProps = null;
37  
38  	private transient int hash;
39  
40  	// Static --------------------------------------------------------
41  
42  	// Constructors --------------------------------------------------
43  	public ComponentName(String name) throws MalformedComponentNameException {
44  		init(name);
45  	}
46  
47  	public ComponentName(String domain, String name) throws MalformedComponentNameException {
48  		init(domain + ":" + name);
49  	}
50  
51  	public ComponentName(String domain, Hashtable table) throws MalformedComponentNameException {
52  		if (table == null)
53  		   throw new NullPointerException("null table");
54  
55  		initDomain(domain, null);
56  
57  		if (table.size() < 1)
58  		   throw new MalformedComponentNameException("empty table");
59  
60  		initProperties((Hashtable) table.clone(), null);
61  
62  		this.kProps = ckProps;
63  	}
64  
65  	// Public ------------------------------------------------------
66  	/***
67  	 * Quotes the passed string suitable for use as a value in an
68  	 * ObjectName.
69  	 *
70  	 * @param value the string to quote
71  	 * @return the quoted string
72  	 * @exception NullPointerException for a null string
73  	 */
74  	public static String quote(String value) {
75  		if (value == null)
76  			throw new NullPointerException("null value");
77  
78  		StringBuffer buffer = new StringBuffer(value.length() + 10);
79  		buffer.append('"');
80  		char[] chars = value.toCharArray();
81  		for (int i = 0; i < chars.length; i++) {
82  			switch (chars[i]) {
83  				case '"' :
84  				case '*' :
85  				case '?' :
86  				case '//' :
87  					buffer.append('//').append(chars[i]);
88  					break;
89  				case '\n' :
90  					buffer.append('//').append('n');
91  					break;
92  				default :
93  					buffer.append(chars[i]);
94  			}
95  		}
96  		buffer.append('"');
97  
98  		return buffer.toString();
99  	}
100 
101 	/***
102 	 * Unquotes a string, unquote(quote(s)).equals(s) is always true.
103 	 *
104 	 * @param value the string to unquote
105 	 * @return the unquoted string
106 	 * @exception IllegalArgumentException when the string is
107 	 *            not of a form that can be unquoted.
108 	 * @exception NullPointerException for a null string
109 	 */
110 	public static String unquote(String value) {
111 		if (value == null)
112 			throw new NullPointerException("null value");
113 		if (value.length() == 0)
114 			throw new IllegalArgumentException("Empty value");
115 
116 		StringBuffer buffer = new StringBuffer(value.length());
117 
118 		char[] chars = value.toCharArray();
119 
120 		boolean inQuote = false;
121 		boolean escape = false;
122 
123 		for (int i = 0; i < chars.length; ++i) {
124 			// Valid escape character?
125 			char c = chars[i];
126 			if (escape) {
127 				switch (c) {
128 					case '//' :
129 					case '"' :
130 					case '*' :
131 					case '?' :
132 						escape = false;
133 						buffer.append(c);
134 						break;
135 					case 'n' :
136 						escape = false;
137 						buffer.append('\n');
138 						break;
139 
140 						// Invalid escape character
141 					default :
142 						throw new IllegalArgumentException(
143 							"The value " + value + " contains an invalid escape sequence backslash " + c);
144 				}
145 			}
146 
147 			// Starting a quote
148 			else if (inQuote == false && c == '"')
149 				inQuote = true;
150 
151 			// Ending a quote
152 			else if (inQuote && c == '"')
153 				inQuote = false;
154 
155 			// Escaping
156 			else if (inQuote && c == '//')
157 				escape = true;
158 
159 			// Inside a quote
160 			else if (inQuote) {
161 				switch (c) {
162 					case '"' :
163 						throw new IllegalArgumentException(
164 							"The value " + value + " cannot contain quote inside a quote pair, use backslash quote");
165 					case '*' :
166 					case '?' :
167 						throw new IllegalArgumentException(
168 							"The value " + value + " cannot contain " + c + " inside a quote pair, use backslash " + c);
169 					case '\n' :
170 						throw new IllegalArgumentException(
171 							"The value " + value + " cannot contain a new line inside a quote pair, use backslash n");
172 				}
173 				buffer.append(c);
174 			}
175 
176 			// Plain text
177 			else
178 				throw new IllegalArgumentException("The value " + value + " is not enclosed in quotes");
179 		}
180 
181 		if (inQuote)
182 			throw new IllegalArgumentException("Unterminated quote pair, missing quote");
183 		if (escape)
184 			throw new IllegalArgumentException("Unterminated escape, missing one of backslash quote asterisk question mark or n");
185 
186 		return buffer.toString();
187 	}
188 
189 	public boolean equals(Object object) {
190 		if (object == this) {
191 			return true;
192 		}
193 
194 		if (object instanceof ComponentName) {
195 			ComponentName oname = (ComponentName) object;
196 			return (oname.hash == hash && domain.equals(oname.domain) && ckProps.equals(oname.ckProps));
197 		}
198 
199 		return false;
200 	}
201 
202 	public int hashCode() {
203 		return hash;
204 	}
205 
206 	public String toString() {
207 		return this.domain + ":" + ckProps;
208 	}
209 
210 	public boolean isPattern() {
211 		return hasPattern;
212 	}
213 
214 	public String getCanonicalName() {
215 		return this.domain + ":" + ckProps;
216 	}
217 
218 	public String getDomain() {
219 		return domain;
220 	}
221 
222 	public String getKeyProperty(String property) {
223 		return (String) propertiesHash.get(property);
224 	}
225 
226 	public Hashtable getKeyPropertyList() {
227 		return (Hashtable) propertiesHash.clone();
228 	}
229 
230 	public String getKeyPropertyListString() {
231 		return kProps;
232 	}
233 
234 	public String getCanonicalKeyPropertyListString() {
235 		return ckProps;
236 	}
237 
238 	public boolean isPropertyPattern() {
239 		return hasPropertyPattern;
240 	}
241 
242 	// Private -----------------------------------------------------
243 
244 	/***
245 	 * constructs an object name from a string
246 	 */
247 	private void init(String name) throws MalformedComponentNameException {
248 		if (name == null)
249 			throw new NullPointerException("null name");
250 
251 		if (name.length() == 0)
252 			name = "*:*";
253 
254 		int domainSep = name.indexOf(':');
255 
256 		if (-1 == domainSep)
257 			throw new MalformedComponentNameException("missing domain");
258 
259 		initDomain(name.substring(0, domainSep), name);
260 		initProperties(name.substring(domainSep + 1), name);
261 	}
262 
263 	/***
264 	  * checks for domain patterns and illegal characters
265 	  */
266 	 private void initDomain(String dstring, String name) throws MalformedComponentNameException
267 	 {
268 		if (null == dstring)
269 		   throw new NullPointerException("null domain");
270 
271 		checkIllegalDomain(dstring, name);
272 
273 		if (dstring.indexOf('*') > -1 || dstring.indexOf('?') > -1)
274 		{
275 		   this.hasPattern = true;
276 		   this.hasDomainPattern = true;
277 		}
278 
279 		this.domain = dstring;
280 	 }
281 	/***
282 	 * takes the properties string and breaks it up into key/value pairs for
283 	 * insertion into a newly created hashtable.
284 	 *
285 	 * minimal validation is performed so that it doesn't blow up when
286 	 * constructing the kvp strings.
287 	 *
288 	 * checks for duplicate keys
289 	 *
290 	 * detects property patterns
291 	 *
292 	 */
293 	private void initProperties(String properties, String name) throws MalformedComponentNameException {
294 		if (null == properties || properties.length() < 1)
295 			throw new MalformedComponentNameException(addDebugObjectName(name) + "null or empty properties");
296 
297 		Hashtable ptable = new Hashtable();
298 
299 		char[] chars = properties.toCharArray();
300 
301 		String key = null;
302 		String value = null;
303 		int start = 0;
304 		boolean inKey = true;
305 		boolean inQuote = false;
306 		boolean escape = false;
307 
308 		for (int current = 0; current < chars.length; ++current) {
309 			char c = chars[current];
310 
311 			// Previous character was the backslash escape
312 			if (escape)
313 				escape = false;
314 
315 			// In a quote
316 			else if (inQuote) {
317 				// End the quote
318 				if (c == '"')
319 					inQuote = false;
320 
321 				// Start escaping
322 				else if (c == '//')
323 					escape = true;
324 			}
325 
326 			// Processing the key
327 			else if (inKey) {
328 				// Found the terminator
329 				if (c == '=' || c == ',') {
330 					if (current == start)
331 						throw new MalformedComponentNameException(addDebugObjectName(name) + "Empty key");
332 					key = properties.substring(start, current);
333 
334 					// Didn't get an equals so the only thing valid is asterisk
335 					if (c == ',') {
336 						if (key.equals("*")) {
337 							if (hasPropertyPattern)
338 								throw new MalformedComponentNameException(
339 									addDebugObjectName(name) + "A property pattern may only contain one * property");
340 							this.hasPropertyPattern = true;
341 							this.hasPattern = true;
342 						} else
343 							throw new MalformedComponentNameException(
344 								addDebugObjectName(name) + "Invalid key/value data " + key);
345 					} else {
346 						// Check for a duplicate key and process the value
347 						if (ptable.containsKey(key))
348 							throw new MalformedComponentNameException(addDebugObjectName(name) + "Duplicate key " + key);
349 						inKey = false;
350 					}
351 					start = current + 1;
352 				}
353 			}
354 
355 			// Processing a value
356 			else {
357 				// Starting a quote
358 				if (c == '"')
359 					inQuote = true;
360 
361 				// Found the terminator
362 				else if (c == ',') {
363 					// Add the key, value pair and process the next pair
364 					if (current == start)
365 						ptable.put(key, "");
366 					else
367 						ptable.put(key, properties.substring(start, current));
368 
369 					inKey = true;
370 					start = current + 1;
371 				}
372 			}
373 		}
374 
375 		// Fell off the end while processing a key
376 		if (inKey) {
377 			if (start == chars.length)
378 				throw new MalformedComponentNameException(
379 					addDebugObjectName(name) + "An ObjectName cannot end with a comma");
380 
381 			// Might be ok if the remainder is an asterisk
382 			key = properties.substring(start, chars.length);
383 			if (key.equals("*")) {
384 				if (hasPropertyPattern)
385 					throw new MalformedComponentNameException(
386 						addDebugObjectName(name) + "A property pattern may only contain one * property");
387 
388 				this.hasPropertyPattern = true;
389 				this.hasPattern = true;
390 			} else
391 				throw new MalformedComponentNameException(addDebugObjectName(name) + "Invalid key/value data " + key);
392 		}
393 
394 		// Fell off the end while processing a value
395 		if (inKey == false) {
396 			// No value
397 			if (start == chars.length)
398 				ptable.put(key, "");
399 			else
400 				ptable.put(key, properties.substring(start, chars.length));
401 		}
402 
403 		initProperties(ptable, name);
404 		this.kProps = properties;
405 	}
406 
407 	/***
408 	 * validates incoming properties hashtable
409 	 *
410 	 * builds canonical string
411 	 *
412 	 * precomputes the hashcode
413 	 */
414 	private void initProperties(Hashtable properties, String name) throws MalformedComponentNameException {
415 		if (null == properties || (!this.hasPropertyPattern && properties.size() < 1))
416 			throw new MalformedComponentNameException(addDebugObjectName(name) + "null or empty properties");
417 
418 		Iterator it = properties.keySet().iterator();
419 		ArrayList list = new ArrayList();
420 
421 		while (it.hasNext()) {
422 			String key = null;
423 			try {
424 				key = (String) it.next();
425 			} catch (ClassCastException e) {
426 				throw new MalformedComponentNameException(addDebugObjectName(name) + "key is not a string " + key);
427 			}
428 
429 			String val = null;
430 			try {
431 				val = (String) properties.get(key);
432 			} catch (ClassCastException e) {
433 				throw new MalformedComponentNameException(addDebugObjectName(name) + "value is not a string " + val);
434 			}
435 
436 			if (key.equals("*") && val.equals("*")) {
437 				it.remove();
438 				this.hasPropertyPattern = true;
439 				this.hasPattern = true;
440 				continue;
441 			}
442 
443 			if (key.length() == 0)
444 				throw new MalformedComponentNameException(addDebugObjectName(name) + "key has no length =" + val);
445 
446 			checkIllegalKey(key, name);
447 			checkIllegalValue(val, name);
448 
449 			list.add(new String(key + "=" + val));
450 		}
451 
452 		Collections.sort(list);
453 		StringBuffer strBuffer = new StringBuffer();
454 
455 		it = list.iterator();
456 		while (it.hasNext()) {
457 			strBuffer.append(it.next());
458 			if (it.hasNext()) {
459 				strBuffer.append(',');
460 			}
461 		}
462 
463 		if (this.hasPropertyPattern) {
464 			if (properties.size() > 0) {
465 				strBuffer.append(",*");
466 			} else {
467 				strBuffer.append("*");
468 			}
469 		}
470 
471 		this.propertiesHash = properties;
472 		this.ckProps = strBuffer.toString();
473 		this.hash = getCanonicalName().hashCode();
474 	}
475 
476 	private void checkIllegalKey(String key, String name) throws MalformedComponentNameException {
477 		char[] chars = key.toCharArray();
478 
479 		for (int i = 0; i < chars.length; ++i) {
480 			switch (chars[i]) {
481 				case ':' :
482 				case ',' :
483 				case '=' :
484 				case '*' :
485 				case '?' :
486 					throw new MalformedComponentNameException(
487 						addDebugObjectName(name) + "The key " + key + " cannot contain a " + chars[i] + " character");
488 				case '\n' :
489 					throw new MalformedComponentNameException(
490 						addDebugObjectName(name) + "The key " + key + " cannot contain a new line character");
491 			}
492 		}
493 	}
494 
495 	private void checkIllegalValue(String value, String name) throws MalformedComponentNameException {
496 		char[] chars = value.toCharArray();
497 
498 		boolean inQuote = false;
499 		boolean escape = false;
500 
501 		for (int i = 0; i < chars.length; ++i) {
502 			// Valid escape character?
503 			char c = chars[i];
504 			if (escape) {
505 				switch (c) {
506 					case '//' :
507 					case 'n' :
508 					case '"' :
509 					case '*' :
510 					case '?' :
511 						escape = false;
512 						break;
513 
514 						// Invalid escape character
515 					default :
516 						throw new MalformedComponentNameException(
517 							addDebugObjectName(name)
518 								+ "The value "
519 								+ value
520 								+ " contains an invalid escape sequence backslash "
521 								+ c);
522 				}
523 			}
524 
525 			// Starting a quote
526 			else if (inQuote == false && c == '"')
527 				inQuote = true;
528 
529 			// Ending a quote
530 			else if (inQuote && c == '"')
531 				inQuote = false;
532 
533 			// Escaping
534 			else if (inQuote && c == '//')
535 				escape = true;
536 
537 			// Inside a quote
538 			else if (inQuote) {
539 				switch (c) {
540 					case '"' :
541 						throw new MalformedComponentNameException(
542 							addDebugObjectName(name)
543 								+ "The value "
544 								+ value
545 								+ " cannot contain quote inside a quote pair, use backslash quote");
546 					case '*' :
547 					case '?' :
548 						throw new MalformedComponentNameException(
549 							addDebugObjectName(name)
550 								+ "The value "
551 								+ value
552 								+ " cannot contain "
553 								+ c
554 								+ " inside a quote pair, use backslash "
555 								+ c);
556 					case '\n' :
557 						throw new MalformedComponentNameException(
558 							addDebugObjectName(name)
559 								+ "The value "
560 								+ value
561 								+ " cannot contain a new line inside a quote pair, use backslash n");
562 				}
563 			}
564 
565 			// Plain text
566 			else {
567 				switch (c) {
568 					case ':' :
569 					case ',' :
570 					case '=' :
571 					case '*' :
572 					case '?' :
573 						throw new MalformedComponentNameException(
574 							addDebugObjectName(name)
575 								+ "The value "
576 								+ value
577 								+ " cannot contain "
578 								+ c
579 								+ " use quote backslash "
580 								+ c
581 								+ " quote or ObjectName.quote(String)");
582 					case '\n' :
583 						throw new MalformedComponentNameException(
584 							addDebugObjectName(name)
585 								+ "The value "
586 								+ value
587 								+ " cannot contain a new line use quote backslash n quote or ObjectName.quote(String)");
588 				}
589 			}
590 		}
591 
592 		if (inQuote)
593 			throw new MalformedComponentNameException(
594 				addDebugObjectName(name) + "Unterminated quote pair, missing quote");
595 		if (escape)
596 			throw new MalformedComponentNameException(
597 				addDebugObjectName(name)
598 					+ "Unterminated escape, missing one of backslash quote asterisk question mark or n");
599 	}
600 
601 	/***
602 	 * returns true if the domain contains illegal characters
603 	 */
604 	private void checkIllegalDomain(String dom, String name) throws MalformedComponentNameException {
605 		char[] chars = dom.toCharArray();
606 
607 		for (int i = 0; i < chars.length; i++) {
608 			switch (chars[i]) {
609 				case ':' :
610 					throw new MalformedComponentNameException(
611 						addDebugObjectName(name) + "The domain " + dom + " cannot contain a : character");
612 				case '\n' :
613 					throw new MalformedComponentNameException(
614 						addDebugObjectName(name) + "The domain " + dom + " cannot contain a new line character");
615 			}
616 		}
617 	}
618 
619 	private String addDebugObjectName(String name) {
620 		if (name == null)
621 			return "";
622 		else
623 			return name + " is not a valid ObjectName. ";
624 	}
625 
626 	/***
627 	 * @param string
628 	 */
629 	public void setDomain(String domain) throws MalformedComponentNameException {
630 		initDomain(domain, null);
631 	}
632 
633 	/***
634 	 * Checks if this instance matches a pattern.
635 	 * 
636 	 * @param pattern the pattern
637 	 * @return true if it matches
638 	 */
639 	public boolean matches(ComponentName pattern) {
640 		// We do casts here without any checking since the keys and values have been
641 		// checked in the ComponentName constructor.
642 
643 		// Check if the domain matches
644 		if ((!pattern.getDomain().equals("*") && !pattern.getDomain().equals(getDomain())))
645 			return false;
646 
647 		// Check the keys in pattern and see if there is a match;
648 		Hashtable props = pattern.getKeyPropertyList();
649 		for (Enumeration e = props.keys(); e.hasMoreElements();) {
650 			String key = (String) e.nextElement();
651 			String value = (String) propertiesHash.get(key);
652 			if ((value == null) || !(value.equals(props.get(key))))
653 				return false;
654 		}
655 		return true;
656 	}
657 }
This page was automatically generated by Maven