Coverage Report - org.kuali.student.common.assembly.data.Data
 
Classes in this File Line Coverage Branch Coverage Complexity
Data
28%
68/237
25%
16/64
1.326
Data$1
0%
0/4
0%
0/2
1.326
Data$2
50%
5/10
N/A
1.326
Data$2$1
28%
2/7
N/A
1.326
Data$3
0%
0/10
N/A
1.326
Data$3$1
0%
0/7
N/A
1.326
Data$BooleanValue
30%
3/10
0%
0/2
1.326
Data$DataType
100%
3/3
N/A
1.326
Data$DataValue
40%
4/10
0%
0/2
1.326
Data$DateValue
40%
4/10
0%
0/2
1.326
Data$DoubleValue
40%
4/10
0%
0/2
1.326
Data$FloatValue
0%
0/10
0%
0/2
1.326
Data$IntegerKey
40%
4/10
0%
0/4
1.326
Data$IntegerValue
0%
0/10
0%
0/2
1.326
Data$Key
N/A
N/A
1.326
Data$LongValue
0%
0/10
0%
0/2
1.326
Data$Property
N/A
N/A
1.326
Data$ShortValue
0%
0/10
0%
0/2
1.326
Data$StringKey
70%
7/10
50%
2/4
1.326
Data$StringValue
40%
4/10
N/A
1.326
Data$TimeValue
0%
0/10
0%
0/2
1.326
Data$TimestampValue
0%
0/10
0%
0/2
1.326
Data$Value
N/A
N/A
1.326
 
 1  
 /**
 2  
  * Copyright 2010 The Kuali Foundation Licensed under the
 3  
  * Educational Community License, Version 2.0 (the "License"); you may
 4  
  * not use this file except in compliance with the License. You may
 5  
  * obtain a copy of the License at
 6  
  *
 7  
  * http://www.osedu.org/licenses/ECL-2.0
 8  
  *
 9  
  * Unless required by applicable law or agreed to in writing,
 10  
  * software distributed under the License is distributed on an "AS IS"
 11  
  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 12  
  * or implied. See the License for the specific language governing
 13  
  * permissions and limitations under the License.
 14  
  */
 15  
 
 16  
 package org.kuali.student.common.assembly.data;
 17  
 
 18  
 import java.io.Serializable;
 19  
 import java.sql.Time;
 20  
 import java.sql.Timestamp;
 21  
 import java.util.Date;
 22  
 import java.util.HashMap;
 23  
 import java.util.HashSet;
 24  
 import java.util.Iterator;
 25  
 import java.util.LinkedHashMap;
 26  
 import java.util.Map;
 27  
 import java.util.Set;
 28  
 import java.util.Map.Entry;
 29  
 
 30  
 import javax.xml.bind.annotation.XmlRootElement;
 31  
 import javax.xml.bind.annotation.XmlType;
 32  
 
 33  
 /**
 34  
  * Kuali Student data representation.  Data is essentially a map of values.
 35  
  * 
 36  
  * @author Kuali Student Team
 37  
  * @see Value
 38  
  */
 39  
 @SuppressWarnings({"serial", "unchecked"})
 40  0
 public class Data implements Serializable, Iterable<Data.Property>, HasChangeCallbacks {
 41  218
     @XmlType(name = "lookUpDataType")
 42  10
     public enum DataType {
 43  1
         STRING, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN, DATE, TRUNCATED_DATE, DATA, LIST
 44  
     }
 45  
 
 46  
     @XmlRootElement
 47  
     public static class BooleanValue implements Value {
 48  
         private Boolean value;
 49  
 
 50  0
         protected BooleanValue() {
 51  
 
 52  0
         }
 53  
 
 54  3
         public BooleanValue(final Boolean value) {
 55  3
             this.value = value;
 56  3
         }
 57  
 
 58  
         @Override
 59  
         public <T> T get() {
 60  0
             return (T) value;
 61  
         }
 62  
 
 63  
         @Override
 64  
         public Class getType() {
 65  0
             return Boolean.class;
 66  
         }
 67  
 
 68  
         @Override
 69  
         public String toString() {
 70  0
             if (value == null) {
 71  0
                 return "";
 72  
             } else {
 73  0
                 return String.valueOf(value);
 74  
             }
 75  
         }
 76  
     }
 77  
 
 78  
     @XmlRootElement
 79  
     public static class DataValue implements Value {
 80  
         private Data value;
 81  
 
 82  0
         protected DataValue() {
 83  
 
 84  0
         }
 85  
 
 86  2
         public DataValue(final Data value) {
 87  2
             this.value = value;
 88  2
         }
 89  
 
 90  
         @Override
 91  
         public <T> T get() {
 92  2
             return (T) value;
 93  
         }
 94  
 
 95  
         @Override
 96  
         public Class getType() {
 97  0
             return Data.class;
 98  
         }
 99  
 
 100  
         @Override
 101  
         public String toString() {
 102  0
             if (value == null) {
 103  0
                 return null;
 104  
             } else {
 105  0
                 return value.toString();
 106  
             }
 107  
         }
 108  
     }
 109  
 
 110  
     @XmlRootElement
 111  
     public static class DateValue implements Value {
 112  
         private Date value;
 113  
 
 114  0
         protected DateValue() {
 115  
 
 116  0
         }
 117  
 
 118  1
         public DateValue(final Date value) {
 119  1
             this.value = value;
 120  1
         }
 121  
 
 122  
         @Override
 123  
         public <T> T get() {
 124  1
             return (T) value;
 125  
         }
 126  
 
 127  
         @Override
 128  
         public Class getType() {
 129  0
             return Date.class;
 130  
         }
 131  
 
 132  
         @Override
 133  
         public String toString() {
 134  0
             if (value == null) {
 135  0
                 return null;
 136  
             } else {
 137  0
                 return String.valueOf(value);
 138  
             }
 139  
         }
 140  
     }
 141  
 
 142  
     @XmlRootElement
 143  
     public static class DoubleValue implements Value {
 144  
         private Double value;
 145  
 
 146  0
         protected DoubleValue() {
 147  
 
 148  0
         }
 149  
 
 150  1
         public DoubleValue(final Double value) {
 151  1
             this.value = value;
 152  1
         }
 153  
 
 154  
         @Override
 155  
         public <T> T get() {
 156  1
             return (T) value;
 157  
         }
 158  
 
 159  
         @Override
 160  
         public Class getType() {
 161  0
             return Double.class;
 162  
         }
 163  
 
 164  
         @Override
 165  
         public String toString() {
 166  0
             if (value == null) {
 167  0
                 return null;
 168  
             } else {
 169  0
                 return String.valueOf(value);
 170  
             }
 171  
         }
 172  
     }
 173  
 
 174  
     @XmlRootElement
 175  
     public static class FloatValue implements Value {
 176  
         private Float value;
 177  
 
 178  0
         protected FloatValue() {
 179  
 
 180  0
         }
 181  
 
 182  0
         public FloatValue(final Float value) {
 183  0
             this.value = value;
 184  0
         }
 185  
 
 186  
         @Override
 187  
         public <T> T get() {
 188  0
             return (T) value;
 189  
         }
 190  
 
 191  
         @Override
 192  
         public Class getType() {
 193  0
             return Float.class;
 194  
         }
 195  
 
 196  
         @Override
 197  
         public String toString() {
 198  0
             if (value == null) {
 199  0
                 return null;
 200  
             } else {
 201  0
                 return String.valueOf(value);
 202  
             }
 203  
         }
 204  
     }
 205  
 
 206  
     public static class IntegerKey implements Key {
 207  
         private Integer key;
 208  
 
 209  0
         protected IntegerKey() {
 210  
 
 211  0
         }
 212  
 
 213  1
         public IntegerKey(final Integer key) {
 214  1
             this.key = key;
 215  1
         }
 216  
 
 217  
         /*
 218  
          * (non-Javadoc)
 219  
          * 
 220  
          * @see java.lang.Object#equals(java.lang.Object)
 221  
          */
 222  
 
 223  
         @Override
 224  
         public boolean equals(final Object obj) {
 225  0
             return obj instanceof IntegerKey && key.equals(((IntegerKey) obj).key);
 226  
         }
 227  
 
 228  
         @Override
 229  
         public <T> T get() {
 230  0
             return (T) key;
 231  
         }
 232  
 
 233  
         @Override
 234  
         public Class getType() {
 235  0
             return Integer.class;
 236  
         }
 237  
 
 238  
         /*
 239  
          * (non-Javadoc)
 240  
          * 
 241  
          * @see java.lang.Object#hashCode()
 242  
          */
 243  
 
 244  
         @Override
 245  
         public int hashCode() {
 246  2
             return key.hashCode();
 247  
         }
 248  
 
 249  
         /*
 250  
          * (non-Javadoc)
 251  
          * 
 252  
          * @see java.lang.Object#toString()
 253  
          */
 254  
 
 255  
         @Override
 256  
         public String toString() {
 257  0
             return String.valueOf(key);
 258  
         }
 259  
 
 260  
     }
 261  
 
 262  
     @XmlRootElement
 263  
     public static class IntegerValue implements Value {
 264  
         private Integer value;
 265  
 
 266  0
         protected IntegerValue() {
 267  
 
 268  0
         }
 269  
 
 270  0
         public IntegerValue(final Integer value) {
 271  0
             this.value = value;
 272  0
         }
 273  
 
 274  
         @Override
 275  
         public <T> T get() {
 276  0
             return (T) value;
 277  
         }
 278  
 
 279  
         @Override
 280  
         public Class getType() {
 281  0
             return Integer.class;
 282  
         }
 283  
 
 284  
         @Override
 285  
         public String toString() {
 286  0
             if (value == null) {
 287  0
                 return null;
 288  
             } else {
 289  0
                 return String.valueOf(value);
 290  
             }
 291  
         }
 292  
     }
 293  
 
 294  
     public interface Key extends Serializable {
 295  
 
 296  
         <T> T get();
 297  
 
 298  
         Class getType();
 299  
     }
 300  
 
 301  
     @XmlRootElement
 302  
     public static class LongValue implements Value {
 303  
         private Long value;
 304  
 
 305  0
         protected LongValue() {
 306  
 
 307  0
         }
 308  
 
 309  0
         public LongValue(final Long value) {
 310  0
             this.value = value;
 311  0
         }
 312  
 
 313  
         @Override
 314  
         public <T> T get() {
 315  0
             return (T) value;
 316  
         }
 317  
 
 318  
         @Override
 319  
         public Class getType() {
 320  0
             return Long.class;
 321  
         }
 322  
 
 323  
         @Override
 324  
         public String toString() {
 325  0
             if (value == null) {
 326  0
                 return null;
 327  
             } else {
 328  0
                 return String.valueOf(value);
 329  
             }
 330  
         }
 331  
     }
 332  
 
 333  
     public interface Property {
 334  
         <T> T getKey();
 335  
 
 336  
         Class getKeyType();
 337  
 
 338  
         Key getWrappedKey();
 339  
 
 340  
         <T> T getValue();
 341  
 
 342  
         Class getValueType();
 343  
 
 344  
         Value getWrappedValue();
 345  
     }
 346  
 
 347  
     @XmlRootElement
 348  
     public static class ShortValue implements Value {
 349  
         private Short value;
 350  
 
 351  0
         protected ShortValue() {
 352  
 
 353  0
         }
 354  
 
 355  0
         public ShortValue(final Short value) {
 356  0
             this.value = value;
 357  0
         }
 358  
 
 359  
         @Override
 360  
         public <T> T get() {
 361  0
             return (T) value;
 362  
         }
 363  
 
 364  
         @Override
 365  
         public Class getType() {
 366  0
             return Short.class;
 367  
         }
 368  
 
 369  
         @Override
 370  
         public String toString() {
 371  0
             if (value == null) {
 372  0
                 return null;
 373  
             } else {
 374  0
                 return String.valueOf(value);
 375  
             }
 376  
         }
 377  
     }
 378  
 
 379  
     @XmlRootElement
 380  
     public static class StringKey implements Key {
 381  
         private String key;
 382  
 
 383  0
         protected StringKey() {
 384  
 
 385  0
         }
 386  
 
 387  62
         public StringKey(final String key) {
 388  62
             this.key = key;
 389  62
         }
 390  
 
 391  
         /*
 392  
          * (non-Javadoc)
 393  
          * 
 394  
          * @see java.lang.Object#equals(java.lang.Object)
 395  
          */
 396  
 
 397  
         @Override
 398  
         public boolean equals(final Object obj) {
 399  36
             return obj instanceof StringKey && key.equals(((StringKey) obj).key);
 400  
         }
 401  
 
 402  
         @Override
 403  
         public <T> T get() {
 404  2
             return (T) key;
 405  
         }
 406  
 
 407  
         @Override
 408  
         public Class<?> getType() {
 409  0
             return String.class;
 410  
         }
 411  
 
 412  
         /*
 413  
          * (non-Javadoc)
 414  
          * 
 415  
          * @see java.lang.Object#hashCode()
 416  
          */
 417  
 
 418  
         @Override
 419  
         public int hashCode() {
 420  97
             return key.hashCode();
 421  
         }
 422  
 
 423  
         /*
 424  
          * (non-Javadoc)
 425  
          * 
 426  
          * @see java.lang.Object#toString()
 427  
          */
 428  
 
 429  
         @Override
 430  
         public String toString() {
 431  14
             return key;
 432  
         }
 433  
 
 434  
     }
 435  
 
 436  
     @XmlRootElement
 437  
     public static class StringValue implements Value {
 438  
         private String value;
 439  
 
 440  0
         protected StringValue() {
 441  
 
 442  0
         }
 443  
 
 444  52
         public StringValue(final String value) {
 445  52
             this.value = value;
 446  52
         }
 447  
 
 448  
         @Override
 449  
         public <T> T get() {
 450  26
             return (T) value;
 451  
         }
 452  
 
 453  
         @Override
 454  
         public Class getType() {
 455  0
             return String.class;
 456  
         }
 457  
 
 458  
         @Override
 459  
         public String toString() {
 460  0
             return value;
 461  
         }
 462  
 
 463  
         public void setValue(String value) {
 464  0
             this.value = value;
 465  0
         }
 466  
     }
 467  
 
 468  
     @XmlRootElement
 469  
     public static class TimestampValue implements Value {
 470  
         private Timestamp value;
 471  
 
 472  0
         protected TimestampValue() {
 473  
 
 474  0
         }
 475  
 
 476  0
         public TimestampValue(final Timestamp value) {
 477  0
             this.value = value;
 478  0
         }
 479  
 
 480  
         @Override
 481  
         public <T> T get() {
 482  0
             return (T) value;
 483  
         }
 484  
 
 485  
         @Override
 486  
         public Class getType() {
 487  0
             return Timestamp.class;
 488  
         }
 489  
 
 490  
         @Override
 491  
         public String toString() {
 492  0
             if (value == null) {
 493  0
                 return null;
 494  
             } else {
 495  0
                 return String.valueOf(value);
 496  
             }
 497  
         }
 498  
     }
 499  
 
 500  
     @XmlRootElement
 501  
     public static class TimeValue implements Value {
 502  
         private Time value;
 503  
 
 504  0
         protected TimeValue() {
 505  
 
 506  0
         }
 507  
 
 508  0
         public TimeValue(final Time value) {
 509  0
             this.value = value;
 510  0
         }
 511  
 
 512  
         @Override
 513  
         public <T> T get() {
 514  0
             return (T) value;
 515  
         }
 516  
 
 517  
         @Override
 518  
         public Class getType() {
 519  0
             return Time.class;
 520  
         }
 521  
 
 522  
         @Override
 523  
         public String toString() {
 524  0
             if (value == null) {
 525  0
                 return null;
 526  
             } else {
 527  0
                 return String.valueOf(value);
 528  
             }
 529  
         }
 530  
     }
 531  
 
 532  
     /**
 533  
      * Kuali Student data value interface for use in Data
 534  
      * 
 535  
      * @author Kuali Student Team
 536  
      *
 537  
      */
 538  
     public interface Value extends Serializable {
 539  
         <T> T get();
 540  
 
 541  
         Class getType();
 542  
     }
 543  
 
 544  1
     public static final Key WILDCARD_KEY = new Data.StringKey(QueryPath.getWildCard());
 545  
 
 546  
     private transient Set<ChangeCallback> changeCallbacks;
 547  
 
 548  
     private String className;
 549  
 
 550  
     private Map<Key, Value> map;
 551  
 
 552  5
     private Data parent = null;
 553  
 
 554  5
     private Key parentKey = null;
 555  
 
 556  
     public Data() {
 557  5
         this(Data.class.getName());
 558  5
     }
 559  
 
 560  5
     public Data(final String className) {
 561  5
         this.className = className;
 562  5
         map = new LinkedHashMap<Key, Value>();
 563  5
     }
 564  
 
 565  
     protected void _getQueryPath(final QueryPath path) {
 566  27
         if (parent != null) {
 567  0
             parent._getQueryPath(path);
 568  0
             path.add(parentKey);
 569  
         }
 570  27
     }
 571  
 
 572  
     protected void execChangeCallbacks(ChangeType type, QueryPath path) {
 573  27
         if (changeCallbacks != null) {
 574  0
             for (ChangeCallback c : changeCallbacks) {
 575  0
                 c.onChange(type, path);
 576  
             }
 577  
         }
 578  27
         if (parent != null) {
 579  0
             parent.execChangeCallbacks(type, path);
 580  
         }
 581  27
     }
 582  
 
 583  
     public ChangeCallbackRegistration addChangeCallback(final ChangeCallback callback) {
 584  0
         if (changeCallbacks == null) {
 585  0
             changeCallbacks = new HashSet<ChangeCallback>();
 586  
         }
 587  0
         changeCallbacks.add(callback);
 588  0
         return new ChangeCallbackRegistration() {
 589  
             @Override
 590  
             public void remove() {
 591  0
                 if (changeCallbacks != null) {
 592  0
                     changeCallbacks.remove(callback);
 593  
                 }
 594  0
             }
 595  
         };
 596  
     }
 597  
 
 598  
     private void put(Key key, Value value) {
 599  27
         Value existing = map.put(key, value);
 600  27
         ChangeType type = existing == null ? ChangeType.ADD : ChangeType.UPDATE;
 601  27
         QueryPath path = getQueryPath();
 602  27
         path.add(key);
 603  27
         execChangeCallbacks(type, path);
 604  27
     }
 605  
 
 606  
     public void remove(Key key) {
 607  
         // TODO probably need to add all of the other remove(type) methods
 608  0
         map.remove(key);
 609  0
         QueryPath path = getQueryPath();
 610  0
         path.add(key);
 611  0
         execChangeCallbacks(ChangeType.REMOVE, path);
 612  0
     }
 613  
 
 614  
     public void add(final Boolean value) {
 615  0
         put(new IntegerKey(map.size()), new BooleanValue(value));
 616  0
     }
 617  
 
 618  
     public void add(final Data value) {
 619  1
         final Key k = new IntegerKey(map.size());
 620  1
         put(k, new DataValue(value));
 621  1
         if (value != null) {
 622  1
             value.parent = this;
 623  1
             value.parentKey = k;
 624  
         }
 625  1
     }
 626  
 
 627  
     public void add(final Date value) {
 628  0
         put(new IntegerKey(map.size()), new DateValue(value));
 629  0
     }
 630  
 
 631  
     public void add(final Double value) {
 632  0
         put(new IntegerKey(map.size()), new DoubleValue(value));
 633  0
     }
 634  
 
 635  
     public void add(final Float value) {
 636  0
         put(new IntegerKey(map.size()), new FloatValue(value));
 637  0
     }
 638  
 
 639  
     public void add(final Integer value) {
 640  0
         put(new IntegerKey(map.size()), new IntegerValue(value));
 641  0
     }
 642  
 
 643  
     public void add(final Long value) {
 644  0
         put(new IntegerKey(map.size()), new LongValue(value));
 645  0
     }
 646  
 
 647  
     public void add(final Short value) {
 648  0
         put(new IntegerKey(map.size()), new ShortValue(value));
 649  0
     }
 650  
 
 651  
     public void add(final String value) {
 652  0
         put(new IntegerKey(map.size()), new StringValue(value));
 653  0
     }
 654  
 
 655  
     public void add(final Time value) {
 656  0
         put(new IntegerKey(map.size()), new TimeValue(value));
 657  0
     }
 658  
 
 659  
     public void add(final Timestamp value) {
 660  0
         put(new IntegerKey(map.size()), new TimestampValue(value));
 661  0
     }
 662  
 
 663  
     public Data copy() {
 664  0
         return copy(new Data(this.className), true);
 665  
     }
 666  
 
 667  
     public Data copy(Data target, boolean recurse) {
 668  
         // note, this was the clone() method, but my eclipse code cleanup insists on @Override, and the compiler gives an
 669  
         // error
 670  0
         for (final Entry<Key, Value> e : map.entrySet()) {
 671  0
             if (recurse && e.getValue().getType().equals(Data.class)) {
 672  0
                 Data value = e.getValue().get();
 673  0
                 if (value != null) {
 674  0
                     value = value.copy();
 675  
                 }
 676  0
                 target.map.put(e.getKey(), new DataValue(value));
 677  0
             } else {
 678  0
                 target.map.put(e.getKey(), e.getValue());
 679  
             }
 680  
         }
 681  0
         return target;
 682  
     }
 683  
 
 684  
     public <T> T get(final Integer key) {
 685  0
         final Value v = map.get(new IntegerKey(key));
 686  0
         T result = null;
 687  0
         if (v != null) {
 688  0
             result = (T) v.get();
 689  
         }
 690  0
         return result;
 691  
     }
 692  
 
 693  
     public <T> T get(final Key key) {
 694  27
         final Value v = map.get(key);
 695  27
         T result = null;
 696  27
         if (v != null) {
 697  22
             result = (T) v.get();
 698  
         }
 699  27
         return result;
 700  
     }
 701  
 
 702  
     public <T> T get(final String key) {
 703  11
         final Value v = map.get(new StringKey(key));
 704  11
         T result = null;
 705  11
         if (v != null) {
 706  7
             result = (T) v.get();
 707  
         }
 708  11
         return result;
 709  
     }
 710  
 
 711  
     public String getClassName() {
 712  0
         return this.className;
 713  
     }
 714  
 
 715  
     public Data getParent() {
 716  0
         return parent;
 717  
     }
 718  
 
 719  
     public QueryPath getQueryPath() {
 720  27
         final QueryPath result = new QueryPath();
 721  27
         _getQueryPath(result);
 722  27
         return result;
 723  
     }
 724  
 
 725  
 
 726  
     /**
 727  
      * @return an Iterator that does not contain any _runtimeData
 728  
      */
 729  
     public Iterator<Property> realPropertyIterator() {
 730  1
         HashMap<Key, Value> propertyMap = new HashMap<Key, Value>(map);
 731  
 //            propertyMap.remove("_runtimeData");
 732  1
         propertyMap.remove(new StringKey("_runtimeData"));
 733  
 
 734  1
         final Iterator<Map.Entry<Key, Value>> impl = propertyMap.entrySet().iterator();
 735  
 
 736  1
         return new Iterator<Property>() {
 737  
             Map.Entry<Key, Value> current;
 738  
 
 739  
             @Override
 740  
             public boolean hasNext() {
 741  2
                 return impl.hasNext();
 742  
             }
 743  
 
 744  
             @Override
 745  
             public Property next() {
 746  1
                 final Map.Entry<Key, Value> entry = impl.next();
 747  1
                 current = entry;
 748  1
                 return new Property() {
 749  
                     @Override
 750  
                     public <T> T getKey() {
 751  0
                         return (T) entry.getKey().get();
 752  
                     }
 753  
 
 754  
                     @Override
 755  
                     public Class<?> getKeyType() {
 756  0
                         return entry.getKey().getType();
 757  
                     }
 758  
 
 759  
                     @Override
 760  
                     public <T> T getValue() {
 761  1
                         return (T) entry.getValue().get();
 762  
                     }
 763  
 
 764  
                     @Override
 765  
                     public Class<?> getValueType() {
 766  0
                         return entry.getValue().getType();
 767  
                     }
 768  
 
 769  
                     @Override
 770  
                     public Key getWrappedKey() {
 771  0
                         return entry.getKey();
 772  
                     }
 773  
 
 774  
                     @Override
 775  
                     public Value getWrappedValue() {
 776  0
                         return entry.getValue();
 777  
                     }
 778  
                 };
 779  
             }
 780  
 
 781  
             @Override
 782  
             public void remove() {
 783  0
                 impl.remove();
 784  0
                 QueryPath path = getQueryPath();
 785  0
                 path.add(current.getKey());
 786  0
                 execChangeCallbacks(ChangeType.REMOVE, path);
 787  0
             }
 788  
         };
 789  
     }
 790  
 
 791  
     /*
 792  
     * (non-Javadoc)
 793  
     *
 794  
     * @see java.lang.Iterable#iterator()
 795  
     */
 796  
 
 797  
     @Override
 798  
     public Iterator<Property> iterator() {
 799  0
         final Iterator<Map.Entry<Key, Value>> impl = map.entrySet().iterator();
 800  
 
 801  0
         return new Iterator<Property>() {
 802  
             Map.Entry<Key, Value> current;
 803  
 
 804  
             @Override
 805  
             public boolean hasNext() {
 806  0
                 return impl.hasNext();
 807  
             }
 808  
 
 809  
             @Override
 810  
             public Property next() {
 811  0
                 final Map.Entry<Key, Value> entry = impl.next();
 812  0
                 current = entry;
 813  0
                 return new Property() {
 814  
                     @Override
 815  
                     public <T> T getKey() {
 816  0
                         return (T) entry.getKey().get();
 817  
                     }
 818  
 
 819  
                     @Override
 820  
                     public Class<?> getKeyType() {
 821  0
                         return entry.getKey().getType();
 822  
                     }
 823  
 
 824  
                     @Override
 825  
                     public <T> T getValue() {
 826  0
                         return (T) entry.getValue().get();
 827  
                     }
 828  
 
 829  
                     @Override
 830  
                     public Class<?> getValueType() {
 831  0
                         return entry.getValue().getType();
 832  
                     }
 833  
 
 834  
                     @Override
 835  
                     public Key getWrappedKey() {
 836  0
                         return entry.getKey();
 837  
                     }
 838  
 
 839  
                     @Override
 840  
                     public Value getWrappedValue() {
 841  0
                         return entry.getValue();
 842  
                     }
 843  
                 };
 844  
             }
 845  
 
 846  
             @Override
 847  
             public void remove() {
 848  0
                 impl.remove();
 849  0
                 QueryPath path = getQueryPath();
 850  0
                 path.add(current.getKey());
 851  0
                 execChangeCallbacks(ChangeType.REMOVE, path);
 852  0
             }
 853  
         };
 854  
     }
 855  
 
 856  
     public <T> T query(final QueryPath path) {
 857  1
         T result = null;
 858  1
         Data d = this;
 859  1
         for (final Iterator itr = path.iterator(); itr.hasNext() && d != null;) {
 860  1
             final Key k = (Key) itr.next();
 861  1
             if (itr.hasNext()) {
 862  1
                 Object obj = d.get(k);
 863  1
                 if (obj != null && !(obj instanceof Data)) {
 864  
                     // TODO what should be done if we try to query
 865  
                     // cluset/clus/0/_runtimeData where cluset/0 returns a string instead of Data
 866  
                     // throw an exception here?
 867  0
                     throw new java.lang.IllegalArgumentException();
 868  
                 } else {
 869  1
                     d = d.get(k);
 870  
                 }
 871  1
             } else {
 872  0
                 result = (T) d.get(k);
 873  
             }
 874  1
         }
 875  1
         return result;
 876  
     }
 877  
 
 878  
     public <T> T query(final String path) {
 879  1
         return (T) query(QueryPath.parse(path));
 880  
     }
 881  
 
 882  
     public Class<?> getType(final QueryPath path) {
 883  0
         Value result = null;
 884  0
         Data d = this;
 885  0
         for (final Iterator itr = path.iterator(); itr.hasNext();) {
 886  0
             final Key k = (Key) itr.next();
 887  0
             if (itr.hasNext()) {
 888  0
                 d = d.get(k);
 889  
             } else {
 890  0
                 result = map.get(k);
 891  
             }
 892  0
         }
 893  0
         return result.getType();
 894  
 
 895  
     }
 896  
 
 897  
     public void set(final Integer key, final Boolean value) {
 898  0
         put(new IntegerKey(key), new BooleanValue(value));
 899  0
     }
 900  
 
 901  
     public void set(final Integer key, final Data value) {
 902  0
         final Key k = new IntegerKey(key);
 903  0
         put(k, new DataValue(value));
 904  0
         if (value != null) {
 905  0
             value.parent = this;
 906  0
             value.parentKey = k;
 907  
         }
 908  0
     }
 909  
 
 910  
     public void set(final Integer key, final Date value) {
 911  0
         put(new IntegerKey(key), new DateValue(value));
 912  0
     }
 913  
 
 914  
     public void set(final Integer key, final Double value) {
 915  0
         put(new IntegerKey(key), new DoubleValue(value));
 916  0
     }
 917  
 
 918  
     public void set(final Integer key, final Float value) {
 919  0
         put(new IntegerKey(key), new FloatValue(value));
 920  0
     }
 921  
 
 922  
     public void set(final Integer key, final Integer value) {
 923  0
         put(new IntegerKey(key), new IntegerValue(value));
 924  0
     }
 925  
 
 926  
     public void set(final Integer key, final Long value) {
 927  0
         put(new IntegerKey(key), new LongValue(value));
 928  0
     }
 929  
 
 930  
     public void set(final Integer key, final Short value) {
 931  0
         put(new IntegerKey(key), new ShortValue(value));
 932  0
     }
 933  
 
 934  
     public void set(final Integer key, final String value) {
 935  0
         put(new IntegerKey(key), new StringValue(value));
 936  0
     }
 937  
 
 938  
     public void set(final Integer key, final Time value) {
 939  0
         put(new IntegerKey(key), new TimeValue(value));
 940  0
     }
 941  
 
 942  
     public void set(final Integer key, final Timestamp value) {
 943  0
         put(new IntegerKey(key), new TimestampValue(value));
 944  0
     }
 945  
 
 946  
     public void set(final Key key, final Boolean value) {
 947  0
         put(key, new BooleanValue(value));
 948  0
     }
 949  
 
 950  
     public void set(final Key key, final Data value) {
 951  0
         put(key, new DataValue(value));
 952  0
         if (value != null) {
 953  0
             value.parent = this;
 954  0
             value.parentKey = key;
 955  
         }
 956  0
     }
 957  
 
 958  
     public void set(final Key key, final Date value) {
 959  0
         put(key, new DateValue(value));
 960  0
     }
 961  
 
 962  
     public void set(final Key key, final Double value) {
 963  0
         put(key, new DoubleValue(value));
 964  0
     }
 965  
 
 966  
     public void set(final Key key, final Float value) {
 967  0
         put(key, new FloatValue(value));
 968  0
     }
 969  
 
 970  
     public void set(final Key key, final Integer value) {
 971  0
         put(key, new IntegerValue(value));
 972  0
     }
 973  
 
 974  
     public void set(final Key key, final Long value) {
 975  0
         put(key, new LongValue(value));
 976  0
     }
 977  
 
 978  
     public void set(final Key key, final Short value) {
 979  0
         put(key, new ShortValue(value));
 980  0
     }
 981  
 
 982  
     public void set(final Key key, final String value) {
 983  0
         put(key, new StringValue(value));
 984  0
     }
 985  
 
 986  
     public void set(final Key key, final Time value) {
 987  0
         put(key, new TimeValue(value));
 988  0
     }
 989  
 
 990  
     public void set(final Key key, final Timestamp value) {
 991  0
         put(key, new TimestampValue(value));
 992  0
     }
 993  
 
 994  
     public void set(final Key key, final Value value) {
 995  0
         put(key, value);
 996  0
         if (value instanceof DataValue) {
 997  0
             final Data d = value.get();
 998  0
             if (d != null) {
 999  0
                 d.parent = this;
 1000  0
                 d.parentKey = key;
 1001  
             }
 1002  
         }
 1003  0
     }
 1004  
 
 1005  
     public void set(final String key, final Boolean value) {
 1006  0
         put(new StringKey(key), new BooleanValue(value));
 1007  0
     }
 1008  
 
 1009  
     public void set(final String key, final Data value) {
 1010  1
         final Key k = new StringKey(key);
 1011  1
         put(k, new DataValue(value));
 1012  1
         if (value != null) {
 1013  1
             value.parent = this;
 1014  1
             value.parentKey = k;
 1015  
         }
 1016  1
     }
 1017  
 
 1018  
     public void set(final String key, final Date value) {
 1019  1
         put(new StringKey(key), new DateValue(value));
 1020  1
     }
 1021  
 
 1022  
     public void set(final String key, final Double value) {
 1023  1
         put(new StringKey(key), new DoubleValue(value));
 1024  1
     }
 1025  
 
 1026  
     public void set(final String key, final Float value) {
 1027  0
         put(new StringKey(key), new FloatValue(value));
 1028  0
     }
 1029  
 
 1030  
     public void set(final String key, final Integer value) {
 1031  0
         put(new StringKey(key), new IntegerValue(value));
 1032  0
     }
 1033  
 
 1034  
     public void set(final String key, final Long value) {
 1035  0
         put(new StringKey(key), new LongValue(value));
 1036  0
     }
 1037  
 
 1038  
     public void set(final String key, final Short value) {
 1039  0
         put(new StringKey(key), new ShortValue(value));
 1040  0
     }
 1041  
 
 1042  
     public void set(final String key, final String value) {
 1043  23
         put(new StringKey(key), new StringValue(value));
 1044  23
     }
 1045  
 
 1046  
     public void set(final String key, final Time value) {
 1047  0
         put(new StringKey(key), new TimeValue(value));
 1048  0
     }
 1049  
 
 1050  
     public void set(final String key, final Timestamp value) {
 1051  0
         put(new StringKey(key), new TimestampValue(value));
 1052  0
     }
 1053  
 
 1054  
     public Integer size() {
 1055  0
         return map.size();
 1056  
     }
 1057  
 
 1058  
     public String toString() {
 1059  0
             return _toXmlString("");
 1060  
     }
 1061  
         
 1062  
     /**
 1063  
      * Converts the data map to a bracketed string representation
 1064  
      * @return
 1065  
      */
 1066  
     private String _toString(){
 1067  0
         StringBuffer dataString = new StringBuffer();
 1068  
 
 1069  0
         dataString.append("{");
 1070  0
         for (Iterator itr = this.iterator(); itr.hasNext();) {
 1071  0
             Property p = (Property) itr.next();
 1072  0
             dataString.append(p.getKey() + "=" + p.getValue());
 1073  0
             if (itr.hasNext()) {
 1074  0
                 dataString.append(", ");
 1075  
             }
 1076  0
         }
 1077  0
         dataString.append("}");
 1078  
 
 1079  0
         return dataString.toString();
 1080  
     }
 1081  
     
 1082  
     /**
 1083  
      * Converts the data map to an xml representation
 1084  
      * 
 1085  
      */
 1086  
     private String _toXmlString(String indent){
 1087  0
         StringBuffer dataString = new StringBuffer();
 1088  
                 
 1089  0
             for (Iterator itr = this.iterator(); itr.hasNext();) {
 1090  0
             Property p = (Property) itr.next();
 1091  0
             Object value = p.getValue();
 1092  0
             if (value instanceof Data){                    
 1093  0
                     if (p.getKey() instanceof Integer){
 1094  0
                             dataString.append(indent + "<listitem index=\"" + p.getKey() + "\">\n");
 1095  0
                             dataString.append(((Data)value)._toXmlString(indent + "  "));
 1096  0
                         dataString.append(indent + "</listitem>\n");                            
 1097  
                     } else {
 1098  0
                             dataString.append(indent + "<" + p.getKey() + ">\n");
 1099  0
                                 dataString.append(((Data)value)._toXmlString(indent + "  "));
 1100  0
                             dataString.append(indent + "</" + p.getKey() + ">\n");
 1101  
                     }
 1102  0
             } else if (p.getKey() instanceof Integer){
 1103  0
                     dataString.append(indent + "<listitem index=\"" + p.getKey() + "\" value=\""+ value + "\"/>\n");
 1104  
             } else {
 1105  0
                     dataString.append(indent + "<" + p.getKey() + " value=\""+ value + "\"/>\n");                    
 1106  
             }
 1107  0
         }
 1108  
 
 1109  0
         return dataString.toString();
 1110  
     }
 1111  
 
 1112  
     public boolean containsKey(Key key) {
 1113  0
         return map.containsKey(key);
 1114  
     }
 1115  
 
 1116  
     public boolean containsValue(Value value) {
 1117  0
         return map.containsValue(value);
 1118  
     }
 1119  
 
 1120  
     /**
 1121  
      * @return set of top level keys known to this data branch
 1122  
      */
 1123  
     public Set keySet() {
 1124  2
         return map.keySet();
 1125  
     }
 1126  
 
 1127  
     public boolean isEmpty() {
 1128  0
         return map.isEmpty();
 1129  
     }
 1130  
 }