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.text.ParseException; 019import java.util.ArrayList; 020import java.util.Date; 021import java.util.Map; 022import java.util.UUID; 023import java.util.regex.Pattern; 024import org.modeshape.schematic.document.Bson.BinaryType; 025import org.modeshape.schematic.internal.document.IncrementalDocumentEditor; 026import org.modeshape.schematic.internal.document.MutableDocument; 027 028public interface EditableDocument extends Document { 029 030 /** 031 * Unwrap this editor to obtain the potentially wrapped document. 032 * 033 * @return the wrapped document, or this object; never null 034 */ 035 Document unwrap(); 036 037 /** 038 * Remove the field with the supplied name, and return the value. 039 * 040 * @param name The name of the field 041 * @return the value that was removed, or null if there was no such value 042 */ 043 Object remove( String name ); 044 045 /** 046 * Returns the underlying mutable document. 047 * 048 * @return a {@link MutableDocument} instance; never null 049 */ 050 MutableDocument asMutableDocument(); 051 052 /** 053 * Remove all fields from this document. 054 */ 055 void removeAll(); 056 057 /** 058 * Sets on this object all name/value pairs from the supplied object. If the supplied object is null, this method does 059 * nothing. 060 * 061 * @param object the object containing the name/value pairs to be set on this object 062 */ 063 void putAll( Document object ); 064 065 /** 066 * Sets on this object all key/value pairs from the supplied map. If the supplied map is null, this method does nothing. 067 * 068 * @param map the map containing the name/value pairs to be set on this object 069 */ 070 void putAll( Map<? extends String, ? extends Object> map ); 071 072 /** 073 * Merges the supplied document onto this document. This will set on this document each of the fields in the supplied 074 * document; nested documents in the supplied document will be merged recursively. 075 * <p> 076 * Consider the following example. If this document contains: 077 * 078 * <pre> 079 * { 080 * "firstName" : "Jane", 081 * "lastName" : "Smith", 082 * "address" : { 083 * "street" : "Main Street", 084 * "city" : "Springfield" 085 * }, 086 * "phone" : "(800)555-1212" 087 * } 088 * </pre> 089 * 090 * and another document 'other' contains: 091 * 092 * <pre> 093 * { 094 * "lastName" : "Doe", 095 * "address" : { 096 * "city" : "Memphis", 097 * "zip" : 12345 098 * }, 099 * "phone" : { 100 * "home" : "(800)555-1212" 101 * } 102 * } 103 * </pre> 104 * 105 * then merging 'other' onto the first will result in the first being modified to contain: 106 * 107 * <pre> 108 * { 109 * "firstName" : "Jane", 110 * "lastName" : "Doe", 111 * "address" : { 112 * "street" : "Main Street", 113 * "city" : "Memphis", 114 * "zip" : 12345 115 * }, 116 * "phone" : { 117 * "home" : "(800)555-1212" 118 * } 119 * } 120 * </pre> 121 * 122 * @param other the other document whose values should be merged 123 */ 124 void merge( Document other ); 125 126 /** 127 * Set the value for the field with the given name to the supplied value. 128 * 129 * @param name The name of the field 130 * @param value the new value for the field 131 * @return This document, to allow for chaining methods 132 */ 133 EditableDocument set( String name, 134 Object value ); 135 136 /** 137 * Set the value for the field with the given name to the supplied boolean value. 138 * 139 * @param name The name of the field 140 * @param value the new value for the field 141 * @return This document, to allow for chaining methods 142 */ 143 EditableDocument setBoolean( String name, 144 boolean value ); 145 146 /** 147 * Set the value for the field with the given name to the supplied integer value. 148 * 149 * @param name The name of the field 150 * @param value the new value for the field 151 * @return This document, to allow for chaining methods 152 */ 153 EditableDocument setNumber( String name, 154 int value ); 155 156 /** 157 * Set the value for the field with the given name to the supplied long value. 158 * 159 * @param name The name of the field 160 * @param value the new value for the field 161 * @return This document, to allow for chaining methods 162 */ 163 EditableDocument setNumber( String name, 164 long value ); 165 166 /** 167 * Set the value for the field with the given name to the supplied float value. 168 * 169 * @param name The name of the field 170 * @param value the new value for the field 171 * @return This document, to allow for chaining methods 172 */ 173 EditableDocument setNumber( String name, 174 float value ); 175 176 /** 177 * Set the value for the field with the given name to the supplied double value. 178 * 179 * @param name The name of the field 180 * @param value the new value for the field 181 * @return This document, to allow for chaining methods 182 */ 183 EditableDocument setNumber( String name, 184 double value ); 185 186 /** 187 * Set the value for the field with the given name to the supplied string value. 188 * 189 * @param name The name of the field 190 * @param value the new value for the field 191 * @return This document, to allow for chaining methods 192 */ 193 EditableDocument setString( String name, 194 String value ); 195 196 /** 197 * Set the value for the field with the given name to a {@link Symbol} created from the supplied string value. Symbols are 198 * defined in the BSON specification as being similar to a string but which exists for those languages that have a specific 199 * symbol type. Symbols are serialized to JSON as a normal string. 200 * 201 * @param name The name of the field 202 * @param value the new value for the field 203 * @return This document, to allow for chaining methods 204 * @see #setString(String, String) 205 */ 206 EditableDocument setSymbol( String name, 207 String value ); 208 209 /** 210 * Set the value for the field with the given name to be a new, empty Document. 211 * 212 * @param name The name of the field 213 * @return The editable document that was just created; never null 214 */ 215 EditableDocument setDocument( String name ); 216 217 /** 218 * Set the value for the field with the given name to be the supplied Document. 219 * 220 * @param name The name of the field 221 * @param document the document 222 * @return The editable document that was just set as the value for the named field; never null and may or may not be the same 223 * instance as the supplied <code>document</code>. 224 */ 225 EditableDocument setDocument( String name, 226 Document document ); 227 228 /** 229 * Get the existing document value in this document for the given field name. 230 * 231 * @param name The name of the pair 232 * @return The editable document field value, if found, or null if there is no such pair or if the value is not a document 233 */ 234 @Override 235 EditableDocument getDocument( String name ); 236 237 /** 238 * Get the existing document value in this document for the given field name, or create a new document if there is no existing 239 * document at this field. 240 * 241 * @param name The name of the pair 242 * @return The editable document field value; never null 243 */ 244 EditableDocument getOrCreateDocument( String name ); 245 246 /** 247 * Set the value for the field with the given name to be a new, empty array. 248 * 249 * @param name The name of the field 250 * @return The editable array that was just created; never null 251 */ 252 EditableArray setArray( String name ); 253 254 /** 255 * Set the value for the field with the given name to be the supplied array. 256 * 257 * @param name The name of the field 258 * @param array the array 259 * @return The editable array that was just set as the value for the named field; never null and may or may not be the same 260 * instance as the supplied <code>array</code>. 261 */ 262 EditableArray setArray( String name, 263 Array array ); 264 265 /** 266 * Set the value for the field with the given name to be the supplied array. 267 * 268 * @param name The name of the field 269 * @param values the (valid) values for the array 270 * @return The editable array that was just set as the value for the named field; never null and may or may not be the same 271 * instance as the supplied <code>array</code>. 272 */ 273 EditableArray setArray( String name, 274 Object... values ); 275 276 /** 277 * Get the existing array value in this document for the given field name. 278 * 279 * @param name The name of the pair 280 * @return The editable array field value (as a list), if found, or null if there is no such pair or if the value is not an 281 * array 282 */ 283 @Override 284 EditableArray getArray( String name ); 285 286 /** 287 * Get the existing array value in this document for the given field name, or create a new array if there is no existing array 288 * at this field. 289 * 290 * @param name The name of the pair 291 * @return The editable array field value; never null 292 */ 293 EditableArray getOrCreateArray( String name ); 294 295 /** 296 * Set the value for the field with the given name to the supplied date value. 297 * 298 * @param name The name of the field 299 * @param value the new value for the field 300 * @return This document, to allow for chaining methods 301 */ 302 EditableDocument setDate( String name, 303 Date value ); 304 305 /** 306 * Set the value for the field with the given name to the date value parsed from the ISO-8601 date representation. 307 * Specifically, the date string must match one of these patterns: 308 * <ul> 309 * <li>"<code><i>yyyy</i>-<i>MM</i>-<i>dd</i>T<i>HH</i>:<i>mm</i>:<i>ss</i></code>" where "<code>T</code>" is a literal 310 * character</li> 311 * <li>"<code><i>yyyy</i>-<i>MM</i>-<i>dd</i>T<i>HH</i>:<i>mm</i>:<i>ss</i>Z</code>" where "<code>T</code>" and " 312 * <code>Z</code>" are literal characters</li> 313 * <li>"<code><i>yyyy</i>-<i>MM</i>-<i>dd</i>T<i>HH</i>:<i>mm</i>:<i>ss</i>GMT+<i>00</i>:<i>00</i></code>" where " 314 * <code>T</code>", and "<code>GMT</code>" are literal characters</li> 315 * </ul> 316 * 317 * @param name The name of the field 318 * @param isoDate the new value for the field 319 * @return This document, to allow for chaining methods 320 * @throws ParseException if the supplied value could not be parsed into a valid date 321 */ 322 EditableDocument setDate( String name, 323 String isoDate ) throws ParseException; 324 325 /** 326 * Set the value for the field with the given name to a {@link Timestamp} with the supplied time in seconds and increment. 327 * Note that {@link Date} values are recommended for most purposes, as they are better suited to most applications' 328 * representations of time instants. 329 * 330 * @param name The name of the field 331 * @param timeInSeconds the time in seconds for the new Timestamp 332 * @param increment the time increment for the new Timestamp 333 * @return This document, to allow for chaining methods 334 * @see #setDate(String, Date) 335 */ 336 EditableDocument setTimestamp( String name, 337 int timeInSeconds, 338 int increment ); 339 340 /** 341 * Set the value for the field with the given name to an {@link ObjectId} created from the supplied hexadecimal binary value. 342 * Object IDs are defined by the BSON specification as 12-byte binary values designed to have a reasonably high probability of 343 * being unique when allocated. Since there is no explicit way to represent these in a JSON document, each ObjectId value is 344 * serialized in a JSON document as a nested document of the form: 345 * 346 * <pre> 347 * { "$oid" : "<i>12bytesOfIdInBase16</i>" } 348 * </pre> 349 * 350 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 351 * be converted to an ObjectId value. 352 * <p> 353 * For example, an ObjectId with time value of "1310745823", machine value of "1", process value of "2", and increment value 354 * of "3" would be written as 355 * 356 * <pre> 357 * { "$oid" : "4e2064df0000010002000003" } 358 * </pre> 359 * 360 * </p> 361 * 362 * @param name The name of the field 363 * @param hex the hexadecimal binary value for the ObjectId 364 * @return This document, to allow for chaining methods 365 * @see #setObjectId(String, byte[]) 366 * @see #setObjectId(String, int, int, int, int) 367 */ 368 EditableDocument setObjectId( String name, 369 String hex ); 370 371 /** 372 * Set the value for the field with the given name to an {@link ObjectId} created from the supplied 12-byte binary value. 373 * Object IDs are defined by the BSON specification as 12-byte binary values designed to have a reasonably high probability of 374 * being unique when allocated. Since there is no explicit way to represent these in a JSON document, each ObjectId value is 375 * serialized in a JSON document as a nested document of the form: 376 * 377 * <pre> 378 * { "$oid" : "<i>12bytesOfIdInBase16</i>" } 379 * </pre> 380 * 381 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 382 * be converted to an ObjectId value. 383 * <p> 384 * For example, an ObjectId with time value of "1310745823", machine value of "1", process value of "2", and increment value 385 * of "3" would be written as 386 * 387 * <pre> 388 * { "$oid" : "4e2064df0000010002000003" } 389 * </pre> 390 * 391 * </p> 392 * 393 * @param name The name of the field 394 * @param bytes the 12-byte value for the ObjectId 395 * @return This document, to allow for chaining methods 396 * @see #setObjectId(String, String) 397 * @see #setObjectId(String, int, int, int, int) 398 */ 399 EditableDocument setObjectId( String name, 400 byte[] bytes ); 401 402 /** 403 * Set the value for the field with the given name to an {@link ObjectId} created from the supplied hexadecimal binary value. 404 * Object IDs are defined by the BSON specification as 12-byte binary values designed to have a reasonably high probability of 405 * being unique when allocated. Since there is no explicit way to represent these in a JSON document, each ObjectId value is 406 * serialized in a JSON document as a nested document of the form: 407 * 408 * <pre> 409 * { "$oid" : "<i>12bytesOfIdInBase16</i>" } 410 * </pre> 411 * 412 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 413 * be converted to an ObjectId value. 414 * <p> 415 * For example, an ObjectId with time value of "1310745823", machine value of "1", process value of "2", and increment value 416 * of "3" would be written as 417 * 418 * <pre> 419 * { "$oid" : "4e2064df0000010002000003" } 420 * </pre> 421 * 422 * </p> 423 * 424 * @param name The name of the field 425 * @param time the Unix-style timestamp, which is a signed integer representing the number of seconds before or after January 426 * 1st 1970 (UTC) 427 * @param machine the first three bytes of the (md5) hash of the machine host name, or of the mac/network address, or the 428 * virtual machine id 429 * @param process the 2 bytes of the process id (or thread id) of the process generating the object id 430 * @param inc an ever incrementing value, or a random number if a counter can't be used in the language/runtime 431 * @return This document, to allow for chaining methods 432 * @see #setObjectId(String, String) 433 * @see #setObjectId(String, byte[]) 434 */ 435 EditableDocument setObjectId( String name, 436 int time, 437 int machine, 438 int process, 439 int inc ); 440 441 /** 442 * Set the value for the field with the given name to the supplied regular expression. Regular expression values are 443 * represented in memory using {@link Pattern} instances, and are stored natively in BSON as regular expressions. However, 444 * when serialized to JSON, regular expressions are written as nested documents of the form: 445 * 446 * <pre> 447 * { "$regex" : "<i>pattern</i>" } 448 * </pre> 449 * 450 * where "<i>pattern</i>" is the regular expression pattern. 451 * <p> 452 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 453 * be converted to a regular expression value. 454 * </p> 455 * 456 * @param name The name of the field 457 * @param pattern the regular expression pattern string 458 * @return This document, to allow for chaining methods 459 * @see #setRegularExpression(String, String, int) 460 */ 461 EditableDocument setRegularExpression( String name, 462 String pattern ); 463 464 /** 465 * Set the value for the field with the given name to the supplied regular expression. Regular expression values are 466 * represented in memory using {@link Pattern} instances, and are stored natively in BSON as regular expressions. However, 467 * when serialized to JSON, regular expressions are written as nested documents of the form: 468 * 469 * <pre> 470 * { "$regex" : "<i>pattern</i>", "$options" : "<i>flags</i>" } 471 * </pre> 472 * 473 * where "<i>pattern</i>" is the regular expression pattern, and "<i>flags</i>" is a string representation of the regular 474 * expression options. 475 * <p> 476 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 477 * be converted to a regular expression value. 478 * </p> 479 * 480 * @param name The name of the field 481 * @param pattern the regular expression pattern string 482 * @param flags the bitwise-anded {@link Pattern} options: {@link Pattern#CANON_EQ}, {@link Pattern#CASE_INSENSITIVE}, 483 * {@link Pattern#CASE_INSENSITIVE}, {@link Pattern#COMMENTS}, {@link Pattern#DOTALL}, {@link Pattern#LITERAL}, 484 * {@link Pattern#MULTILINE}, {@link Pattern#UNICODE_CASE}, and {@link Pattern#UNIX_LINES} 485 * @return This document, to allow for chaining methods 486 * @see #setRegularExpression(String, String) 487 */ 488 EditableDocument setRegularExpression( String name, 489 String pattern, 490 int flags ); 491 492 /** 493 * Set the value for the field with the given name to be a null value. Both JSON and BSON formats support null values, and 494 * {@link Null} is used for the value in the in-memory representation. The {@link #isNull(String)} methods can be used to 495 * determine if a field has been set to null, or {@link #isNullOrMissing(String)} if the field has not be set or if it has 496 * been set to null. 497 * 498 * @param name The name of the field 499 * @return This document, to allow for chaining methods 500 * @see #isNull(String) 501 * @see #isNullOrMissing(String) 502 */ 503 EditableDocument setNull( String name ); 504 505 /** 506 * Set the value for the field with the given name to be a binary value. JSON does not formally support binary values, and so 507 * such values will be encoded using a nested document of the form: 508 * 509 * <pre> 510 * { "$type" : <i>typeAsInt</i>, "$base64" : "<i>bytesInBase64</i>" } 511 * </pre> 512 * 513 * where "<i>typeAsInt</i>" is the integer representation of the {@link BinaryType BSON type}, and "<i>bytesInBase64</i>" is 514 * the Base64 encoding of the actual Binary {@link Binary#getBytes() bytes}. 515 * <p> 516 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 517 * be converted to Binary value. 518 * </p> 519 * 520 * @param name The name of the field 521 * @param type one of the {@link BinaryType BSON type} constants denoting the type of the {@link Binary} value 522 * @param data the bytes for the {@link Binary} value 523 * @return This document, to allow for chaining methods 524 */ 525 EditableDocument setBinary( String name, 526 byte type, 527 byte[] data ); 528 529 /** 530 * Set the value for the field with the given name to be a {@link UUID}. JSON does not formally support binary values, and so 531 * such values will be encoded using a nested document of the form: 532 * 533 * <pre> 534 * { "$uuid" : "<i>string-form-of-uuid</i>" } 535 * </pre> 536 * 537 * where "<i>string-form-of-uuid</i>" is the UUID's {@link UUID#toString() string representation} 538 * <p> 539 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 540 * be converted to UUID value. 541 * </p> 542 * 543 * @param name The name of the field 544 * @param uuid the UUID value 545 * @return This document, to allow for chaining methods 546 */ 547 EditableDocument setUuid( String name, 548 UUID uuid ); 549 550 /** 551 * Set the value for the field with the given name to be a {@link Code} or {@link CodeWithScope}. JSON does not formally 552 * support such values, and so when written to JSON they will be encoded using a nested document of the form: 553 * 554 * <pre> 555 * { "$code" : "<i>code</i>" } 556 * </pre> 557 * 558 * or, if there is a scope document 559 * 560 * <pre> 561 * { "$code" : "<i>code</i>", "$scope" : <i>scope document</i> } 562 * </pre> 563 * 564 * where "<i>code</i>" is the {@link Code}'s {@link Code#getCode() JavaScript code} and <i>scopeDocument</i> is the nested 565 * document representing the {@link CodeWithScope#getScope() scope} in which the JavaScript code should be evaluated. 566 * <p> 567 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 568 * be converted to {@link Code} or {@link CodeWithScope} value. 569 * </p> 570 * <p> 571 * Note that when <code>includeScope</code> is <code>true</code>, the returned {@link EditableDocument} can be used to 572 * populate the scope document. 573 * 574 * @param name The name of the field 575 * @param code the code 576 * @param includeScope true if the code should include a scope (and if this method should return an {@link EditableDocument} 577 * for this scope document), or false otherwise 578 * @return if <code>includeScope</code> is <code>true</code>, then the {@link EditableDocument} for the scope; otherwise, this 579 * document to allow for chaining methods 580 * @see #setCode(String, String, Document) 581 */ 582 EditableDocument setCode( String name, 583 String code, 584 boolean includeScope ); 585 586 /** 587 * Set the value for the field with the given name to be a {@link Code} or {@link CodeWithScope}. JSON does not formally 588 * support such values, and so when written to JSON they will be encoded using a nested document of the form: 589 * 590 * <pre> 591 * { "$code" : "<i>code</i>" } 592 * </pre> 593 * 594 * or, if there is a scope document 595 * 596 * <pre> 597 * { "$code" : "<i>code</i>", "$scope" : <i>scope document</i> } 598 * </pre> 599 * 600 * where "<i>code</i>" is the {@link Code}'s {@link Code#getCode() JavaScript code} and <i>scopeDocument</i> is the nested 601 * document representing the {@link CodeWithScope#getScope() scope} in which the JavaScript code should be evaluated. 602 * <p> 603 * When nested documents of this form are read by this library's {@link Json JSON reader}, nested documents of this form will 604 * be converted to {@link Code} or {@link CodeWithScope} value. 605 * </p> 606 * 607 * @param name The name of the field 608 * @param code the code 609 * @param scope the scope in which the JavaScript code should be evaulated, or null if there is no scope 610 * @return the {@link EditableDocument} for the scope, or null if the <code>scope</code> reference is null 611 * @see #setCode(String, String, boolean) 612 */ 613 EditableDocument setCode( String name, 614 String code, 615 Document scope ); 616 617 @Override 618 EditableDocument clone(); 619 620 @Override 621 default Editor edit(boolean clone) { 622 return clone ? 623 new IncrementalDocumentEditor(this.clone().asMutableDocument(), new ArrayList<>()) : 624 new IncrementalDocumentEditor(this.asMutableDocument(), new ArrayList<>()); 625 } 626 627 @Override 628 default EditableDocument editable() { 629 return this; 630 } 631}