001package conexp.fx.core.xml; 002 003/* 004 * #%L 005 * Concept Explorer FX 006 * %% 007 * Copyright (C) 2010 - 2023 Francesco Kriegel 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025 026import java.util.Iterator; 027import java.util.List; 028import java.util.Map; 029 030import conexp.fx.core.collections.Collections3; 031 032public class Data<T> { 033 034 protected final Datatype type; 035 protected final String key; 036 protected T value; 037 038 public Data(final Datatype type, final String key, final T value) throws NullPointerException, 039 IndexOutOfBoundsException { 040 super(); 041 if (type == null) 042 throw new NullPointerException("Unable to create data without type"); 043 if (key == null) 044 throw new IndexOutOfBoundsException("Unable to create data without keys"); 045// if (value == null) 046// throw new NullPointerException("Unable to create data without value"); 047 this.type = type; 048 this.key = key; 049 this.value = value; 050 } 051 052 @Override 053 public boolean equals(Object object) { 054 if (object == null) 055 return false; 056 if (!(object instanceof Data)) 057 return false; 058 final Data<?> other = (Data<?>) object; 059 if (!this.type.equals(other.type)) 060 return false; 061 if (!this.key.equals(other.key)) 062 return false; 063 if (!this.value.equals(other.value)) 064 return false; 065 return true; 066 } 067 068 @Override 069 public int hashCode() { 070 return 1 + 2 * type.hashCode() + 3 * key.hashCode() + 5 * value.hashCode(); 071 } 072 073 @Override 074 public String toString() { 075 return toString(""); 076 } 077 078 private static final String PREFIX = "| "; 079 080 private final String toString(final String prefix) { 081 switch (type) { 082 case STRING: 083 return prefix + key + " (" + type + ") = \"" + value.toString() + "\""; 084 case BOOLEAN: 085 case INTEGER: 086 case BOOLEAN_LIST: 087 case INTEGER_LIST: 088 case STRING_LIST: 089 return prefix + key + " (" + type + ") = " + value.toString(); 090 case METADATA: 091 case COMPOUND: 092 return prefix + key + " (" + type + ")\r\n"; 093 case COMPOUND_LIST: 094 return prefix + key + " (" + type + ")" 095 + toString(prefix + PREFIX, this.toCompoundListData().getSubkey(), this.toCompoundListData().getValue()); 096 default: 097 return prefix + key + " (" + type + ")\r\n"; 098 } 099 } 100 101 private final String toString(final String prefix, final String subkey, final List<Map<String, Data<?>>> list) { 102 String string = ""; 103 for (Map<String, Data<?>> map : list) 104 string += "\r\n" + prefix + subkey + "\r\n" + toString(prefix + PREFIX, map); 105 return string; 106 } 107 108 private final String toString(final String prefix, final Map<String, Data<?>> map) { 109 final Iterator<String> keys = Collections3.sort(map.keySet()).iterator(); 110 String string = ""; 111 if (keys.hasNext()) 112 string += map.get(keys.next()).toString(prefix); 113 while (keys.hasNext()) 114 string += "\r\n" + map.get(keys.next()).toString(prefix); 115 return string; 116 } 117 118 public final Datatype getType() { 119 return type; 120 } 121 122 public final String getKey() { 123 return new String(key); 124 } 125 126 public final T getValue() { 127 return value; 128 } 129 130 public final T setValue(T value) throws NullPointerException { 131 if (value == null) 132 throw new NullPointerException("Unable to set null value on data"); 133 final T previous = this.value; 134 this.value = value; 135 return previous; 136 } 137 138 public final boolean isBooleanData() { 139 return getType().equals(Datatype.BOOLEAN); 140 } 141 142 public final BooleanData toBooleanData() throws ClassCastException { 143 if (!isBooleanData()) 144 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.BOOLEAN); 145 return (BooleanData) this; 146 } 147 148 public final Boolean getBooleanValue() { 149 return toBooleanData().getValue(); 150 } 151 152 public final void setBooleanValue(final Boolean value) { 153 toBooleanData().setValue(value); 154 } 155 156 public final boolean isIntegerData() { 157 return getType().equals(Datatype.INTEGER); 158 } 159 160 public final IntegerData toIntegerData() throws ClassCastException { 161 if (!isIntegerData()) 162 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.INTEGER); 163 return (IntegerData) this; 164 } 165 166 public final Integer getIntegerValue() { 167 return toIntegerData().getValue(); 168 } 169 170 public final void setIntegerValue(final Integer value) { 171 toIntegerData().setValue(value); 172 } 173 174 public final boolean isFloatData() { 175 return getType().equals(Datatype.FLOAT); 176 } 177 178 public final FloatData toFloatData() throws ClassCastException { 179 if (!isFloatData()) 180 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.FLOAT); 181 return (FloatData) this; 182 } 183 184 public final Float getFloatValue() { 185 return toFloatData().getValue(); 186 } 187 188 public final void setFloatValue(final Float value) { 189 toFloatData().setValue(value); 190 } 191 192 public final boolean isStringData() { 193 return getType().equals(Datatype.STRING); 194 } 195 196 public final StringData toStringData() throws ClassCastException { 197 if (!isStringData()) 198 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.STRING); 199 return (StringData) this; 200 } 201 202 public final String getStringValue() { 203 return toStringData().getValue(); 204 } 205 206 public final void setStringValue(final String value) { 207 toStringData().setValue(value); 208 } 209 210 public final boolean isCompoundData() { 211 return getType().equals(Datatype.COMPOUND); 212 } 213 214 public final CompoundData toCompoundData() throws ClassCastException { 215 if (!isCompoundData()) 216 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.COMPOUND); 217 return (CompoundData) this; 218 } 219 220 public final Map<String, Data<?>> getCompoundValue() { 221 return toCompoundData().getValue(); 222 } 223 224 public final boolean isListData() { 225 return isBooleanListData() || isIntegerListData() || isStringListData() || isCompoundListData(); 226 } 227 228 public final ListData<?> toListData() throws ClassCastException { 229 if (!isListData()) 230 throw new ClassCastException("Cannot cast data of type " + type + " to LIST"); 231 return (ListData<?>) this; 232 } 233 234 public final List<?> getListValue() { 235 return toListData().getValue(); 236 } 237 238 public final boolean isBooleanListData() { 239 return getType().equals(Datatype.BOOLEAN_LIST); 240 } 241 242 public final BooleanListData toBooleanListData() throws ClassCastException { 243 if (!isBooleanListData()) 244 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.BOOLEAN_LIST); 245 return (BooleanListData) this; 246 } 247 248 public final List<Boolean> getBooleanListValue() { 249 return toBooleanListData().getValue(); 250 } 251 252 public final boolean isIntegerListData() { 253 return getType().equals(Datatype.INTEGER_LIST); 254 } 255 256 public final IntegerListData toIntegerListData() throws ClassCastException { 257 if (!isIntegerListData()) 258 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.INTEGER_LIST); 259 return (IntegerListData) this; 260 } 261 262 public final List<Integer> getIntegerListValue() { 263 return toIntegerListData().getValue(); 264 } 265 266 public final boolean isFloatListData() { 267 return getType().equals(Datatype.FLOAT_LIST); 268 } 269 270 public final FloatListData toFloatListData() throws ClassCastException { 271 if (!isFloatListData()) 272 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.FLOAT_LIST); 273 return (FloatListData) this; 274 } 275 276 public final List<Float> getFloatListValue() { 277 return toFloatListData().getValue(); 278 } 279 280 public final boolean isStringListData() { 281 return getType().equals(Datatype.STRING_LIST); 282 } 283 284 public final StringListData toStringListData() throws ClassCastException { 285 if (!isStringListData()) 286 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.STRING_LIST); 287 return (StringListData) this; 288 } 289 290 public final List<String> getStringListValue() { 291 return toStringListData().getValue(); 292 } 293 294 public final boolean isCompoundListData() { 295 return getType().equals(Datatype.COMPOUND_LIST); 296 } 297 298 public final CompoundListData toCompoundListData() throws ClassCastException { 299 if (!isCompoundListData()) 300 throw new ClassCastException("Cannot cast data of type " + type + " to " + Datatype.COMPOUND_LIST); 301 return (CompoundListData) this; 302 } 303 304 public final List<Map<String, Data<?>>> getCompoundListValue() { 305 return toCompoundListData().getValue(); 306 } 307 308 public final boolean isMetadata() { 309 return getType().equals(Datatype.METADATA); 310 } 311 312 public final boolean isDocument() { 313 return getType().equals(Datatype.DOCUMENT); 314 } 315 316}