001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.schematic.document; 017 018import java.io.Serializable; 019import java.util.Date; 020import java.util.List; 021import java.util.Map; 022import java.util.Properties; 023import java.util.Set; 024import java.util.UUID; 025import java.util.regex.Pattern; 026import org.modeshape.schematic.SchemaLibrary; 027 028/** 029 * Primary read-only interface for an in-memory representation of JSON/BSON objects. 030 * 031 * @author Randall Hauch <rhauch@redhat.com> (C) 2011 Red Hat Inc. 032 */ 033public interface Document extends Serializable { 034 035 /** 036 * Gets the value in this document for the given field name. 037 * 038 * @param name The name of the pair 039 * @return The field value, if found, or null otherwise 040 */ 041 Object get( String name ); 042 043 /** 044 * Get the boolean value in this document for the given field name. 045 * 046 * @param name The name of the pair 047 * @return The boolean field value, if found, or null if there is no such pair or if the value is not a boolean 048 */ 049 Boolean getBoolean( String name ); 050 051 /** 052 * Get the boolean value in this document for the given field name. 053 * 054 * @param name The name of the pair 055 * @param defaultValue the default value to return if there is no such pair or if the value is not a boolean 056 * @return The boolean field value if found, or <code>defaultValue</code> if there is no such pair or if the value is not a 057 * boolean 058 */ 059 boolean getBoolean( String name, 060 boolean defaultValue ); 061 062 /** 063 * Get the integer value in this document for the given field name. 064 * 065 * @param name The name of the pair 066 * @return The integer field value, if found, or null if there is no such pair or if the value is not an integer 067 */ 068 Integer getInteger( String name ); 069 070 /** 071 * Get the integer value in this document for the given field name. 072 * 073 * @param name The name of the pair 074 * @param defaultValue the default value to return if there is no such pair or if the value is not a integer 075 * @return The integer field value if found, or <code>defaultValue</code> if there is no such pair or if the value is not a 076 * integer 077 */ 078 int getInteger( String name, 079 int defaultValue ); 080 081 /** 082 * Get the integer value in this document for the given field name. 083 * 084 * @param name The name of the pair 085 * @return The long field value, if found, or null if there is no such pair or if the value is not a long value 086 */ 087 Long getLong( String name ); 088 089 /** 090 * Get the long value in this document for the given field name. 091 * 092 * @param name The name of the pair 093 * @param defaultValue the default value to return if there is no such pair or if the value is not a long value 094 * @return The long field value if found, or <code>defaultValue</code> if there is no such pair or if the value is not a long 095 * value 096 */ 097 long getLong( String name, 098 long defaultValue ); 099 100 /** 101 * Get the double value in this document for the given field name. 102 * 103 * @param name The name of the pair 104 * @return The double field value, if found, or null if there is no such pair or if the value is not a double 105 */ 106 Double getDouble( String name ); 107 108 /** 109 * Get the double value in this document for the given field name. 110 * 111 * @param name The name of the pair 112 * @param defaultValue the default value to return if there is no such pair or if the value is not a double 113 * @return The double field value if found, or <code>defaultValue</code> if there is no such pair or if the value is not a 114 * double 115 */ 116 double getDouble( String name, 117 double defaultValue ); 118 119 /** 120 * Get the number value in this document for the given field name. 121 * 122 * @param name The name of the pair 123 * @return The double field value, if found, or null if there is no such pair or if the value is not a number 124 */ 125 Number getNumber( String name ); 126 127 /** 128 * Get the number value in this document for the given field name. 129 * 130 * @param name The name of the pair 131 * @param defaultValue the default value to return if there is no such pair or if the value is not a number 132 * @return The number field value if found, or <code>defaultValue</code> if there is no such pair or if the value is not a 133 * number 134 */ 135 Number getNumber( String name, 136 Number defaultValue ); 137 138 /** 139 * Get the string value in this document for the given field name. This method will return the string even if the actual value 140 * is a {@link Symbol}. 141 * 142 * @param name The name of the pair 143 * @return The string field value, if found, or null if there is no such pair or if the value is not a string 144 */ 145 String getString( String name ); 146 147 /** 148 * Get the string value in this document for the given field name. This method will return the string even if the actual value 149 * is a {@link Symbol}. 150 * 151 * @param name The name of the pair 152 * @param defaultValue the default value to return if there is no such pair or if the value is not a string 153 * @return The string field value if found, or <code>defaultValue</code> if there is no such pair or if the value is not a 154 * string 155 */ 156 String getString( String name, 157 String defaultValue ); 158 159 /** 160 * Get the array value in this document for the given field name. 161 * 162 * @param name The name of the pair 163 * @return The array field value (as a list), if found, or null if there is no such pair or if the value is not an array 164 */ 165 List<?> getArray( String name ); 166 167 /** 168 * Get the document value in this document for the given field name. 169 * 170 * @param name The name of the pair 171 * @return The document field value, if found, or null if there is no such pair or if the value is not a document 172 */ 173 Document getDocument( String name ); 174 175 /** 176 * Determine whether this object has a pair with the given the name and the value is null. This is equivalent to calling: 177 * 178 * <pre> 179 * this.get(name) instanceof Null; 180 * </pre> 181 * 182 * @param name The name of the pair 183 * @return <code>true</code> if the field has been set to a {@link Null} value, or false otherwise 184 * @see #isNullOrMissing(String) 185 */ 186 boolean isNull( String name ); 187 188 /** 189 * Determine whether this object has a pair with the given the name and the value is null, or if this object has no field with 190 * the given name. This is equivalent to calling: 191 * 192 * <pre> 193 * Null.matches(this.get(name)); 194 * </pre> 195 * 196 * @param name The name of the pair 197 * @return <code>true</code> if the field value for the name is null or if there is no such field. 198 * @see #isNull(String) 199 */ 200 boolean isNullOrMissing( String name ); 201 202 /** 203 * Get the {@link MaxKey} value in this document for the given field name. 204 * 205 * @param name The name of the pair 206 * @return The {@link MaxKey} field value, if found, or null if there is no such pair or if the value is not a {@link MaxKey} 207 */ 208 MaxKey getMaxKey( String name ); 209 210 /** 211 * Get the {@link MinKey} value in this document for the given field name. 212 * 213 * @param name The name of the pair 214 * @return The {@link MinKey} field value, if found, or null if there is no such pair or if the value is not a {@link MinKey} 215 */ 216 MinKey getMinKey( String name ); 217 218 /** 219 * Get the {@link Code} value in this document for the given field name. 220 * 221 * @param name The name of the pair 222 * @return The {@link Code} field value, if found, or null if there is no such pair or if the value is not a {@link Code} 223 */ 224 Code getCode( String name ); 225 226 /** 227 * Get the {@link CodeWithScope} value in this document for the given field name. 228 * 229 * @param name The name of the pair 230 * @return The {@link CodeWithScope} field value, if found, or null if there is no such pair or if the value is not a 231 * {@link CodeWithScope} 232 */ 233 CodeWithScope getCodeWithScope( String name ); 234 235 /** 236 * Get the {@link ObjectId} value in this document for the given field name. 237 * 238 * @param name The name of the pair 239 * @return The {@link ObjectId} field value, if found, or null if there is no such pair or if the value is not a 240 * {@link ObjectId} 241 */ 242 ObjectId getObjectId( String name ); 243 244 /** 245 * Get the {@link Binary} value in this document for the given field name. 246 * 247 * @param name The name of the pair 248 * @return The {@link Binary} field value, if found, or null if there is no such pair or if the value is not a {@link Binary} 249 */ 250 Binary getBinary( String name ); 251 /** 252 * Get the {@link Date} value in this document for the given field name. 253 * 254 * @param name The name of the pair 255 * @return The {@link Date} field value, if found, or null if there is no such pair or if the value is not a {@link Date} 256 */ 257 Date getDate( String name ); 258 259 /** 260 * Get the {@link Symbol} value in this document for the given field name. 261 * 262 * @param name The name of the pair 263 * @return The {@link Symbol} field value, if found, or null if there is no such pair or if the value is not a {@link Symbol} 264 */ 265 Symbol getSymbol( String name ); 266 267 /** 268 * Get the {@link Pattern} value in this document for the given field name. 269 * 270 * @param name The name of the pair 271 * @return The {@link Pattern} field value, if found, or null if there is no such pair or if the value is not a 272 * {@link Pattern} 273 */ 274 Pattern getPattern( String name ); 275 276 /** 277 * Get the {@link UUID} value in this document for the given field name. 278 * 279 * @param name The name of the pair 280 * @return The {@link UUID} field value, if found, or null if there is no such pair or if the value is not a {@link UUID} 281 */ 282 UUID getUuid( String name ); 283 284 /** 285 * Get the {@link UUID} value in this document for the given field name. 286 * 287 * @param name The name of the pair 288 * @param defaultValue the default value to return if there is no such pair or if the value is not a string 289 * @return The {@link UUID} field value if found, or <code>defaultValue</code> if there is no such pair or if the value is not 290 * a UUID (or a string that is convertable from a UUID) 291 */ 292 UUID getUuid( String name, 293 UUID defaultValue ); 294 295 /** 296 * Get the {@link Bson.Type} constant that describes the type of value for the given field name. 297 * 298 * @param name The name of the pair 299 * @return the {@link Bson.Type} constant describing the value, or -1 if there is no field with the supplied name 300 */ 301 int getType( String name ); 302 303 /** 304 * Returns a map representing this BSONObject. 305 * 306 * @return the map 307 */ 308 Map<String, ?> toMap(); 309 310 /** 311 * Obtain an iterator over the {@link Field}s in this object. 312 * 313 * @return a field iterator; never null 314 */ 315 Iterable<Field> fields(); 316 317 /** 318 * Checks if this object contains a field with the given name. 319 * 320 * @param name The name of the pair for which to check 321 * @return true if this document contains a field with the supplied name, or false otherwise 322 */ 323 boolean containsField( String name ); 324 325 /** 326 * Checks if this object contains all of the fields in the supplied document. 327 * 328 * @param document The document with the fields that should be in this document 329 * @return true if this document contains all of the fields in the supplied document, or false otherwise 330 */ 331 boolean containsAll( Document document ); 332 333 /** 334 * Returns this object's fields' names 335 * 336 * @return The names of the fields in this object 337 */ 338 Set<String> keySet(); 339 340 /** 341 * Return the number of name-value pairs in this object. 342 * 343 * @return the number of name-value pairs; never negative 344 */ 345 int size(); 346 347 /** 348 * Return whether this document contains no fields and is therefore empty. 349 * 350 * @return true if there are no fields in this document, or false if there is at least one. 351 */ 352 boolean isEmpty(); 353 354 /** 355 * Obtain a clone of this document. 356 * 357 * @return the clone of this document; never null 358 */ 359 Document clone(); 360 361 /** 362 * Obtain a clone of this document, but with the supplied fields replaced. 363 * 364 * @param changedFields the fields that should be changed; may be null 365 * @return the clone of this document with the change fields, or this document if there are no changes 366 */ 367 Document with( Map<String, Object> changedFields ); 368 369 /** 370 * Obtain a clone of this document, but with the supplied fields replaced. 371 * 372 * @param fieldName the name of the file that should be changed; may be null 373 * @param value the new value for the field 374 * @return the clone of this document with the change fields, or this document if there are no changes 375 */ 376 Document with( String fieldName, 377 Object value ); 378 379 /** 380 * Obtain a clone of this document, but with the field values transformed using the supplied {@link ValueTransformer}. 381 * 382 * @param transformer the transformer that should be used to transform each field value; may not be null 383 * @return the clone of this document with transformed fields, or this document if the transformer changed none of the values 384 */ 385 Document with( ValueTransformer transformer ); 386 387 /** 388 * Obtain a clone of this document, but with all variables in string field values replaced with the referenced values from the 389 * supplied properties. 390 * <p> 391 * Variables may appear anywhere within a string value, and multiple variables can be used within the same value. Variables 392 * take the form: 393 * 394 * <pre> 395 * variable := '${' variableNames [ ':' defaultValue ] '}' 396 * 397 * variableNames := variableName [ ',' variableNames ] 398 * 399 * variableName := /* any characters except ',' and ':' and '}' 400 * 401 * defaultValue := /* any characters except 402 * </pre> 403 * 404 * Note that <i>variableName</i> is the name used to look up the {@link Properties} property. 405 * </p> 406 * Notice that the syntax supports multiple <i>variables</i>. The logic will process the <i>variables</i> from let to right, 407 * until an existing System property is found. And at that point, it will stop and will not attempt to find values for the 408 * other <i>variables</i>. 409 * <p> 410 * 411 * @param properties the properties keyed by variable name 412 * @return the clone of this document with variables in fields string values replaced with values from the properties object, 413 * or this document if no variables were found 414 * @see #withVariablesReplacedWithSystemProperties() 415 * @see #with(ValueTransformer) 416 * @see SchemaLibrary#convertValues(Document, String) 417 */ 418 Document withVariablesReplaced( Properties properties ); 419 420 /** 421 * Obtain a clone of this document, but with all variables in string field values replaced with the referenced values from the 422 * System properties. 423 * <p> 424 * Variables may appear anywhere within a string value, and multiple variables can be used within the same value. Variables 425 * take the form: 426 * 427 * <pre> 428 * variable := '${' variableNames [ ':' defaultValue ] '}' 429 * 430 * variableNames := variableName [ ',' variableNames ] 431 * 432 * variableName := /* any characters except ',' and ':' and '}' 433 * 434 * defaultValue := /* any characters except 435 * </pre> 436 * 437 * Note that <i>variableName</i> is the name used to look up a System property via {@link System#getProperty(String)}. 438 * </p> 439 * Notice that the syntax supports multiple <i>variables</i>. The logic will process the <i>variables</i> from let to right, 440 * until an existing System property is found. And at that point, it will stop and will not attempt to find values for the 441 * other <i>variables</i>. 442 * <p> 443 * <p> 444 * Because only string values can contain variables, the resulting values are left as strings. This may not be valid according 445 * to the document's JSON Schema, so see {@link SchemaLibrary#convertValues(Document, String)} to convert the string values 446 * after variable substitution into the expected non-string types. 447 * </p> 448 * 449 * @return the clone of this document with variables in fields string values replaced with values from the System properties, 450 * or this document if no variables were found 451 * @see #withVariablesReplaced(Properties) 452 * @see #with(ValueTransformer) 453 * @see SchemaLibrary#convertValues(Document, String) 454 */ 455 Document withVariablesReplacedWithSystemProperties(); 456 457 /** 458 * Obtains an editor for the supplied document. The editor allows the caller to make changes to the document and to obtain 459 * these changes as a {@link Changes serializable memento} that can be applied to another document. 460 * 461 * @return an {@link Editor} instance which can used to change the document; never {@code null} 462 */ 463 Editor edit(boolean clone); 464 465 /** 466 * Returns an editable view of the given document. Any changes will be reflected directly in the underlying document 467 * 468 * @return a {@link EditableDocument} instance, never {@code null} 469 */ 470 EditableDocument editable(); 471 472 /** 473 * A component that can transform field values, via {@link Document#with(ValueTransformer)}. Implementations do not need to 474 * worry about {@link Document} values, since the transformer is never called on such values. 475 */ 476 interface ValueTransformer { 477 /** 478 * Transform the supplied field value. 479 * 480 * @param name the name of the field; never null 481 * @param value the existing value for the field 482 * @return the transformed value; never null but may be the same <code>value</code> object if no transformation should be 483 * made 484 */ 485 Object transform( String name, 486 Object value ); 487 } 488 489 interface Field extends Comparable<Field> { 490 491 /** 492 * Get the name of the field 493 * 494 * @return the field's name; never null 495 */ 496 String getName(); 497 498 /** 499 * Get the value of the field. 500 * 501 * @return the field's value; may be null 502 */ 503 Object getValue(); 504 505 String getValueAsString(); 506 507 Integer getValueAsInt(); 508 509 boolean getValueAsBoolean(); 510 511 Binary getValueAsBinary(); 512 513 Number getValueAsNumber(); 514 515 Pattern getValueAsPattern(); 516 517 Double getValueAsDouble(); 518 519 UUID getValueAsUuid(); 520 521 Document getValueAsDocument(); 522 } 523}