##### Coverage Report - org.apache.commons.configuration.ConfigurationKey

Classes in this File | Line Coverage | Branch Coverage | Complexity
ConfigurationKey |
98% | 65/66
100% | 15/15
| 1.8333333333333333;1,833
ConfigurationKey$KeyIterator |
92% | 55/60
100% | 13/13
| 1.8333333333333333;1,833

1 |  |
     /*
2 |  |
      * Licensed to the Apache Software Foundation (ASF) under one or more
3 |  |
      * contributor license agreements.  See the NOTICE file distributed with
4 |  |
      * this work for additional information regarding copyright ownership.
5 |  |
      * The ASF licenses this file to You under the Apache License, Version 2.0
6 |  |
      * (the "License"); you may not use this file except in compliance with
7 |  |
      * the License.  You may obtain a copy of the License at
8 |  |
      *
9 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
10 |  |
      *
11 |  |
      * Unless required by applicable law or agreed to in writing, software
12 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
13 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |  |
      * See the License for the specific language governing permissions and
15 |  |
      * limitations under the License.
16 |  |
      */
17 |  |
18 |  |
     package org.apache.commons.configuration;
19 |  |
20 |  |
     import java.io.Serializable;
21 |  |
     import java.util.Iterator;
22 |  |
     import java.util.NoSuchElementException;
23 |  |
24 |  |
     /**
25 |  |
      * <p>A simple class that supports creation of and iteration on complex
26 |  |
      * configuration keys.</p>
27 |  |
      *
28 |  |
      * <p>For key creation the class works similar to a StringBuffer: There are
29 |  |
      * several <code>appendXXXX()</code> methods with which single parts
30 |  |
      * of a key can be constructed. All these methods return a reference to the
31 |  |
      * actual object so they can be written in a chain. When using this methods
32 |  |
      * the exact syntax for keys need not be known.</p>
33 |  |
      *
34 |  |
      * <p>This class also defines a specialized iterator for configuration keys.
35 |  |
      * With such an iterator a key can be tokenized into its single parts. For
36 |  |
      * each part it can be checked whether it has an associated index.</p>
37 |  |
      *
38 |  |
      * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
39 |  |
      * @version $Id: ConfigurationKey.java 439648 2006-09-02 20:42:10Z oheger $
40 |  |
      */
41 | 9120 |
     public class ConfigurationKey implements Serializable
42 |  |
     {
43 |  |
         /** Constant for a property delimiter.*/
44 |  |
         public static final char PROPERTY_DELIMITER = '.';
45 |  |
46 |  |
         /** Constant for an escaped delimiter. */
47 | 3 |
         public static final String ESCAPED_DELIMITER =
48 |  |
             String.valueOf(PROPERTY_DELIMITER) + String.valueOf(PROPERTY_DELIMITER);
49 |  |
50 |  |
         /** Constant for an attribute start marker.*/
51 |  |
         private static final String ATTRIBUTE_START = "[@";
52 |  |
53 |  |
         /** Constant for an attribute end marker.*/
54 |  |
         private static final String ATTRIBUTE_END = "]";
55 |  |
56 |  |
         /** Constant for an index start marker.*/
57 |  |
         private static final char INDEX_START = '(';
58 |  |
59 |  |
         /** Constant for an index end marker.*/
60 |  |
         private static final char INDEX_END = ')';
61 |  |
62 |  |
         /** Constant for the initial StringBuffer size.*/
63 |  |
         private static final int INITIAL_SIZE = 32;
64 |  |
65 |  |
         /**
66 |  |
          * The serial version ID.
67 |  |
          */
68 |  |
         private static final long serialVersionUID = -4299732083605277656L;
69 |  |
70 |  |
         /** Holds a buffer with the so far created key.*/
71 |  |
         private StringBuffer keyBuffer;
72 |  |
73 |  |
         /**
74 |  |
          * Creates a new, empty instance of <code>ConfigurationKey</code>.
75 |  |
          */
76 |  |
         public ConfigurationKey()
77 | 183 |
         {
78 | 183 |
             keyBuffer = new StringBuffer(INITIAL_SIZE);
79 | 183 |
         }
80 |  |
81 |  |
         /**
82 |  |
          * Creates a new instance of <code>ConfigurationKey</code> and
83 |  |
          * initializes it with the given key.
84 |  |
          *
85 |  |
          * @param key the key as a string
86 |  |
          */
87 |  |
         public ConfigurationKey(String key)
88 | 54 |
         {
89 | 54 |
             keyBuffer = new StringBuffer(key);
90 | 54 |
             removeTrailingDelimiter();
91 | 54 |
         }
92 |  |
93 |  |
         /**
94 |  |
          * Appends the name of a property to this key. If necessary, a
95 |  |
          * property delimiter will be added.
96 |  |
          *
97 |  |
          * @param property the name of the property to be added
98 |  |
          * @return a reference to this object
99 |  |
          */
100 |  |
         public ConfigurationKey append(String property)
101 |  |
         {
102 | 257 |
             if (keyBuffer.length() > 0 && !hasDelimiter() && !isAttributeKey(property))
103 |  |
             {
104 | 108 |
                 keyBuffer.append(PROPERTY_DELIMITER);
105 |  |
             }
106 |  |
107 | 257 |
             keyBuffer.append(property);
108 | 257 |
             removeTrailingDelimiter();
109 | 257 |
             return this;
110 |  |
         }
111 |  |
112 |  |
         /**
113 |  |
          * Appends an index to this configuration key.
114 |  |
          *
115 |  |
          * @param index the index to be appended
116 |  |
          * @return a reference to this object
117 |  |
          */
118 |  |
         public ConfigurationKey appendIndex(int index)
119 |  |
         {
120 | 21 |
             keyBuffer.append(INDEX_START).append(index);
121 | 21 |
             keyBuffer.append(INDEX_END);
122 | 21 |
             return this;
123 |  |
         }
124 |  |
125 |  |
         /**
126 |  |
          * Appends an attribute to this configuration key.
127 |  |
          *
128 |  |
          * @param attr the name of the attribute to be appended
129 |  |
          * @return a reference to this object
130 |  |
          */
131 |  |
         public ConfigurationKey appendAttribute(String attr)
132 |  |
         {
133 | 5 |
             keyBuffer.append(constructAttributeKey(attr));
134 | 5 |
             return this;
135 |  |
         }
136 |  |
137 |  |
         /**
138 |  |
          * Checks if this key is an attribute key.
139 |  |
          *
140 |  |
          * @return a flag if this key is an attribute key
141 |  |
          */
142 |  |
         public boolean isAttributeKey()
143 |  |
         {
144 | 0 |
             return isAttributeKey(keyBuffer.toString());
145 |  |
         }
146 |  |
147 |  |
         /**
148 |  |
          * Checks if the passed in key is an attribute key. Such attribute keys
149 |  |
          * start and end with certain marker strings. In some cases they must be
150 |  |
          * treated slightly different.
151 |  |
          *
152 |  |
          * @param key the key (part) to be checked
153 |  |
          * @return a flag if this key is an attribute key
154 |  |
          */
155 |  |
         public static boolean isAttributeKey(String key)
156 |  |
         {
157 | 681 |
             return key != null
158 |  |
             && key.startsWith(ATTRIBUTE_START)
159 |  |
             && key.endsWith(ATTRIBUTE_END);
160 |  |
         }
161 |  |
162 |  |
         /**
163 |  |
          * Decorates the given key so that it represents an attribute. Adds
164 |  |
          * special start and end markers.
165 |  |
          *
166 |  |
          * @param key the key to be decorated
167 |  |
          * @return the decorated attribute key
168 |  |
          */
169 |  |
         public static String constructAttributeKey(String key)
170 |  |
         {
171 | 8 |
             StringBuffer buf = new StringBuffer();
172 | 8 |
             buf.append(ATTRIBUTE_START).append(key).append(ATTRIBUTE_END);
173 | 8 |
             return buf.toString();
174 |  |
         }
175 |  |
176 |  |
         /**
177 |  |
          * Extracts the name of the attribute from the given attribute key.
178 |  |
          * This method removes the attribute markers - if any - from the
179 |  |
          * specified key.
180 |  |
          *
181 |  |
          * @param key the attribute key
182 |  |
          * @return the name of the corresponding attribute
183 |  |
          */
184 |  |
         public static String attributeName(String key)
185 |  |
         {
186 | 2 |
             return isAttributeKey(key) ? removeAttributeMarkers(key) : key;
187 |  |
         }
188 |  |
189 |  |
         /**
190 |  |
          * Helper method for removing attribute markers from a key.
191 |  |
          *
192 |  |
          * @param key the key
193 |  |
          * @return the key with removed attribute markers
194 |  |
          */
195 |  |
         static String removeAttributeMarkers(String key)
196 |  |
         {
197 | 7 |
             return key.substring(ATTRIBUTE_START.length(), key.length() - ATTRIBUTE_END.length());
198 |  |
         }
199 |  |
200 |  |
         /**
201 |  |
          * Helper method that checks if the actual buffer ends with a property
202 |  |
          * delimiter.
203 |  |
          *
204 |  |
          * @return a flag if there is a trailing delimiter
205 |  |
          */
206 |  |
         private boolean hasDelimiter()
207 |  |
         {
208 | 424 |
             int count = 0;
209 | 424 |
             for (int idx = keyBuffer.length() - 1; idx >= 0
210 | 8 |
                     && keyBuffer.charAt(idx) == PROPERTY_DELIMITER; idx--)
211 |  |
             {
212 | 8 |
                 count++;
213 |  |
             }
214 | 424 |
             return count % 2 == 1;
215 |  |
         }
216 |  |
217 |  |
         /**
218 |  |
          * Removes a trailing delimiter if there is any.
219 |  |
          */
220 |  |
         private void removeTrailingDelimiter()
221 |  |
         {
222 | 626 |
             while (hasDelimiter())
223 |  |
             {
224 | 4 |
                 keyBuffer.deleteCharAt(keyBuffer.length() - 1);
225 |  |
             }
226 | 311 |
         }
227 |  |
228 |  |
         /**
229 |  |
          * Returns a string representation of this object. This is the
230 |  |
          * configuration key as a plain string.
231 |  |
          *
232 |  |
          * @return a string for this object
233 |  |
          */
234 |  |
         public String toString()
235 |  |
         {
236 | 121 |
             return keyBuffer.toString();
237 |  |
         }
238 |  |
239 |  |
         /**
240 |  |
          * Returns an iterator for iterating over the single components of
241 |  |
          * this configuration key.
242 |  |
          *
243 |  |
          * @return an iterator for this key
244 |  |
          */
245 |  |
         public KeyIterator iterator()
246 |  |
         {
247 | 277 |
             return new KeyIterator();
248 |  |
         }
249 |  |
250 |  |
         /**
251 |  |
          * Returns the actual length of this configuration key.
252 |  |
          *
253 |  |
          * @return the length of this key
254 |  |
          */
255 |  |
         public int length()
256 |  |
         {
257 | 203 |
             return keyBuffer.length();
258 |  |
         }
259 |  |
260 |  |
         /**
261 |  |
          * Sets the new length of this configuration key. With this method it is
262 |  |
          * possible to truncate the key, e.g. to return to a state prior calling
263 |  |
          * some <code>append()</code> methods. The semantic is the same as
264 |  |
          * the <code>setLength()</code> method of <code>StringBuffer</code>.
265 |  |
          *
266 |  |
          * @param len the new length of the key
267 |  |
          */
268 |  |
         public void setLength(int len)
269 |  |
         {
270 | 1 |
             keyBuffer.setLength(len);
271 | 1 |
         }
272 |  |
273 |  |
         /**
274 |  |
          * Checks if two <code>ConfigurationKey</code> objects are equal. The
275 |  |
          * method can be called with strings or other objects, too.
276 |  |
          *
277 |  |
          * @param c the object to compare
278 |  |
          * @return a flag if both objects are equal
279 |  |
          */
280 |  |
         public boolean equals(Object c)
281 |  |
         {
282 | 11 |
             if (c == null)
283 |  |
             {
284 | 1 |
                 return false;
285 |  |
             }
286 |  |
287 | 10 |
             return keyBuffer.toString().equals(c.toString());
288 |  |
         }
289 |  |
290 |  |
         /**
291 |  |
          * Returns the hash code for this object.
292 |  |
          *
293 |  |
          * @return the hash code
294 |  |
          */
295 |  |
         public int hashCode()
296 |  |
         {
297 | 2 |
             return String.valueOf(keyBuffer).hashCode();
298 |  |
         }
299 |  |
300 |  |
         /**
301 |  |
          * Returns a configuration key object that is initialized with the part
302 |  |
          * of the key that is common to this key and the passed in key.
303 |  |
          *
304 |  |
          * @param other the other key
305 |  |
          * @return a key object with the common key part
306 |  |
          */
307 |  |
         public ConfigurationKey commonKey(ConfigurationKey other)
308 |  |
         {
309 | 104 |
             if (other == null)
310 |  |
             {
311 | 1 |
                 throw new IllegalArgumentException("Other key must no be null!");
312 |  |
             }
313 |  |
314 | 103 |
             ConfigurationKey result = new ConfigurationKey();
315 | 103 |
             KeyIterator it1 = iterator();
316 | 103 |
             KeyIterator it2 = other.iterator();
317 |  |
318 | 350 |
             while (it1.hasNext() && it2.hasNext() && partsEqual(it1, it2))
319 |  |
             {
320 | 144 |
                 if (it1.isAttribute())
321 |  |
                 {
322 | 2 |
                     result.appendAttribute(it1.currentKey());
323 |  |
                 }
324 |  |
                 else
325 |  |
                 {
326 | 142 |
                     result.append(it1.currentKey());
327 | 142 |
                     if (it1.hasIndex)
328 |  |
                     {
329 | 7 |
                         result.appendIndex(it1.getIndex());
330 |  |
                     }
331 |  |
                 }
332 |  |
             }
333 |  |
334 | 103 |
             return result;
335 |  |
         }
336 |  |
337 |  |
         /**
338 |  |
          * Returns the &quot;difference key&quot; to a given key. This value
339 |  |
          * is the part of the passed in key that differs from this key. There is
340 |  |
          * the following relation:
341 |  |
          * <code>other = key.commonKey(other) + key.differenceKey(other)</code>
342 |  |
          * for an arbitrary configuration key <code>key</code>.
343 |  |
          *
344 |  |
          * @param other the key for which the difference is to be calculated
345 |  |
          * @return the difference key
346 |  |
          */
347 |  |
         public ConfigurationKey differenceKey(ConfigurationKey other)
348 |  |
         {
349 | 67 |
             ConfigurationKey common = commonKey(other);
350 | 67 |
             ConfigurationKey result = new ConfigurationKey();
351 |  |
352 | 67 |
             if (common.length() < other.length())
353 |  |
             {
354 | 63 |
                 String k = other.toString().substring(common.length());
355 |  |
                 // skip trailing delimiters
356 | 63 |
                 int i = 0;
357 | 170 |
                 while (i < k.length() && k.charAt(i) == PROPERTY_DELIMITER)
358 |  |
                 {
359 | 44 |
                     i++;
360 |  |
                 }
361 |  |
362 | 63 |
                 if (i < k.length())
363 |  |
                 {
364 | 63 |
                     result.append(k.substring(i));
365 |  |
                 }
366 |  |
             }
367 |  |
368 | 67 |
             return result;
369 |  |
         }
370 |  |
371 |  |
         /**
372 |  |
          * Helper method for comparing two key parts.
373 |  |
          *
374 |  |
          * @param it1 the iterator with the first part
375 |  |
          * @param it2 the iterator with the second part
376 |  |
          * @return a flag if both parts are equal
377 |  |
          */
378 |  |
         private static boolean partsEqual(KeyIterator it1, KeyIterator it2)
379 |  |
         {
380 | 232 |
             return it1.nextKey().equals(it2.nextKey())
381 |  |
             && it1.getIndex() == it2.getIndex()
382 |  |
             && it1.isAttribute() == it2.isAttribute();
383 |  |
         }
384 |  |
385 |  |
         /**
386 |  |
          * A specialized iterator class for tokenizing a configuration key.
387 |  |
          * This class implements the normal iterator interface. In addition it
388 |  |
          * provides some specific methods for configuration keys.
389 |  |
          */
390 | 419 |
         public class KeyIterator implements Iterator, Cloneable
391 |  |
         {
392 |  |
             /** Stores the current key name.*/
393 |  |
             private String current;
394 |  |
395 |  |
             /** Stores the start index of the actual token.*/
396 |  |
             private int startIndex;
397 |  |
398 |  |
             /** Stores the end index of the actual token.*/
399 |  |
             private int endIndex;
400 |  |
401 |  |
             /** Stores the index of the actual property if there is one.*/
402 |  |
             private int indexValue;
403 |  |
404 |  |
             /** Stores a flag if the actual property has an index.*/
405 |  |
             private boolean hasIndex;
406 |  |
407 |  |
             /** Stores a flag if the actual property is an attribute.*/
408 |  |
             private boolean attribute;
409 |  |
410 |  |
             /**
411 |  |
              * Helper method for determining the next indices.
412 |  |
              *
413 |  |
              * @return the next key part
414 |  |
              */
415 |  |
             private String findNextIndices()
416 |  |
             {
417 | 567 |
                 startIndex = endIndex;
418 |  |
                 // skip empty names
419 | 567 |
                 while (startIndex < keyBuffer.length()
420 | 883 |
                         && keyBuffer.charAt(startIndex) == PROPERTY_DELIMITER)
421 |  |
                 {
422 | 316 |
                     startIndex++;
423 |  |
                 }
424 |  |
425 |  |
                 // Key ends with a delimiter?
426 | 567 |
                 if (startIndex >= keyBuffer.length())
427 |  |
                 {
428 | 0 |
                     endIndex = keyBuffer.length();
429 | 0 |
                     startIndex = endIndex - 1;
430 | 0 |
                     return keyBuffer.substring(startIndex, endIndex);
431 |  |
                 }
432 |  |
                 else
433 |  |
                 {
434 | 567 |
                     return nextKeyPart();
435 |  |
                 }
436 |  |
             }
437 |  |
438 |  |
             /**
439 |  |
              * Helper method for extracting the next key part. Takes escaping of
440 |  |
              * delimiter characters into account.
441 |  |
              *
442 |  |
              * @return the next key part
443 |  |
              */
444 |  |
             private String nextKeyPart()
445 |  |
             {
446 | 567 |
                 StringBuffer key = new StringBuffer(INITIAL_SIZE);
447 | 567 |
                 int idx = startIndex;
448 | 567 |
                 int endIdx = keyBuffer.toString().indexOf(ATTRIBUTE_START,
449 |  |
                         startIndex);
450 | 567 |
                 if (endIdx < 0 || endIdx == startIndex)
451 |  |
                 {
452 | 532 |
                     endIdx = keyBuffer.length();
453 |  |
                 }
454 | 567 |
                 boolean found = false;
455 |  |
456 | 5254 |
                 while (!found && idx < endIdx)
457 |  |
                 {
458 | 4120 |
                     char c = keyBuffer.charAt(idx);
459 | 4120 |
                     if (c == PROPERTY_DELIMITER)
460 |  |
                     {
461 |  |
                         // a duplicated delimiter means escaping
462 | 385 |
                         if (idx == endIdx - 1
463 |  |
                                 || keyBuffer.charAt(idx + 1) != PROPERTY_DELIMITER)
464 |  |
                         {
465 | 382 |
                             found = true;
466 |  |
                         }
467 |  |
                         else
468 |  |
                         {
469 | 3 |
                             idx++;
470 |  |
                         }
471 |  |
                     }
472 | 4120 |
                     if (!found)
473 |  |
                     {
474 | 3738 |
                         key.append(c);
475 | 3738 |
                         idx++;
476 |  |
                     }
477 |  |
                 }
478 |  |
479 | 567 |
                 endIndex = idx;
480 | 567 |
                 return key.toString();
481 |  |
             }
482 |  |
483 |  |
             /**
484 |  |
              * Returns the next key part of this configuration key. This is a short
485 |  |
              * form of <code>nextKey(false)</code>.
486 |  |
              *
487 |  |
              * @return the next key part
488 |  |
              */
489 |  |
             public String nextKey()
490 |  |
             {
491 | 566 |
                 return nextKey(false);
492 |  |
             }
493 |  |
494 |  |
             /**
495 |  |
              * Returns the next key part of this configuration key. The boolean
496 |  |
              * parameter indicates wheter a decorated key should be returned. This
497 |  |
              * affects only attribute keys: if the parameter is <b>false</b>, the
498 |  |
              * attribute markers are stripped from the key; if it is <b>true</b>,
499 |  |
              * they remain.
500 |  |
              *
501 |  |
              * @param decorated a flag if the decorated key is to be returned
502 |  |
              * @return the next key part
503 |  |
              */
504 |  |
             public String nextKey(boolean decorated)
505 |  |
             {
506 | 568 |
                 if (!hasNext())
507 |  |
                 {
508 | 1 |
                     throw new NoSuchElementException("No more key parts!");
509 |  |
                 }
510 |  |
511 | 567 |
                 hasIndex = false;
512 | 567 |
                 indexValue = -1;
513 | 567 |
                 String key = findNextIndices();
514 |  |
515 | 567 |
                 current = key;
516 | 567 |
                 hasIndex = checkIndex(key);
517 | 567 |
                 attribute = checkAttribute(current);
518 |  |
519 | 567 |
                 return currentKey(decorated);
520 |  |
             }
521 |  |
522 |  |
             /**
523 |  |
              * Helper method for checking if the passed key is an attribute.
524 |  |
              * If this is the case, the internal fields will be set.
525 |  |
              *
526 |  |
              * @param key the key to be checked
527 |  |
              * @return a flag if the key is an attribute
528 |  |
              */
529 |  |
             private boolean checkAttribute(String key)
530 |  |
             {
531 | 567 |
                 if (isAttributeKey(key))
532 |  |
                 {
533 | 6 |
                     current = removeAttributeMarkers(key);
534 | 6 |
                     return true;
535 |  |
                 }
536 |  |
                 else
537 |  |
                 {
538 | 561 |
                     return false;
539 |  |
                 }
540 |  |
             }
541 |  |
542 |  |
             /**
543 |  |
              * Helper method for checking if the passed key contains an index.
544 |  |
              * If this is the case, internal fields will be set.
545 |  |
              *
546 |  |
              * @param key the key to be checked
547 |  |
              * @return a flag if an index is defined
548 |  |
              */
549 |  |
             private boolean checkIndex(String key)
550 |  |
             {
551 | 567 |
                 boolean result = false;
552 |  |
553 | 567 |
                 int idx = key.lastIndexOf(INDEX_START);
554 | 567 |
                 if (idx > 0)
555 |  |
                 {
556 | 23 |
                     int endidx = key.indexOf(INDEX_END, idx);
557 |  |
558 | 23 |
                     if (endidx > idx + 1)
559 |  |
                     {
560 | 22 |
                         indexValue = Integer.parseInt(key.substring(idx + 1, endidx));
561 | 22 |
                         current = key.substring(0, idx);
562 | 22 |
                         result = true;
563 |  |
                     }
564 |  |
                 }
565 |  |
566 | 567 |
                 return result;
567 |  |
             }
568 |  |
569 |  |
             /**
570 |  |
              * Checks if there is a next element.
571 |  |
              *
572 |  |
              * @return a flag if there is a next element
573 |  |
              */
574 |  |
             public boolean hasNext()
575 |  |
             {
576 | 1183 |
                 return endIndex < keyBuffer.length();
577 |  |
             }
578 |  |
579 |  |
             /**
580 |  |
              * Returns the next object in the iteration.
581 |  |
              *
582 |  |
              * @return the next object
583 |  |
              */
584 |  |
             public Object next()
585 |  |
             {
586 | 5 |
                 return nextKey();
587 |  |
             }
588 |  |
589 |  |
             /**
590 |  |
              * Removes the current object in the iteration. This method is not
591 |  |
              * supported by this iterator type, so an exception is thrown.
592 |  |
              */
593 |  |
             public void remove()
594 |  |
             {
595 | 1 |
                 throw new UnsupportedOperationException("Remove not supported!");
596 |  |
             }
597 |  |
598 |  |
             /**
599 |  |
              * Returns the current key of the iteration (without skipping to the
600 |  |
              * next element). This is the same key the previous <code>next()</code>
601 |  |
              * call had returned. (Short form of <code>currentKey(false)</code>.
602 |  |
              *
603 |  |
              * @return the current key
604 |  |
              */
605 |  |
             public String currentKey()
606 |  |
             {
607 | 144 |
                 return currentKey(false);
608 |  |
             }
609 |  |
610 |  |
             /**
611 |  |
              * Returns the current key of the iteration (without skipping to the
612 |  |
              * next element). The boolean parameter indicates wheter a decorated
613 |  |
              * key should be returned. This affects only attribute keys: if the
614 |  |
              * parameter is <b>false</b>, the attribute markers are stripped from
615 |  |
              * the key; if it is <b>true</b>, they remain.
616 |  |
              *
617 |  |
              * @param decorated a flag if the decorated key is to be returned
618 |  |
              * @return the current key
619 |  |
              */
620 |  |
             public String currentKey(boolean decorated)
621 |  |
             {
622 | 775 |
                 return (decorated && isAttribute()) ? constructAttributeKey(current) : current;
623 |  |
             }
624 |  |
625 |  |
             /**
626 |  |
              * Returns a flag if the current key is an attribute. This method can
627 |  |
              * be called after <code>next()</code>.
628 |  |
              *
629 |  |
              * @return a flag if the current key is an attribute
630 |  |
              */
631 |  |
             public boolean isAttribute()
632 |  |
             {
633 | 499 |
                 return attribute;
634 |  |
             }
635 |  |
636 |  |
             /**
637 |  |
              * Returns the index value of the current key. If the current key does
638 |  |
              * not have an index, return value is -1. This method can be called
639 |  |
              * after <code>next()</code>.
640 |  |
              *
641 |  |
              * @return the index value of the current key
642 |  |
              */
643 |  |
             public int getIndex()
644 |  |
             {
645 | 303 |
                 return indexValue;
646 |  |
             }
647 |  |
648 |  |
             /**
649 |  |
              * Returns a flag if the current key has an associated index.
650 |  |
              * This method can be called after <code>next()</code>.
651 |  |
              *
652 |  |
              * @return a flag if the current key has an index
653 |  |
              */
654 |  |
             public boolean hasIndex()
655 |  |
             {
656 | 5 |
                 return hasIndex;
657 |  |
             }
658 |  |
659 |  |
             /**
660 |  |
              * Creates a clone of this object.
661 |  |
              *
662 |  |
              * @return a clone of this object
663 |  |
              */
664 |  |
             public Object clone()
665 |  |
             {
666 |  |
                 try
667 |  |
                 {
668 | 0 |
                     return super.clone();
669 |  |
                 }
670 |  |
                 catch (CloneNotSupportedException cex)
671 |  |
                 {
672 |  |
                     // should not happen
673 | 0 |
                     return null;
674 |  |
                 }
675 |  |
             }
676 |  |
         }
677 |  |
     }