1 16 package org.outerj.daisy.repository.commonimpl; 17 18 import org.outerj.daisy.repository.commonimpl.schema.CommonRepositorySchema; 19 import org.outerj.daisy.repository.*; 20 import org.outerj.daisy.repository.schema.*; 21 import org.outerx.daisy.x10.DocumentDocument; 22 23 import java.util.*; 24 25 29 public class DocumentVariantImpl { 30 private DocumentImpl ownerDocument; 31 private DocumentStrategy documentStrategy; 32 private CommonRepositorySchema repositorySchema; 33 private AuthenticatedUser currentUser; 34 35 private Map parts = new HashMap(); 36 private boolean partChanges = false; 37 private long documentTypeId; 38 private boolean documentTypeChanged = false; 39 private String name; 40 private boolean nameUpdated = false; 41 private long branchId; 42 private long languageId; 43 private boolean isNew; 44 private Date lastModified; 45 private long lastModifier = -1; 46 private boolean retired = false; 47 private boolean retiredChanged = false; 48 private VersionImpl[] versions; 49 50 private Version liveVersion; 51 52 private boolean liveVersionLoaded = false; 53 54 private Version lastVersion; 55 56 private boolean lastVersionLoaded = false; 57 private long lastVersionId = -1; 58 private long liveVersionId = -1; 59 60 private Map fields = new HashMap(); 61 private boolean fieldChanges = false; 62 private List links = new ArrayList(3); 63 private boolean linkChanges = false; 64 private Map customFields = new HashMap(); 65 private boolean customFieldChanges = false; 66 private Map documentCollections = new HashMap(); 67 private boolean documentCollectionChanges = false; 68 private LockInfoImpl lockInfo = new LockInfoImpl(); 69 private VersionState versionState = VersionState.PUBLISH; 70 private String summary; 71 private long updateCount = 0; 72 private IntimateAccess intimateAccess = new IntimateAccess(); 73 private long createdFromBranchId = -1; 74 private long createdFromLanguageId = -1; 75 private long createdFromVersionId = -1; 76 private boolean validateOnSave = true; 79 private long startBranchId; 80 private long startLanguageId; 81 82 public static final String ERROR_ACCESSING_REPOSITORY_SCHEMA = "Error accessing repository schema information."; 83 private static final String READ_ONLY_MESSAGE = "This document object is read-only."; 84 85 public DocumentVariantImpl(DocumentImpl ownerDocument, DocumentStrategy documentStrategy, CommonRepositorySchema repositorySchema, AuthenticatedUser currentUser, long documentTypeId, long branchId, long languageId) { 86 this.ownerDocument = ownerDocument; 87 this.documentStrategy = documentStrategy; 88 this.repositorySchema = repositorySchema; 89 this.currentUser = currentUser; 90 this.documentTypeId = documentTypeId; 91 this.branchId = branchId; 92 this.languageId = languageId; 93 this.isNew = true; 94 } 95 96 public DocumentVariantImpl.IntimateAccess getIntimateAccess(DocumentStrategy strategy) { 97 if (this.documentStrategy == strategy) 98 return intimateAccess; 99 return null; 100 } 101 102 public long getBranchId() { 103 return branchId; 104 } 105 106 public long getLanguageId() { 107 return languageId; 108 } 109 110 public boolean isNew() { 111 return isNew; 112 } 113 114 public long getDocumentTypeId() { 115 return documentTypeId; 116 } 117 118 public long getDocumentId() { 119 return ownerDocument.getId(); 120 } 121 122 public void setValidateOnSave(boolean validateOnSave) { 123 this.validateOnSave = validateOnSave; 124 } 125 126 public void changeDocumentType(long documentTypeId) throws RepositoryException { 127 if (ownerDocument.isReadOnly()) 128 throw new RuntimeException (READ_ONLY_MESSAGE); 129 130 if (documentTypeId != this.documentTypeId) { 131 repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser); 134 135 this.documentTypeId = documentTypeId; 136 this.documentTypeChanged = true; 137 } 138 } 139 140 public void changeDocumentType(String documentTypeName) throws RepositoryException { 141 if (ownerDocument.isReadOnly()) 142 throw new RuntimeException (READ_ONLY_MESSAGE); 143 144 DocumentType documentType = repositorySchema.getDocumentTypeByName(documentTypeName, false, currentUser); 145 changeDocumentType(documentType.getId()); 146 } 147 148 public Field getField(String name) throws FieldNotFoundException { 149 FieldType fieldType = null; 150 try { 151 fieldType = repositorySchema.getFieldTypeByName(name, false, currentUser); 152 } catch (RepositoryException e) { 153 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 154 } 155 return getField(fieldType.getId()); 156 } 157 158 public Field getField(long fieldTypeId) throws FieldNotFoundException { 159 Field field = (Field)fields.get(new Long (fieldTypeId)); 160 if (field == null) 161 throw new FieldNotFoundException(fieldTypeId); 162 else 163 return field; 164 } 165 166 public boolean hasField(long fieldTypeId) { 167 Field field = (Field)fields.get(new Long (fieldTypeId)); 168 return field != null; 169 } 170 171 public boolean hasField(String fieldTypeName) { 172 FieldType fieldType = null; 173 try { 174 fieldType = repositorySchema.getFieldTypeByName(fieldTypeName, false, currentUser); 175 } catch (RepositoryException e) { 176 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 177 } 178 return hasField(fieldType.getId()); 179 } 180 181 public Fields getFields() { 182 return new FieldsImpl((Field[])fields.values().toArray(new Field[0])); 183 } 184 185 public Fields getFieldsInOrder() { 186 return new FieldsImpl(orderFields((Field[])fields.values().toArray(new Field[0]))); 187 } 188 189 public void setField(String name, Object value) throws DocumentTypeInconsistencyException { 190 if (ownerDocument.isReadOnly()) 191 throw new RuntimeException (READ_ONLY_MESSAGE); 192 193 FieldType fieldType = null; 194 try { 195 fieldType = repositorySchema.getFieldTypeByName(name, false, currentUser); 196 } catch (RepositoryException e) { 197 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 198 } 199 setField(fieldType.getId(), value); 200 } 201 202 public void setField(long fieldTypeId, Object value) throws DocumentTypeInconsistencyException { 203 if (ownerDocument.isReadOnly()) 204 throw new RuntimeException (READ_ONLY_MESSAGE); 205 206 if (value == null) 207 throw new NullPointerException ("Field value cannot be null!"); 208 209 DocumentType documentType = null; 210 try { 211 documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser); 212 } catch (RepositoryException e) { 213 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 214 } 215 216 FieldType fieldType; 217 try { 218 fieldType = repositorySchema.getFieldTypeById(fieldTypeId, false, currentUser); 219 } catch (RepositoryException e) { 220 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 221 } 222 223 if (!documentType.hasFieldType(fieldTypeId)) 224 throw new DocumentTypeInconsistencyException("The FieldType \"" + fieldType.getName() + "\" (ID: " + fieldTypeId + ") is not allowed on this document."); 225 226 checkFieldValue(fieldType, value); 227 228 if (fieldType.getValueType() == ValueType.DATE) { 230 if (fieldType.isMultiValue()) { 231 Object [] values = (Object [])value; 232 for (int i = 0; i < values.length; i++) 233 values[i] = getDate((Date)values[i]); 234 } else { 235 value = getDate((Date)value); 236 } 237 } else if (fieldType.getValueType() == ValueType.DATETIME) { 238 if (fieldType.isMultiValue()) { 239 Object [] values = (Object [])value; 240 for (int i = 0; i < values.length; i++) 241 values[i] = getDateTime((Date)values[i]); 242 } else { 243 value = getDateTime((Date)value); 244 } 245 } 246 247 FieldImpl field = (FieldImpl)fields.get(new Long (fieldTypeId)); 248 249 if (field != null && (fieldType.isMultiValue() ? Arrays.equals((Object [])field.getValue(), (Object [])value) : field.getValue().equals(value))) 251 return; 252 253 field = new FieldImpl(intimateAccess, fieldTypeId, value); 254 fields.put(new Long (fieldTypeId), field); 255 fieldChanges = true; 256 } 257 258 private Date getDate(Date date) { 259 Calendar calendar = new GregorianCalendar(); 260 calendar.setTime(date); 261 calendar.set(Calendar.HOUR_OF_DAY, 0); 262 calendar.set(Calendar.MINUTE, 0); 263 calendar.set(Calendar.SECOND, 0); 264 calendar.set(Calendar.MILLISECOND, 0); 265 return calendar.getTime(); 266 } 267 268 private Date getDateTime(Date date) { 269 Calendar calendar = new GregorianCalendar(); 270 calendar.setTime(date); 271 calendar.set(Calendar.MILLISECOND, 0); 272 return calendar.getTime(); 273 } 274 275 private void checkFieldValue(FieldType fieldType, Object value) throws DocumentTypeInconsistencyException { 276 ValueType valueType = fieldType.getValueType(); 277 if (fieldType.isMultiValue()) { 278 if (!value.getClass().isArray()) 279 throw new DocumentTypeInconsistencyException("The value for the multivalue-field \"" + fieldType.getName() + "\" should be an array."); 280 Object [] values = (Object [])value; 281 if (values.length == 0) 282 throw new DocumentTypeInconsistencyException("The value supplied for the multivalue field \"" + fieldType.getName() + "\" is a zero-length array, it should be an array of at least one element."); 283 for (int i = 0; i < values.length; i++) { 284 if (!valueType.getTypeClass().isAssignableFrom(values[i].getClass())) 285 throw new DocumentTypeInconsistencyException("The supplied value for the multivalue field \"" + fieldType.getName() + "\" at index " + i + " is not of the correct type. Expected was a " + valueType.toString() + " (" + valueType.getTypeClass().getName() + ") but got a " + value.getClass().getName()); 286 } 287 } else { 288 if (!valueType.getTypeClass().isAssignableFrom(value.getClass())) 289 throw new DocumentTypeInconsistencyException("The supplied value for the field \"" + fieldType.getName() + "\" is not of the correct type. Expected was a " + valueType.toString() + " (" + valueType.getTypeClass().getName() + ") but got a " + value.getClass().getName()); 290 } 291 } 292 293 public void deleteField(String name) { 294 if (ownerDocument.isReadOnly()) 295 throw new RuntimeException (READ_ONLY_MESSAGE); 296 297 FieldType fieldType = null; 298 try { 299 fieldType = repositorySchema.getFieldTypeByName(name, false, currentUser); 300 } catch (RepositoryException e) { 301 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 302 } 303 deleteField(fieldType.getId()); 304 } 305 306 public void deleteField(long fieldTypeId) { 307 if (ownerDocument.isReadOnly()) 308 throw new RuntimeException (READ_ONLY_MESSAGE); 309 310 Long key = new Long (fieldTypeId); 311 if (fields.containsKey(key)) { 312 fields.remove(new Long (fieldTypeId)); 313 fieldChanges = true; 314 } 315 } 316 317 public LockInfo getLockInfo(boolean fresh) throws RepositoryException { 318 LockInfoImpl lockInfo = this.lockInfo; 319 if ((fresh || lockInfo == null) && !isNew) { 320 synchronized(this) { 321 lockInfo = documentStrategy.getLockInfo(this); 322 this.lockInfo = lockInfo; 323 } 324 } 325 return lockInfo; 326 } 327 328 public void clearLockInfo() { 332 this.lockInfo = null; 333 } 334 335 public boolean lock(long duration, LockType lockType) throws RepositoryException { 336 if (ownerDocument.isReadOnly()) 337 throw new RuntimeException (READ_ONLY_MESSAGE); 338 339 if (isNew) 340 throw new RepositoryException("Can't take a lock on a new, non-saved document variant."); 341 342 lockInfo = documentStrategy.lock(this, duration, lockType); 343 344 if (!lockInfo.hasLock()) 345 return false; 346 347 return lockInfo.getUserId() == currentUser.getId(); 348 } 349 350 public boolean releaseLock() throws RepositoryException { 351 if (ownerDocument.isReadOnly()) 352 throw new RuntimeException (READ_ONLY_MESSAGE); 353 354 if (isNew) 355 return true; 356 357 lockInfo = documentStrategy.releaseLock(this); 358 return !lockInfo.hasLock(); 359 } 360 361 public void addXml(DocumentDocument.Document documentXml) throws RepositoryException { 362 addNonVersionedDataToXml(documentXml); 363 364 documentXml.setDataVersionId(-1); documentXml.setName(name); 366 documentXml.setFields(getFieldsInOrder().getXml().getFields()); 367 documentXml.setParts(getPartsInOrder().getXml().getParts()); 368 documentXml.setLinks(getLinks().getXml().getLinks()); 369 documentXml.setValidateOnSave(validateOnSave); 370 } 371 372 public void addXml(DocumentDocument.Document documentXml, long versionId) throws RepositoryException { 373 Version version = getVersion(versionId); 374 addNonVersionedDataToXml(documentXml); 375 376 documentXml.setDataVersionId(versionId); 377 documentXml.setName(version.getDocumentName()); 378 documentXml.setFields(version.getFieldsInOrder().getXml().getFields()); 379 documentXml.setParts(version.getPartsInOrder().getXml().getParts()); 380 documentXml.setLinks(version.getLinks().getXml().getLinks()); 381 } 382 383 public void addNonVersionedDataToXml(DocumentDocument.Document documentXml) { 384 if (!isNew) { 385 GregorianCalendar lastModified = new GregorianCalendar(); 386 lastModified.setTime(this.lastModified); 387 documentXml.setVariantLastModified(lastModified); 388 documentXml.setVariantLastModifier(lastModifier); 389 if (liveVersionId != -1) 390 documentXml.setLiveVersionId(liveVersionId); 391 } 392 393 documentXml.setBranchId(branchId); 394 documentXml.setLanguageId(languageId); 395 documentXml.setTypeId(documentTypeId); 396 documentXml.setLastVersionId(lastVersionId); 397 documentXml.setRetired(retired); 398 documentXml.setNewVersionState(DocumentDocument.Document.NewVersionState.Enum.forString(versionState.toString())); 399 documentXml.setVariantUpdateCount(updateCount); 400 if (summary != null) 401 documentXml.setSummary(summary); 402 documentXml.setCreatedFromBranchId(createdFromBranchId); 403 documentXml.setCreatedFromLanguageId(createdFromLanguageId); 404 documentXml.setCreatedFromVersionId(createdFromVersionId); 405 406 DocumentDocument.Document.CustomFields customFieldsXml = documentXml.addNewCustomFields(); 407 Iterator customFieldsIt = customFields.entrySet().iterator(); 408 while (customFieldsIt.hasNext()) { 409 Map.Entry customField = (Map.Entry)customFieldsIt.next(); 410 DocumentDocument.Document.CustomFields.CustomField customFieldXml = customFieldsXml.addNewCustomField(); 411 customFieldXml.setName((String )customField.getKey()); 412 customFieldXml.setValue((String )customField.getValue()); 413 } 414 415 LockInfo lockInfo; 416 try { 417 lockInfo = getLockInfo(false); 418 } catch (RepositoryException e) { 419 throw new RuntimeException (e); 420 } 421 documentXml.setLockInfo(lockInfo.getXml().getLockInfo()); 422 423 long[] collectionIds = new long[documentCollections.size()]; 424 Iterator collectionsIt = documentCollections.values().iterator(); 425 int i = 0; 426 while (collectionsIt.hasNext()) { 427 DocumentCollection collection = (DocumentCollection)collectionsIt.next(); 428 collectionIds[i] = collection.getId(); 429 i++; 430 } 431 documentXml.addNewCollectionIds().setCollectionIdArray(collectionIds); 432 } 433 434 public void setName(String name) { 435 if (ownerDocument.isReadOnly()) 436 throw new RuntimeException (READ_ONLY_MESSAGE); 437 438 if (name == null) 439 throw new NullPointerException ("name may not be null."); 440 441 if (!name.equals(this.name)) { 442 this.name = name; 443 nameUpdated = true; 444 } 445 } 446 447 public String getName() { 448 return name; 449 } 450 451 public void setPart(String partTypeName, String mimeType, byte[] data) throws DocumentTypeInconsistencyException { 452 if (ownerDocument.isReadOnly()) 453 throw new RuntimeException (READ_ONLY_MESSAGE); 454 455 if (data == null) 456 throw new NullPointerException ("data argument cannot be null."); 457 458 setPart(partTypeName, mimeType, new ByteArrayPartDataSource(data)); 459 460 } 461 462 public void setPart(long partTypeId, String mimeType, byte[] data) throws DocumentTypeInconsistencyException { 463 if (ownerDocument.isReadOnly()) 464 throw new RuntimeException (READ_ONLY_MESSAGE); 465 466 if (data == null) 467 throw new NullPointerException ("data argument cannot be null."); 468 469 setPart(partTypeId, mimeType, new ByteArrayPartDataSource(data)); 470 } 471 472 public void setPart(String partTypeName, String mimeType, PartDataSource partDataSource) throws DocumentTypeInconsistencyException { 473 if (ownerDocument.isReadOnly()) 474 throw new RuntimeException (READ_ONLY_MESSAGE); 475 476 PartType partType = null; 477 try { 478 partType = repositorySchema.getPartTypeByName(partTypeName, false, currentUser); 479 } catch (RepositoryException e) { 480 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 481 } 482 483 setPart(partType.getId(), mimeType, partDataSource); 484 } 485 486 public void setPart(long partTypeId, String mimeType, PartDataSource partDataSource) throws DocumentTypeInconsistencyException { 487 if (ownerDocument.isReadOnly()) 488 throw new RuntimeException (READ_ONLY_MESSAGE); 489 490 DocumentType documentType; 492 try { 493 documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser); 494 } catch (RepositoryException e) { 495 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 496 } 497 498 PartType partType; 499 try { 500 partType = repositorySchema.getPartTypeById(partTypeId, false, currentUser); 501 } catch (RepositoryException e) { 502 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 503 } 504 505 if (mimeType == null || mimeType.length() == 0) 506 throw new NullPointerException ("mimeType argument cannot be null or an empty string"); 507 508 if (partDataSource == null) 509 throw new NullPointerException ("partDataSource argument cannot be null."); 510 511 if (!documentType.hasPartType(partTypeId)) 512 throw new DocumentTypeInconsistencyException("The PartType \"" + partType.getName() + "\" (ID: " + partTypeId + ") is not allowed on this document."); 513 514 if (!partType.mimeTypeAllowed(mimeType)) 515 throw new DocumentTypeInconsistencyException("The mime-type \"" + mimeType + "\" isn't part of the allowed mime types (" + partType.getMimeTypes() + ") required by the PartType \"" + partType.getName() + "\" (ID: " + partTypeId + ")."); 516 517 PartImpl part = new PartImpl(intimateAccess, partTypeId, lastVersionId); 518 PartImpl.IntimateAccess partInt = part.getIntimateAccess(documentStrategy); 519 partInt.setMimeType(mimeType); 520 partInt.setData(partDataSource); 521 partInt.setNewOrUpdated(true, true); 522 523 parts.put(new Long (partTypeId), part); 524 partChanges = true; 525 } 526 527 public void setPartFileName(String partTypeName, String fileName) { 528 if (ownerDocument.isReadOnly()) 529 throw new RuntimeException (READ_ONLY_MESSAGE); 530 531 PartType partType = null; 532 try { 533 partType = repositorySchema.getPartTypeByName(partTypeName, false, currentUser); 534 } catch (RepositoryException e) { 535 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 536 } 537 538 setPartFileName(partType.getId(), fileName); 539 } 540 541 public void setPartFileName(long partTypeId, String fileName) { 542 if (ownerDocument.isReadOnly()) 543 throw new RuntimeException (READ_ONLY_MESSAGE); 544 545 PartImpl part = (PartImpl)parts.get(new Long (partTypeId)); 546 if (part == null) 547 throw new RepositoryRuntimeException("The document does not have a part for part type ID " + partTypeId); 548 549 if ((part.getFileName() == null && fileName == null) || (part.getFileName() != null && part.getFileName().equals(fileName))) 550 return; 551 552 PartImpl.IntimateAccess partInt = part.getIntimateAccess(documentStrategy); 553 partInt.setFileName(fileName); 554 partInt.setNewOrUpdated(true, partInt.isDataUpdated()); 555 partChanges = true; 556 } 557 558 public void setPartMimeType(String partTypeName, String mimeType) { 559 if (ownerDocument.isReadOnly()) 560 throw new RuntimeException (READ_ONLY_MESSAGE); 561 562 PartType partType = null; 563 try { 564 partType = repositorySchema.getPartTypeByName(partTypeName, false, currentUser); 565 } catch (RepositoryException e) { 566 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 567 } 568 569 setPartMimeType(partType.getId(), mimeType); 570 } 571 572 public void setPartMimeType(long partTypeId, String mimeType) { 573 if (ownerDocument.isReadOnly()) 574 throw new RuntimeException (READ_ONLY_MESSAGE); 575 576 if (mimeType == null) 577 throw new IllegalArgumentException ("Part mime-type cannot be set to null value."); 578 579 PartImpl part = (PartImpl)parts.get(new Long (partTypeId)); 580 if (part == null) 581 throw new RepositoryRuntimeException("The document does not have a part for part type ID " + partTypeId); 582 583 if (part.getMimeType().equals(mimeType)) 584 return; 585 586 PartImpl.IntimateAccess partInt = part.getIntimateAccess(documentStrategy); 587 partInt.setMimeType(mimeType); 588 partInt.setNewOrUpdated(true, partInt.isDataUpdated()); 589 partChanges = true; 590 } 591 592 public Parts getParts() { 593 return new PartsImpl((Part[])parts.values().toArray(new Part[0])); 594 } 595 596 public Parts getPartsInOrder() { 597 return new PartsImpl(orderParts((Part[])parts.values().toArray(new Part[0]))); 598 } 599 600 private Part[] orderParts(Part[] parts) { 601 Part[] resultList = new Part[parts.length]; 602 boolean[] handled = new boolean[parts.length]; 603 604 DocumentType documentType = null; 605 try { 606 documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser); 607 } catch (RepositoryException e) { 608 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 609 } 610 PartTypeUse[] partTypeUses = documentType.getPartTypeUses(); 611 612 int resultListPos = -1; 613 for (int i = 0; i < partTypeUses.length; i++) { 614 long id = partTypeUses[i].getPartType().getId(); 615 for (int k = 0; k < parts.length; k++) { 616 if (parts[k].getTypeId() == id) { 617 handled[k] = true; 618 resultListPos++; 619 resultList[resultListPos] = parts[k]; 620 break; 621 } 622 } 623 } 624 625 for (int i = 0; i < handled.length; i++) { 626 if (!handled[i]) { 627 resultListPos++; 628 resultList[resultListPos] = parts[i]; 629 } 630 } 631 632 return resultList; 633 } 634 635 private Field[] orderFields(Field[] fields) { 636 Field[] resultList = new Field[fields.length]; 637 boolean[] handled = new boolean[fields.length]; 638 639 DocumentType documentType = null; 640 try { 641 documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser); 642 } catch (RepositoryException e) { 643 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 644 } 645 FieldTypeUse[] fieldTypeUses = documentType.getFieldTypeUses(); 646 647 int resultListPos = -1; 648 for (int i = 0; i < fieldTypeUses.length; i++) { 649 long id = fieldTypeUses[i].getFieldType().getId(); 650 for (int k = 0; k < fields.length; k++) { 651 if (fields[k].getTypeId() == id) { 652 handled[k] = true; 653 resultListPos++; 654 resultList[resultListPos] = fields[k]; 655 break; 656 } 657 } 658 } 659 660 for (int i = 0; i < handled.length; i++) { 661 if (!handled[i]) { 662 resultListPos++; 663 resultList[resultListPos] = fields[i]; 664 } 665 } 666 667 return resultList; 668 } 669 670 public void deletePart(long partTypeId) { 671 if (ownerDocument.isReadOnly()) 672 throw new RuntimeException (READ_ONLY_MESSAGE); 673 674 Long key = new Long (partTypeId); 675 if (parts.containsKey(key)) { 676 parts.remove(key); 677 partChanges = true; 678 } 679 } 680 681 public void deletePart(String name) { 682 if (ownerDocument.isReadOnly()) 683 throw new RuntimeException (READ_ONLY_MESSAGE); 684 685 PartType partType = null; 686 try { 687 partType = repositorySchema.getPartTypeByName(name, false, currentUser); 688 } catch (RepositoryException e) { 689 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 690 } 691 deletePart(partType.getId()); 692 } 693 694 public Part getPart(long partTypeId) throws PartNotFoundException { 695 Part part = (Part)parts.get(new Long (partTypeId)); 696 if (part == null) 697 throw new PartNotFoundException(partTypeId); 698 else 699 return part; 700 } 701 702 public Part getPart(String name) throws PartNotFoundException { 703 PartType partType = null; 704 try { 705 partType = repositorySchema.getPartTypeByName(name, false, currentUser); 706 } catch (RepositoryException e) { 707 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 708 } 709 return getPart(partType.getId()); 710 } 711 712 public boolean hasPart(long partTypeId) { 713 Part part = (Part)parts.get(new Long (partTypeId)); 714 return part != null; 715 } 716 717 public boolean hasPart(String name) { 718 PartType partType = null; 719 try { 720 partType = repositorySchema.getPartTypeByName(name, false, currentUser); 721 } catch (RepositoryException e) { 722 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA, e); 723 } 724 return hasPart(partType.getId()); 725 } 726 727 public void setCustomField(String name, String value) { 728 if (ownerDocument.isReadOnly()) 729 throw new RuntimeException (READ_ONLY_MESSAGE); 730 731 if (name == null) 732 throw new RuntimeException ("name argument cannot be null."); 733 if (value == null) 734 throw new RuntimeException ("value argument cannot be null."); 735 736 customFields.put(name, value); 737 customFieldChanges = true; 738 } 739 740 public void deleteCustomField(String name) { 741 if (ownerDocument.isReadOnly()) 742 throw new RuntimeException (READ_ONLY_MESSAGE); 743 744 if (name == null) 745 throw new RuntimeException ("name argument cannot be null."); 746 747 customFields.remove(name); 748 customFieldChanges = true; 749 } 750 751 public void clearCustomFields() { 752 if (ownerDocument.isReadOnly()) 753 throw new RuntimeException (READ_ONLY_MESSAGE); 754 755 customFields.clear(); 756 customFieldChanges = true; 757 } 758 759 public void clearCollections() { 760 if (ownerDocument.isReadOnly()) 761 throw new RuntimeException (READ_ONLY_MESSAGE); 762 763 documentCollections.clear(); 764 documentCollectionChanges = true; 765 } 766 767 public Map getCustomFields() { 768 return new HashMap(customFields); 769 } 770 771 public String getCustomField(String name) { 772 if (name == null) 773 throw new NullPointerException ("name argument cannot be null."); 774 775 return (String )customFields.get(name); 776 } 777 778 public boolean hasCustomField(String name) { 779 if (name == null) 780 throw new NullPointerException ("name argument cannot be null."); 781 782 return customFields.containsKey(name); 783 } 784 785 public Links getLinks() { 786 return new LinksImpl((Link[])links.toArray(new Link[links.size()])); 787 } 788 789 public void addLink(String title, String target) { 790 if (ownerDocument.isReadOnly()) 791 throw new RuntimeException (READ_ONLY_MESSAGE); 792 793 links.add(new LinkImpl(title, target)); 794 linkChanges = true; 795 } 796 797 public void deleteLink(int index) { 798 if (ownerDocument.isReadOnly()) 799 throw new RuntimeException (READ_ONLY_MESSAGE); 800 801 links.remove(index); 802 linkChanges = true; 803 } 804 805 public void clearLinks() { 806 if (ownerDocument.isReadOnly()) 807 throw new RuntimeException (READ_ONLY_MESSAGE); 808 809 links.clear(); 810 linkChanges = true; 811 } 812 813 public void validate() throws DocumentTypeInconsistencyException { 814 fullConsistencyCheck(); 815 } 816 817 public void setNewVersionState(VersionState versionState) { 818 if (versionState == null) 819 throw new NullPointerException ("versionState argument cannot be null."); 820 821 this.versionState = versionState; 822 } 823 824 public VersionState getNewVersionState() { 825 return versionState; 826 } 827 828 public synchronized Version getVersion(long versionId) throws RepositoryException { 829 if (isNew) 830 throw new RepositoryException("A new document variant has no versions."); 831 if (versionId < 1 || versionId > lastVersionId) 832 throw new RepositoryException("Document with ID " + ownerDocument.getId() + " (branch: " + branchId + ", language: " + languageId + ") does not have a version " + versionId); 833 834 checkVersionsArray(); 835 836 int arrayPos = (int)versionId - 1; 837 if (versions[arrayPos] == null) { 838 versions[arrayPos] = documentStrategy.loadVersion(this, versionId); 839 } 840 841 return versions[arrayPos]; 842 } 843 844 public Version getLastVersion() throws RepositoryException { 845 if (isNew) 846 return null; 847 848 if (lastVersionLoaded) 849 return lastVersion; 850 851 Version[] versions = getVersions().getArray(); 852 lastVersion = versions[versions.length - 1]; 853 lastVersionLoaded = true; 854 return lastVersion; 855 } 856 857 public Version getLiveVersion() throws RepositoryException { 858 if (isNew || liveVersionId == -1) 859 return null; 860 861 if (liveVersionLoaded) 862 return liveVersion; 863 864 checkVersionsArray(); 865 int liveVersionPos = (int)liveVersionId - 1; if (versions[(int)liveVersionId - 1] != null) { 867 liveVersion = versions[liveVersionPos]; 868 } else { 869 VersionImpl newLiveVersion = documentStrategy.loadVersion(this, liveVersionId); 870 versions[liveVersionPos] = newLiveVersion; 871 liveVersion = newLiveVersion; 872 } 873 liveVersionLoaded = true; 874 return liveVersion; 875 } 876 877 public long getLiveVersionId() { 878 return liveVersionId; 879 } 880 881 public synchronized Versions getVersions() throws RepositoryException { 882 if (isNew) 883 return new VersionsImpl(new Version[0]); 884 885 loadVersions(); 886 887 return new VersionsImpl((Version[])versions.clone()); 888 } 889 890 private void loadVersions() throws RepositoryException { 891 checkVersionsArray(); 892 893 VersionImpl[] loadedVersions = null; 894 895 for (int i = 0; i < versions.length; i++) { 899 if (versions[i] == null) { 900 if (loadedVersions == null) 901 loadedVersions = documentStrategy.loadShallowVersions(this); 902 versions[i] = loadedVersions[i]; 903 } 904 } 905 } 906 907 public long getLastVersionId() { 908 return lastVersionId; 909 } 910 911 private final void checkVersionsArray() { 912 if (versions == null) { 913 versions = new VersionImpl[(int)lastVersionId]; 914 } else if (versions.length != lastVersionId) { 915 VersionImpl[] oldVersions = versions; 916 versions = new VersionImpl[(int)lastVersionId]; 917 System.arraycopy(oldVersions, 0, versions, 0, oldVersions.length); 918 } 919 } 920 921 private void fullConsistencyCheck() throws DocumentTypeInconsistencyException { 922 DocumentType documentType = null; 923 try { 924 documentType = repositorySchema.getDocumentTypeById(documentTypeId, false, currentUser); 925 } catch (RepositoryException e) { 926 throw new RuntimeException (ERROR_ACCESSING_REPOSITORY_SCHEMA); 927 } 928 929 PartTypeUse[] partTypeUses = documentType.getPartTypeUses(); 931 boolean[] hasPartType = new boolean[partTypeUses.length]; 932 933 Part[] parts = getParts().getArray(); 934 for (int i = 0; i < parts.length; i++) { 935 long partTypeId = parts[i].getTypeId(); 936 int partTypeIndex = -1; 937 for (int j = 0; j < partTypeUses.length; j++) { 938 if (partTypeUses[j].getPartType().getId() == partTypeId) { 939 partTypeIndex = j; 940 } 941 } 942 if (partTypeIndex == -1) 943 throw new DocumentTypeInconsistencyException("The document contains a not-allowed part (PartType ID: " + partTypeId + ")."); 944 hasPartType[partTypeIndex] = true; 945 if (!partTypeUses[partTypeIndex].getPartType().mimeTypeAllowed(parts[i].getMimeType())) 946 throw new DocumentTypeInconsistencyException("The mime-type for the part \"" + partTypeUses[partTypeIndex].getPartType().getName() + "\" isn't part of the allowed mime types (PartType ID: " + partTypeId + ")."); 947 } 948 949 for (int i = 0; i < partTypeUses.length; i++) { 950 if (partTypeUses[i].isRequired() && !hasPartType[i]) 951 throw new DocumentTypeInconsistencyException("The document doesn't have the required part \"" + partTypeUses[i].getPartType().getName() + "\" (ID: " + partTypeUses[i].getPartType().getId() + ")."); 952 } 953 954 FieldTypeUse[] fieldTypeUses = documentType.getFieldTypeUses(); 956 boolean[] hasFieldType = new boolean[fieldTypeUses.length]; 957 958 Field[] fields = getFields().getArray(); 959 for (int i = 0; i < fields.length; i++) { 960 long fieldTypeId = fields[i].getTypeId(); 961 int fieldTypeIndex = -1; 962 for (int j = 0; j < fieldTypeUses.length; j++) { 963 if (fieldTypeUses[j].getFieldType().getId() == fieldTypeId) { 964 fieldTypeIndex = j; 965 } 966 } 967 if (fieldTypeIndex == -1) 968 throw new DocumentTypeInconsistencyException("The document contains a not-allowed field (FieldType ID: " + fieldTypeId + ")."); 969 hasFieldType[fieldTypeIndex] = true; 970 971 FieldType fieldType = fieldTypeUses[fieldTypeIndex].getFieldType(); 972 checkFieldValue(fieldType, fields[i].getValue()); 973 } 974 975 for (int i = 0; i < fieldTypeUses.length; i++) { 976 if (fieldTypeUses[i].isRequired() && !hasFieldType[i]) 977 throw new DocumentTypeInconsistencyException("The document doesn't have the required field \"" + fieldTypeUses[i].getFieldType().getName() + "\" (ID: " + fieldTypeUses[i].getFieldType().getId() + ")."); 978 } 979 } 980 981 public Date getLastModified() { 982 if (lastModified != null) 983 return (Date)lastModified.clone(); 984 else 985 return lastModified; 986 } 987 988 public long getLastModifier() { 989 return lastModifier; 990 } 991 992 public boolean isRetired() { 993 return retired; 994 } 995 996 public void setRetired(boolean retired) { 997 if (ownerDocument.isReadOnly()) 998 throw new RuntimeException (READ_ONLY_MESSAGE); 999 1000 if (retired != this.retired) { 1001 this.retired = retired; 1002 this.retiredChanged = true; 1003 } 1004 } 1005 1006 public DocumentCollections getCollections() { 1007 return new DocumentCollectionsImpl( 1008 (DocumentCollection[])documentCollections.values().toArray( 1009 new DocumentCollection[documentCollections.size()])); 1010 } 1011 1012 public boolean inCollection(DocumentCollection collection) { 1013 return documentCollections.containsKey(new Long (collection.getId())); 1014 } 1015 1016 public boolean inCollection(long collectionId) { 1017 return documentCollections.containsKey(new Long (collectionId)); 1018 } 1019 1020 public void addToCollection(DocumentCollection c) { 1021 if (ownerDocument.isReadOnly()) 1022 throw new RuntimeException (READ_ONLY_MESSAGE); 1023 1024 if (c.getId() == -1) 1025 throw new IllegalArgumentException ("The specified collection has not yet been saved."); 1026 1027 this.documentCollectionChanges = true; 1028 this.documentCollections.put(new Long (c.getId()), c); 1029 } 1030 1031 public void removeFromCollection(DocumentCollection c) { 1032 if (ownerDocument.isReadOnly()) 1033 throw new RuntimeException (READ_ONLY_MESSAGE); 1034 1035 this.documentCollectionChanges = true; 1036 documentCollections.remove(new Long (c.getId())); 1037 } 1038 1039 public String getSummary() { 1040 return summary == null ? "" : summary; 1041 } 1042 1043 public long getUpdateCount() { 1044 return updateCount; 1045 } 1046 1047 public long getCreatedFromBranchId() { 1048 return createdFromBranchId; 1049 } 1050 1051 public long getCreatedFromLanguageId() { 1052 return createdFromLanguageId; 1053 } 1054 1055 public long getCreatedFromVersionId() { 1056 return createdFromVersionId; 1057 } 1058 1059 1062 public boolean needsNewVersion() { 1063 if (isNew) 1065 return true; 1066 1067 if (nameUpdated || fieldChanges || linkChanges || partChanges) 1068 return true; 1069 1070 return false; 1071 } 1072 1073 public boolean needsSaving() { 1074 boolean nonVersionedChanges = documentCollectionChanges || customFieldChanges || documentTypeChanged || retiredChanged; 1075 if (nonVersionedChanges) 1076 return true; 1077 else 1078 return needsNewVersion(); 1079 } 1080 1081 public class IntimateAccess { 1082 1083 private IntimateAccess() { 1084 } 1085 1086 public void setLockInfo(LockInfoImpl lockInfo) { 1087 DocumentVariantImpl.this.lockInfo = lockInfo; 1088 } 1089 1090 public long getLastVersionId() { 1091 return lastVersionId; 1092 } 1093 1094 public boolean hasCustomFieldChanges() { 1095 return customFieldChanges; 1096 } 1097 1098 public void setIsNew(boolean isNew) { 1099 DocumentVariantImpl.this.isNew = isNew; 1100 } 1101 1102 public boolean isNameUpdated() { 1103 return nameUpdated; 1104 } 1105 1106 public boolean hasFieldChanges() { 1107 return fieldChanges; 1108 } 1109 1110 public boolean hasLinkChanges() { 1111 return linkChanges; 1112 } 1113 1114 public boolean hasPartChanges() { 1115 return partChanges; 1116 } 1117 1118 public boolean hasCollectionChanges() { 1119 return documentCollectionChanges; 1120 } 1121 1122 1125 public void load(long documentTypeId, boolean retired, long lastVersionId, long liveVersionId, 1126 Date lastModified, long lastModifier, long createdFromBranchId, long createdFromLanguageId, 1127 long createdFromVersionId, long updateCount) { 1128 DocumentVariantImpl.this.documentTypeId = documentTypeId; 1129 DocumentVariantImpl.this.retired = retired; 1130 DocumentVariantImpl.this.lastVersionId = lastVersionId; 1131 DocumentVariantImpl.this.liveVersionId = liveVersionId; 1132 DocumentVariantImpl.this.lastModified = lastModified; 1133 DocumentVariantImpl.this.lastModifier = lastModifier; 1134 DocumentVariantImpl.this.createdFromBranchId = createdFromBranchId; 1135 DocumentVariantImpl.this.createdFromLanguageId = createdFromLanguageId; 1136 DocumentVariantImpl.this.createdFromVersionId = createdFromVersionId; 1137 DocumentVariantImpl.this.updateCount = updateCount; 1138 isNew = false; 1139 } 1140 1141 1145 public void saved(long lastVersionId, long liveVersionId, Date lastModified, String summary, long updateCount) { 1146 DocumentVariantImpl.this.lastVersionId = lastVersionId; 1147 DocumentVariantImpl.this.liveVersionId = liveVersionId; 1148 DocumentVariantImpl.this.lastModified = lastModified; 1149 DocumentVariantImpl.this.lastModifier = currentUser.getId(); 1150 DocumentVariantImpl.this.updateCount = updateCount; 1151 DocumentVariantImpl.this.summary = summary; 1152 1153 nameUpdated = false; 1154 partChanges = false; 1155 linkChanges = false; 1156 documentCollectionChanges = false; 1157 1158 PartImpl[] parts = getPartImpls(); 1159 for (int i = 0; i < parts.length; i++) { 1160 PartImpl.IntimateAccess partInt = parts[i].getIntimateAccess(documentStrategy); 1161 partInt.setNewOrUpdated(false, false); 1162 partInt.setData(null); 1163 partInt.setVersionId(lastVersionId); 1164 } 1165 fieldChanges = false; 1166 customFieldChanges = false; 1167 1168 liveVersion = null; 1170 liveVersionLoaded = false; 1171 lastVersion = null; 1172 lastVersionLoaded = false; 1173 isNew = false; 1174 retiredChanged = false; 1175 documentTypeChanged = false; 1176 } 1177 1178 public DocumentStrategy getDocumentStrategy() { 1179 return documentStrategy; 1180 } 1181 1182 public AuthenticatedUser getCurrentUser() { 1183 return currentUser; 1184 } 1185 1186 1189 public void setCustomField(String name, String value) { 1190 customFields.put(name, value); 1191 } 1192 1193 public PartImpl[] getPartImpls() { 1194 return (PartImpl[])parts.values().toArray(new PartImpl[0]); 1195 } 1196 1197 public DocumentCollectionImpl[] getDocumentCollectionImpls() { 1198 return (DocumentCollectionImpl[]) 1199 documentCollections.values().toArray(new DocumentCollectionImpl[0]); 1200 } 1201 1202 1203 public void addPart(PartImpl part) { 1204 parts.put(new Long (part.getTypeId()), part); 1205 } 1206 1207 1210 public void addLink(LinkImpl link) { 1211 links.add(link); 1212 } 1213 1214 1217 public void setName(String name) { 1218 if (name == null) 1219 throw new NullPointerException ("name may not be null."); 1220 DocumentVariantImpl.this.name = name; 1221 } 1222 1223 1227 public void addField(FieldImpl field) { 1228 fields.put(new Long (field.getTypeId()), field); 1229 } 1230 1231 public DocumentImpl getDocument() { 1232 return ownerDocument; 1233 } 1234 1235 public CommonRepositorySchema getRepositorySchema() { 1236 return repositorySchema; 1237 } 1238 1239 1243 public void addCollection(DocumentCollectionImpl collection) { 1244 documentCollections.put(new Long (collection.getId()), collection); 1245 } 1246 1247 public Part[] orderParts(Part[] parts) { 1248 return DocumentVariantImpl.this.orderParts(parts); 1249 } 1250 1251 public Field[] orderFields(Field[] fields) { 1252 return DocumentVariantImpl.this.orderFields(fields); 1253 } 1254 1255 public void setSummary(String summary) { 1256 DocumentVariantImpl.this.summary = summary; 1257 } 1258 1259 public DocumentVariantImpl getVariant() { 1260 return DocumentVariantImpl.this; 1261 } 1262 1263 public void setCreatedFrom(long branchId, long languageId, long versionId) { 1264 createdFromBranchId = branchId; 1265 createdFromLanguageId = languageId; 1266 createdFromVersionId = versionId; 1267 } 1268 1269 public void setStartFrom(long branchId, long languageId) { 1270 startBranchId = branchId; 1271 startLanguageId = languageId; 1272 } 1273 1274 public long getStartBranchId() { 1275 return startBranchId; 1276 } 1277 1278 public long getStartLanguageId() { 1279 return startLanguageId; 1280 } 1281 } 1282} 1283 | Popular Tags |