001/* 002 * Copyright 2010 Anyware Services 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.ametys.plugins.repository.metadata.jcr; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Date; 021import java.util.GregorianCalendar; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Locale; 025import java.util.Set; 026import java.util.regex.Pattern; 027 028import javax.jcr.Node; 029import javax.jcr.NodeIterator; 030import javax.jcr.PathNotFoundException; 031import javax.jcr.Property; 032import javax.jcr.PropertyIterator; 033import javax.jcr.PropertyType; 034import javax.jcr.RepositoryException; 035import javax.jcr.Value; 036import javax.jcr.lock.Lock; 037import javax.jcr.lock.LockManager; 038 039import org.apache.commons.lang3.LocaleUtils; 040 041import org.ametys.core.user.UserIdentity; 042import org.ametys.plugins.repository.AmetysObjectResolver; 043import org.ametys.plugins.repository.AmetysRepositoryException; 044import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 045import org.ametys.plugins.repository.RepositoryConstants; 046import org.ametys.plugins.repository.jcr.NodeTypeHelper; 047import org.ametys.plugins.repository.metadata.CommentableCompositeMetadata; 048import org.ametys.plugins.repository.metadata.MetadataComment; 049import org.ametys.plugins.repository.metadata.ModifiableBinaryMetadata; 050import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 051import org.ametys.plugins.repository.metadata.ModifiableFile; 052import org.ametys.plugins.repository.metadata.ModifiableFolder; 053import org.ametys.plugins.repository.metadata.ModifiableResource; 054import org.ametys.plugins.repository.metadata.ModifiableRichText; 055import org.ametys.plugins.repository.metadata.MultilingualString; 056import org.ametys.plugins.repository.metadata.UnknownMetadataException; 057 058/** 059 * JCR implementation of a CompositeMetadata.<br> 060 * This implementation is based on a child node of the Node supporting the actual content. 061 */ 062public class JCRCompositeMetadata implements ModifiableCompositeMetadata, CommentableCompositeMetadata 063{ 064 /** Prefix for jcr properties and nodes names */ 065 public static final String METADATA_PREFIX = RepositoryConstants.NAMESPACE_PREFIX + ':'; 066 067 /** Comments metadata suffix */ 068 public static final String METADATA_COMMENTS_SUFFIX = "_comments"; 069 070 /** The JCR nodetype of object collection metadata. */ 071 public static final String OBJECT_COLLECTION_METADATA_NODETYPE = METADATA_PREFIX + "objectCollectionMetadata"; 072 073 /** The JCR nodetype of multilingual metadata. */ 074 public static final String MULTILINGUAL_STRING_METADATA_NODETYPE = METADATA_PREFIX + "multilingualString"; 075 076 private static Pattern __metadataNamePattern; 077 078 private Node _node; 079 private boolean _lockAlreadyChecked; 080 private AmetysObjectResolver _resolver; 081 082 /** 083 * Constructor 084 * @param metadataNode the Node supporting this composite metadata 085 * @param resolver The resolver, used to resolve object collections. 086 */ 087 public JCRCompositeMetadata(Node metadataNode, AmetysObjectResolver resolver) 088 { 089 _node = metadataNode; 090 _resolver = resolver; 091 } 092 093 /** 094 * Retrieves the underlying node. 095 * @return the underlying node. 096 */ 097 public Node getNode() 098 { 099 return _node; 100 } 101 102 public boolean hasMetadata(String metadataName) throws AmetysRepositoryException 103 { 104 try 105 { 106 // TODO filter sub-nodes by type (like in getMetadataNames). 107 return _node.hasProperty(METADATA_PREFIX + metadataName) || _node.hasNode(METADATA_PREFIX + metadataName); 108 } 109 catch (RepositoryException e) 110 { 111 throw new AmetysRepositoryException(e); 112 } 113 } 114 115 @Override 116 public void rename(String newName) throws AmetysRepositoryException 117 { 118 try 119 { 120 getNode().getSession().move(getNode().getPath(), getNode().getParent().getPath() + "/" + newName); 121 } 122 catch (RepositoryException e) 123 { 124 throw new AmetysRepositoryException(e); 125 } 126 } 127 128 public void removeMetadata(String metadataName) throws AmetysRepositoryException 129 { 130 try 131 { 132 _checkLock(); 133 String realMetadataName = METADATA_PREFIX + metadataName; 134 135 if (_node.hasProperty(realMetadataName)) 136 { 137 _node.getProperty(realMetadataName).remove(); 138 } 139 else if (_node.hasNode(realMetadataName)) 140 { 141 // Remove all existing nodes 142 NodeIterator it = _node.getNodes(realMetadataName); 143 while (it.hasNext()) 144 { 145 Node next = it.nextNode(); 146 next.remove(); 147 } 148 } 149 else 150 { 151 throw new UnknownMetadataException("No metadata for name: " + metadataName); 152 } 153 } 154 catch (RepositoryException e) 155 { 156 throw new AmetysRepositoryException("Unable to remove metadata " + metadataName, e); 157 } 158 } 159 160 @Override 161 public void copyTo(ModifiableCompositeMetadata metadata) throws AmetysRepositoryException 162 { 163 String[] metadataNames = getMetadataNames(); 164 for (String metadataName : metadataNames) 165 { 166 if (hasMetadata(metadataName)) 167 { 168 MetadataType type = getType(metadataName); 169 170 boolean multiple = isMultiple(metadataName); 171 switch (type) 172 { 173 case COMPOSITE: 174 ModifiableCompositeMetadata compositeMetadata = metadata.getCompositeMetadata(metadataName, true); 175 getCompositeMetadata(metadataName).copyTo(compositeMetadata); 176 break; 177 case USER: 178 if (multiple) 179 { 180 metadata.setMetadata(metadataName, getUserArray(metadataName)); 181 } 182 else 183 { 184 metadata.setMetadata(metadataName, getUser(metadataName)); 185 } 186 break; 187 case BOOLEAN: 188 if (multiple) 189 { 190 metadata.setMetadata(metadataName, getBooleanArray(metadataName)); 191 } 192 else 193 { 194 metadata.setMetadata(metadataName, getBoolean(metadataName)); 195 } 196 break; 197 case DATE: 198 if (multiple) 199 { 200 metadata.setMetadata(metadataName, getDateArray(metadataName)); 201 } 202 else 203 { 204 metadata.setMetadata(metadataName, getDate(metadataName)); 205 } 206 break; 207 case DOUBLE: 208 if (multiple) 209 { 210 metadata.setMetadata(metadataName, getDoubleArray(metadataName)); 211 } 212 else 213 { 214 metadata.setMetadata(metadataName, getDouble(metadataName)); 215 } 216 break; 217 case LONG: 218 if (multiple) 219 { 220 metadata.setMetadata(metadataName, getLongArray(metadataName)); 221 } 222 else 223 { 224 metadata.setMetadata(metadataName, getLong(metadataName)); 225 } 226 break; 227 case BINARY: 228 ModifiableBinaryMetadata binaryMetadata = metadata.getBinaryMetadata(metadataName, true); 229 ModifiableBinaryMetadata srcBinary = getBinaryMetadata(metadataName); 230 231 binaryMetadata.setFilename(srcBinary.getFilename()); 232 binaryMetadata.setMimeType(srcBinary.getMimeType()); 233 binaryMetadata.setLastModified(srcBinary.getLastModified()); 234 binaryMetadata.setEncoding(srcBinary.getEncoding()); 235 binaryMetadata.setInputStream(srcBinary.getInputStream()); 236 break; 237 case RICHTEXT: 238 ModifiableRichText richText = metadata.getRichText(metadataName, true); 239 ModifiableRichText srcRichText = getRichText(metadataName); 240 241 richText.setInputStream(srcRichText.getInputStream()); 242 richText.setEncoding(srcRichText.getEncoding()); 243 richText.setLastModified(srcRichText.getLastModified()); 244 richText.setMimeType(srcRichText.getMimeType()); 245 246 // Copy additional data 247 _copyDataFolder (srcRichText.getAdditionalDataFolder(), richText.getAdditionalDataFolder()); 248 break; 249 case MULTILINGUAL_STRING: 250 MultilingualString srcMultilingualString = getMultilingualString(metadataName); 251 metadata.setMetadata(metadataName, srcMultilingualString); 252 break; 253 default: 254 if (multiple) 255 { 256 metadata.setMetadata(metadataName, getStringArray(metadataName)); 257 } 258 else 259 { 260 metadata.setMetadata(metadataName, getString(metadataName)); 261 } 262 break; 263 } 264 } 265 } 266 } 267 268 private void _copyDataFolder (ModifiableFolder srcDataFolder, ModifiableFolder targetDataFolder) 269 { 270 // Copy folders 271 Collection<ModifiableFolder> folders = srcDataFolder.getFolders(); 272 for (ModifiableFolder srcSubfolder : folders) 273 { 274 ModifiableFolder targetSubFolder = targetDataFolder.addFolder(srcSubfolder.getName()); 275 _copyDataFolder (srcSubfolder, targetSubFolder); 276 } 277 278 // Copy files 279 Collection<ModifiableFile> files = srcDataFolder.getFiles(); 280 for (ModifiableFile srcFile : files) 281 { 282 _copyFile (srcFile, targetDataFolder); 283 } 284 } 285 286 private void _copyFile (ModifiableFile srcFile, ModifiableFolder targetDataFolder) 287 { 288 ModifiableResource srcResource = srcFile.getResource(); 289 290 ModifiableFile targetFile = targetDataFolder.addFile(srcFile.getName()); 291 ModifiableResource targetResource = targetFile.getResource(); 292 293 targetResource.setLastModified(srcResource.getLastModified()); 294 targetResource.setMimeType(srcResource.getMimeType()); 295 targetResource.setEncoding(srcResource.getEncoding()); 296 targetResource.setInputStream(srcResource.getInputStream()); 297 } 298 299 public MetadataType getType(String metadataName) throws AmetysRepositoryException 300 { 301 try 302 { 303 String realMetadataName = METADATA_PREFIX + metadataName; 304 305 if (_node.hasNode(realMetadataName)) 306 { 307 Node node = _node.getNode(realMetadataName); 308 String type = node.getPrimaryNodeType().getName(); 309 if ("nt:frozenNode".equals(_node.getPrimaryNodeType().getName())) 310 { 311 // on version history 312 type = node.getProperty("jcr:frozenPrimaryType").getString(); 313 } 314 315 if (type.equals(OBJECT_COLLECTION_METADATA_NODETYPE)) 316 { 317 return MetadataType.OBJECT_COLLECTION; 318 } 319 else if (type.equals(METADATA_PREFIX + "binaryMetadata")) 320 { 321 return MetadataType.BINARY; 322 } 323 else if (type.equals(METADATA_PREFIX + "richText")) 324 { 325 return MetadataType.RICHTEXT; 326 } 327 else if (type.equals(METADATA_PREFIX + "user")) 328 { 329 return MetadataType.USER; 330 } 331 else if (type.equals(MULTILINGUAL_STRING_METADATA_NODETYPE)) 332 { 333 return MetadataType.MULTILINGUAL_STRING; 334 } 335 else 336 { 337 return MetadataType.COMPOSITE; 338 } 339 } 340 341 if (_node.hasProperty(realMetadataName)) 342 { 343 Property property = _node.getProperty(realMetadataName); 344 int type = property.getType(); 345 346 switch (type) 347 { 348 case PropertyType.STRING: 349 return MetadataType.STRING; 350 case PropertyType.BOOLEAN: 351 return MetadataType.BOOLEAN; 352 case PropertyType.DATE: 353 return MetadataType.DATE; 354 case PropertyType.DOUBLE: 355 return MetadataType.DOUBLE; 356 case PropertyType.LONG: 357 return MetadataType.LONG; 358 default: 359 throw new AmetysRepositoryException("Unhandled JCR property type : " + PropertyType.nameFromValue(type)); 360 } 361 } 362 363 throw new UnknownMetadataException("No metadata for name: " + metadataName); 364 } 365 catch (RepositoryException e) 366 { 367 throw new AmetysRepositoryException("Unable to get property type", e); 368 } 369 } 370 371 public String getString(String metadataName) 372 { 373 return _getString(metadataName, null, true); 374 } 375 376 @Override 377 public String getString(String metadataName, String defaultValue) 378 { 379 return _getString(metadataName, defaultValue, false); 380 } 381 382 private String _getString(String metadataName, String defaultValue, boolean failIfNotExist) 383 { 384 try 385 { 386 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 387 388 if (property.getDefinition().isMultiple()) 389 { 390 Value[] values = property.getValues(); 391 392 if (values.length > 0) 393 { 394 return values[0].getString(); 395 } 396 else 397 { 398 throw new AmetysRepositoryException("Cannot get a String from an empty array"); 399 } 400 } 401 402 return property.getString(); 403 } 404 catch (PathNotFoundException e) 405 { 406 if (failIfNotExist) 407 { 408 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 409 } 410 else 411 { 412 return defaultValue; 413 } 414 } 415 catch (RepositoryException e) 416 { 417 throw new AmetysRepositoryException("Unable to get String property", e); 418 } 419 } 420 421 public String[] getStringArray(String metadataName) throws AmetysRepositoryException 422 { 423 return _getStringArray(metadataName, null, true); 424 } 425 426 public String[] getStringArray(String metadataName, String[] defaultValues) 427 { 428 return _getStringArray(metadataName, defaultValues, false); 429 } 430 431 private String[] _getStringArray(String metadataName, String[] defaultValues, boolean failIfNotExist) 432 { 433 try 434 { 435 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 436 437 if (property.getDefinition().isMultiple()) 438 { 439 Value[] values = property.getValues(); 440 441 String[] results = new String[values.length]; 442 for (int i = 0; i < values.length; i++) 443 { 444 Value value = values[i]; 445 results[i] = value.getString(); 446 } 447 448 return results; 449 } 450 451 Value value = property.getValue(); 452 return new String[] {value.getString()}; 453 } 454 catch (PathNotFoundException e) 455 { 456 if (failIfNotExist) 457 { 458 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 459 } 460 else 461 { 462 return defaultValues; 463 } 464 } 465 catch (RepositoryException e) 466 { 467 throw new AmetysRepositoryException("Unable to get String array property", e); 468 } 469 } 470 471 @Override 472 public String getLocalizedString(String metadataName, Locale locale) throws UnknownMetadataException, AmetysRepositoryException 473 { 474 return _getString(metadataName, locale, null, true); 475 } 476 477 @Override 478 public String getLocalizedString(String metadataName, Locale locale, String defaultValue) throws AmetysRepositoryException 479 { 480 return _getString(metadataName, locale, defaultValue, false); 481 } 482 483 @Override 484 public MultilingualString getMultilingualString(String metadataName) throws AmetysRepositoryException 485 { 486 try 487 { 488 if (_node.hasNode(METADATA_PREFIX + metadataName)) 489 { 490 Node node = _node.getNode(METADATA_PREFIX + metadataName); 491 492 MultilingualString values = new MultilingualString(); 493 494 PropertyIterator properties = node.getProperties(); 495 while (properties.hasNext()) 496 { 497 Property property = properties.nextProperty(); 498 String name = property.getName(); 499 500 try 501 { 502 Locale locale = LocaleUtils.toLocale(name); 503 values.add(locale, property.getString()); 504 } 505 catch (IllegalArgumentException e) 506 { 507 // Property is not a valid locale, ignore it. 508 } 509 } 510 511 return values; 512 } 513 else 514 { 515 throw new UnknownMetadataException("No multilingual String named " + metadataName); 516 } 517 } 518 catch (RepositoryException e) 519 { 520 throw new AmetysRepositoryException("Unable to get multilingual String property", e); 521 } 522 } 523 524 private String _getString(String metadataName, Locale locale, String defaultValue, boolean failIfNotExist) 525 { 526 try 527 { 528 Node node = _node.getNode(METADATA_PREFIX + metadataName); 529 530 Property property = node.getProperty(locale.toString()); 531 return property.getString(); 532 } 533 catch (PathNotFoundException e) 534 { 535 if (failIfNotExist) 536 { 537 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 538 } 539 else 540 { 541 return defaultValue; 542 } 543 } 544 catch (RepositoryException e) 545 { 546 throw new AmetysRepositoryException("Unable to get String property", e); 547 } 548 } 549 550 public boolean getBoolean(String metadataName) throws UnknownMetadataException, AmetysRepositoryException 551 { 552 return _getBoolean(metadataName, null, true); 553 } 554 555 public boolean getBoolean(String metadataName, boolean defaultValue) throws AmetysRepositoryException 556 { 557 return _getBoolean(metadataName, defaultValue, false); 558 } 559 560 private boolean _getBoolean(String metadataName, Boolean defaultValue, boolean failIfNotExist) 561 { 562 try 563 { 564 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 565 566 if (property.getDefinition().isMultiple()) 567 { 568 Value[] values = property.getValues(); 569 570 if (values.length > 0) 571 { 572 return values[0].getBoolean(); 573 } 574 else 575 { 576 throw new AmetysRepositoryException("Cannot get a boolean from an empty array"); 577 } 578 } 579 580 return property.getBoolean(); 581 } 582 catch (PathNotFoundException e) 583 { 584 if (failIfNotExist) 585 { 586 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 587 } 588 else 589 { 590 return defaultValue; 591 } 592 } 593 catch (RepositoryException e) 594 { 595 throw new AmetysRepositoryException("Unable to get boolean property", e); 596 } 597 } 598 599 public boolean[] getBooleanArray(String metadataName) throws AmetysRepositoryException 600 { 601 return _getBooleanArray(metadataName, null, true); 602 } 603 604 public boolean[] getBooleanArray(String metadataName, boolean[] defaultValues) 605 { 606 return _getBooleanArray(metadataName, defaultValues, false); 607 } 608 609 private boolean[] _getBooleanArray(String metadataName, boolean[] defaultValues, boolean failIfNotExist) 610 { 611 try 612 { 613 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 614 615 if (property.getDefinition().isMultiple()) 616 { 617 Value[] values = property.getValues(); 618 619 boolean[] results = new boolean[values.length]; 620 for (int i = 0; i < values.length; i++) 621 { 622 Value value = values[i]; 623 results[i] = value.getBoolean(); 624 } 625 626 return results; 627 } 628 629 Value value = property.getValue(); 630 return new boolean[] {value.getBoolean()}; 631 } 632 catch (PathNotFoundException e) 633 { 634 if (failIfNotExist) 635 { 636 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 637 } 638 else 639 { 640 return defaultValues; 641 } 642 } 643 catch (RepositoryException e) 644 { 645 throw new AmetysRepositoryException("Unable to get boolean array property", e); 646 } 647 } 648 649 public Date getDate(String metadataName) throws AmetysRepositoryException 650 { 651 return _getDate(metadataName, null, true); 652 } 653 654 public Date getDate(String metadataName, Date defaultValue) throws AmetysRepositoryException 655 { 656 return _getDate(metadataName, defaultValue, false); 657 } 658 659 private Date _getDate(String metadataName, Date defaultValue, boolean failIfNotExist) 660 { 661 try 662 { 663 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 664 665 if (property.getDefinition().isMultiple()) 666 { 667 Value[] values = property.getValues(); 668 669 if (values.length > 0) 670 { 671 return values[0].getDate().getTime(); 672 } 673 else 674 { 675 throw new AmetysRepositoryException("Cannot get a date from an empty array"); 676 } 677 } 678 679 return property.getDate().getTime(); 680 } 681 catch (PathNotFoundException e) 682 { 683 if (failIfNotExist) 684 { 685 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 686 } 687 else 688 { 689 return defaultValue; 690 } 691 } 692 catch (RepositoryException e) 693 { 694 throw new AmetysRepositoryException("Unable to get date property", e); 695 } 696 } 697 698 public Date[] getDateArray(String metadataName) throws AmetysRepositoryException 699 { 700 return _getDateArray(metadataName, null, true); 701 } 702 703 public Date[] getDateArray(String metadataName, Date[] defaultValues) 704 { 705 return _getDateArray(metadataName, defaultValues, false); 706 } 707 708 private Date[] _getDateArray(String metadataName, Date[] defaultValues, boolean failIfNotExist) 709 { 710 try 711 { 712 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 713 714 if (property.getDefinition().isMultiple()) 715 { 716 Value[] values = property.getValues(); 717 718 Date[] results = new Date[values.length]; 719 for (int i = 0; i < values.length; i++) 720 { 721 Value value = values[i]; 722 results[i] = value.getDate().getTime(); 723 } 724 725 return results; 726 } 727 728 Value value = property.getValue(); 729 return new Date[] {value.getDate().getTime()}; 730 } 731 catch (PathNotFoundException e) 732 { 733 if (failIfNotExist) 734 { 735 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 736 } 737 else 738 { 739 return defaultValues; 740 } 741 } 742 catch (RepositoryException e) 743 { 744 throw new AmetysRepositoryException("Unable to get date array property", e); 745 } 746 } 747 748 public long getLong(String metadataName) throws AmetysRepositoryException 749 { 750 return _getLong(metadataName, null, true); 751 } 752 753 public long getLong(String metadataName, long defaultValue) throws AmetysRepositoryException 754 { 755 return _getLong(metadataName, defaultValue, false); 756 } 757 758 private long _getLong(String metadataName, Long defaultValue, boolean failIfNotExist) 759 { 760 try 761 { 762 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 763 764 if (property.getDefinition().isMultiple()) 765 { 766 Value[] values = property.getValues(); 767 768 if (values.length > 0) 769 { 770 return values[0].getLong(); 771 } 772 else 773 { 774 throw new AmetysRepositoryException("Cannot get a long from an empty array"); 775 } 776 } 777 778 return property.getLong(); 779 } 780 catch (PathNotFoundException e) 781 { 782 if (failIfNotExist) 783 { 784 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 785 } 786 else 787 { 788 return defaultValue; 789 } 790 } 791 catch (RepositoryException e) 792 { 793 throw new AmetysRepositoryException("Unable to get long property", e); 794 } 795 } 796 797 public long[] getLongArray(String metadataName) throws AmetysRepositoryException 798 { 799 return _getLongArray(metadataName, null, true); 800 } 801 802 public long[] getLongArray(String metadataName, long[] defaultValues) 803 { 804 return _getLongArray(metadataName, defaultValues, false); 805 } 806 807 private long[] _getLongArray(String metadataName, long[] defaultValues, boolean failIfNotExist) 808 { 809 try 810 { 811 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 812 813 if (property.getDefinition().isMultiple()) 814 { 815 Value[] values = property.getValues(); 816 817 long[] results = new long[values.length]; 818 for (int i = 0; i < values.length; i++) 819 { 820 Value value = values[i]; 821 results[i] = value.getLong(); 822 } 823 824 return results; 825 } 826 827 Value value = property.getValue(); 828 return new long[] {value.getLong()}; 829 } 830 catch (PathNotFoundException e) 831 { 832 if (failIfNotExist) 833 { 834 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 835 } 836 else 837 { 838 return defaultValues; 839 } 840 } 841 catch (RepositoryException e) 842 { 843 throw new AmetysRepositoryException("Unable to get long array property", e); 844 } 845 } 846 847 public double getDouble(String metadataName) throws AmetysRepositoryException 848 { 849 return _getDouble(metadataName, null, true); 850 } 851 852 public double getDouble(String metadataName, double defaultValue) throws AmetysRepositoryException 853 { 854 return _getDouble(metadataName, defaultValue, false); 855 } 856 857 private double _getDouble(String metadataName, Double defaultValue, boolean failIfNotExist) 858 { 859 try 860 { 861 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 862 863 if (property.getDefinition().isMultiple()) 864 { 865 Value[] values = property.getValues(); 866 867 if (values.length > 0) 868 { 869 return values[0].getDouble(); 870 } 871 else 872 { 873 throw new AmetysRepositoryException("Cannot get a double from an empty array"); 874 } 875 } 876 877 return property.getDouble(); 878 } 879 catch (PathNotFoundException e) 880 { 881 if (failIfNotExist) 882 { 883 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 884 } 885 else 886 { 887 return defaultValue; 888 } 889 } 890 catch (RepositoryException e) 891 { 892 throw new AmetysRepositoryException("Unable to get double property", e); 893 } 894 } 895 896 public double[] getDoubleArray(String metadataName) throws AmetysRepositoryException 897 { 898 return _getDoubleArray(metadataName, null, true); 899 } 900 901 public double[] getDoubleArray(String metadataName, double[] defaultValues) 902 { 903 return _getDoubleArray(metadataName, defaultValues, false); 904 } 905 906 private double[] _getDoubleArray(String metadataName, double[] defaultValues, boolean failIfNotExist) 907 { 908 try 909 { 910 Property property = _node.getProperty(METADATA_PREFIX + metadataName); 911 912 if (property.getDefinition().isMultiple()) 913 { 914 Value[] values = property.getValues(); 915 916 double[] results = new double[values.length]; 917 for (int i = 0; i < values.length; i++) 918 { 919 Value value = values[i]; 920 results[i] = value.getDouble(); 921 } 922 923 return results; 924 } 925 926 Value value = property.getValue(); 927 return new double[] {value.getDouble()}; 928 } 929 catch (PathNotFoundException e) 930 { 931 if (failIfNotExist) 932 { 933 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 934 } 935 else 936 { 937 return defaultValues; 938 } 939 } 940 catch (RepositoryException e) 941 { 942 throw new AmetysRepositoryException("Unable to get double array property", e); 943 } 944 } 945 946 public UserIdentity getUser(String metadataName) throws AmetysRepositoryException 947 { 948 return _getUser(metadataName, null, true); 949 } 950 951 public UserIdentity getUser(String metadataName, UserIdentity defaultValue) throws AmetysRepositoryException 952 { 953 return _getUser(metadataName, defaultValue, false); 954 } 955 956 private UserIdentity _getUser(String metadataName, UserIdentity defaultValue, boolean failIfNotExist) throws AmetysRepositoryException 957 { 958 try 959 { 960 Node userNode = _node.getNode(METADATA_PREFIX + metadataName); 961 return new UserIdentity(userNode.getProperty("ametys:login").getString(), userNode.getProperty("ametys:population").getString()); 962 } 963 catch (PathNotFoundException e) 964 { 965 if (failIfNotExist) 966 { 967 throw new UnknownMetadataException("Unknown metadata " + METADATA_PREFIX + metadataName + " of " + _node, e); 968 } 969 else 970 { 971 return defaultValue; 972 } 973 } 974 catch (RepositoryException e) 975 { 976 throw new AmetysRepositoryException("Unable to get User metadata", e); 977 } 978 } 979 980 @Override 981 public UserIdentity[] getUserArray(String metadataName) throws AmetysRepositoryException 982 { 983 return _getUserArray(metadataName, null, true); 984 } 985 986 @Override 987 public UserIdentity[] getUserArray(String metadataName, UserIdentity[] defaultValues) throws AmetysRepositoryException 988 { 989 return _getUserArray(metadataName, defaultValues, false); 990 } 991 992 private UserIdentity[] _getUserArray(String metadataName, UserIdentity[] defaultValues, boolean failIfNotExist) throws AmetysRepositoryException 993 { 994 try 995 { 996 if (_node.hasNode(METADATA_PREFIX + metadataName)) 997 { 998 List<UserIdentity> results = new ArrayList<>(); 999 1000 NodeIterator it = _node.getNodes(METADATA_PREFIX + metadataName); 1001 while (it.hasNext()) 1002 { 1003 Node next = (Node) it.next(); 1004 results.add(new UserIdentity(next.getProperty("ametys:login").getString(), next.getProperty("ametys:population").getString())); 1005 } 1006 1007 return results.toArray(new UserIdentity[results.size()]); 1008 } 1009 else if (failIfNotExist) 1010 { 1011 throw new UnknownMetadataException("The metadata '" + metadataName + "' does not exist"); 1012 } 1013 else 1014 { 1015 return defaultValues; 1016 } 1017 } 1018 catch (RepositoryException e) 1019 { 1020 throw new AmetysRepositoryException("Unable to get User array metadata", e); 1021 } 1022 } 1023 1024 @Override 1025 public void setMetadata(String metadataName, String value) throws AmetysRepositoryException 1026 { 1027 if (value == null) 1028 { 1029 throw new NullPointerException("metadata value cannot be null"); 1030 } 1031 1032 _checkMetadataName(metadataName); 1033 1034 try 1035 { 1036 _checkLock(); 1037 _node.setProperty(METADATA_PREFIX + metadataName, value); 1038 } 1039 catch (RepositoryException e) 1040 { 1041 throw new AmetysRepositoryException("Unable to set property", e); 1042 } 1043 } 1044 1045 @Override 1046 public void setMetadata(String metadataName, String[] value) throws AmetysRepositoryException 1047 { 1048 if (value == null) 1049 { 1050 throw new NullPointerException("metadata value cannot be null"); 1051 } 1052 1053 _checkMetadataName(metadataName); 1054 1055 try 1056 { 1057 _checkLock(); 1058 _node.setProperty(METADATA_PREFIX + metadataName, value); 1059 } 1060 catch (RepositoryException e) 1061 { 1062 throw new AmetysRepositoryException("Unable to set property", e); 1063 } 1064 } 1065 1066 @Override 1067 public void setMetadata(String metadataName, String value, Locale locale) throws AmetysRepositoryException 1068 { 1069 if (value == null) 1070 { 1071 throw new NullPointerException("metadata value cannot be null"); 1072 } 1073 1074 _checkMetadataName(metadataName); 1075 1076 try 1077 { 1078 _checkLock(); 1079 1080 Node node = null; 1081 if (_node.hasNode(METADATA_PREFIX + metadataName)) 1082 { 1083 node = _node.getNode(METADATA_PREFIX + metadataName); 1084 } 1085 else 1086 { 1087 node = _node.addNode(METADATA_PREFIX + metadataName, MULTILINGUAL_STRING_METADATA_NODETYPE); 1088 } 1089 1090 node.setProperty(locale.toString(), value); 1091 } 1092 catch (RepositoryException e) 1093 { 1094 throw new AmetysRepositoryException("Unable to set property", e); 1095 } 1096 } 1097 1098 @Override 1099 public void setMetadata(String metadataName, Date value) throws AmetysRepositoryException 1100 { 1101 if (value == null) 1102 { 1103 throw new NullPointerException("metadata value cannot be null"); 1104 } 1105 1106 GregorianCalendar calendar = new GregorianCalendar(); 1107 calendar.setTime(value); 1108 1109 _checkMetadataName(metadataName); 1110 1111 try 1112 { 1113 _checkLock(); 1114 _node.setProperty(METADATA_PREFIX + metadataName, calendar); 1115 } 1116 catch (RepositoryException e) 1117 { 1118 throw new AmetysRepositoryException("Unable to set property", e); 1119 } 1120 } 1121 1122 @Override 1123 public void setMetadata(String metadataName, Date[] values) throws AmetysRepositoryException 1124 { 1125 if (values == null) 1126 { 1127 throw new NullPointerException("metadata value cannot be null"); 1128 } 1129 1130 _checkMetadataName(metadataName); 1131 1132 try 1133 { 1134 _checkLock(); 1135 Value[] jcrValues = new Value[values.length]; 1136 1137 for (int i = 0; i < values.length; i++) 1138 { 1139 Date value = values[i]; 1140 1141 GregorianCalendar calendar = new GregorianCalendar(); 1142 calendar.setTime(value); 1143 1144 jcrValues[i] = _node.getSession().getValueFactory().createValue(calendar); 1145 } 1146 1147 _node.setProperty(METADATA_PREFIX + metadataName, jcrValues); 1148 } 1149 catch (RepositoryException e) 1150 { 1151 throw new AmetysRepositoryException("Unable to set property", e); 1152 } 1153 } 1154 1155 @Override 1156 public void setMetadata(String metadataName, long value) throws AmetysRepositoryException 1157 { 1158 _checkMetadataName(metadataName); 1159 1160 try 1161 { 1162 _checkLock(); 1163 _node.setProperty(METADATA_PREFIX + metadataName, value); 1164 } 1165 catch (RepositoryException e) 1166 { 1167 throw new AmetysRepositoryException("Unable to set property", e); 1168 } 1169 } 1170 1171 @Override 1172 public void setMetadata(String metadataName, double value) throws AmetysRepositoryException 1173 { 1174 _checkMetadataName(metadataName); 1175 1176 try 1177 { 1178 _checkLock(); 1179 _node.setProperty(METADATA_PREFIX + metadataName, value); 1180 } 1181 catch (RepositoryException e) 1182 { 1183 throw new AmetysRepositoryException("Unable to set property", e); 1184 } 1185 } 1186 1187 @Override 1188 public void setMetadata(String metadataName, long[] values) throws AmetysRepositoryException 1189 { 1190 if (values == null) 1191 { 1192 throw new NullPointerException("metadata value cannot be null"); 1193 } 1194 1195 _checkMetadataName(metadataName); 1196 1197 try 1198 { 1199 _checkLock(); 1200 Value[] jcrValues = new Value[values.length]; 1201 1202 for (int i = 0; i < values.length; i++) 1203 { 1204 long value = values[i]; 1205 jcrValues[i] = _node.getSession().getValueFactory().createValue(value); 1206 } 1207 1208 _node.setProperty(METADATA_PREFIX + metadataName, jcrValues); 1209 } 1210 catch (RepositoryException e) 1211 { 1212 throw new AmetysRepositoryException("Unable to set property", e); 1213 } 1214 } 1215 1216 @Override 1217 public void setMetadata(String metadataName, double[] values) throws AmetysRepositoryException 1218 { 1219 if (values == null) 1220 { 1221 throw new NullPointerException("metadata value cannot be null"); 1222 } 1223 1224 _checkMetadataName(metadataName); 1225 1226 try 1227 { 1228 _checkLock(); 1229 Value[] jcrValues = new Value[values.length]; 1230 1231 for (int i = 0; i < values.length; i++) 1232 { 1233 double value = values[i]; 1234 jcrValues[i] = _node.getSession().getValueFactory().createValue(value); 1235 } 1236 1237 _node.setProperty(METADATA_PREFIX + metadataName, jcrValues); 1238 } 1239 catch (RepositoryException e) 1240 { 1241 throw new AmetysRepositoryException("Unable to set property", e); 1242 } 1243 } 1244 1245 @Override 1246 public void setMetadata(String metadataName, boolean value) throws AmetysRepositoryException 1247 { 1248 _checkMetadataName(metadataName); 1249 1250 try 1251 { 1252 _checkLock(); 1253 _node.setProperty(METADATA_PREFIX + metadataName, value); 1254 } 1255 catch (RepositoryException e) 1256 { 1257 throw new AmetysRepositoryException("Unable to set property", e); 1258 } 1259 } 1260 1261 @Override 1262 public void setMetadata(String metadataName, boolean[] values) throws AmetysRepositoryException 1263 { 1264 if (values == null) 1265 { 1266 throw new NullPointerException("metadata value cannot be null"); 1267 } 1268 1269 _checkMetadataName(metadataName); 1270 1271 try 1272 { 1273 _checkLock(); 1274 Value[] jcrValues = new Value[values.length]; 1275 1276 for (int i = 0; i < values.length; i++) 1277 { 1278 boolean value = values[i]; 1279 jcrValues[i] = _node.getSession().getValueFactory().createValue(value); 1280 } 1281 1282 _node.setProperty(METADATA_PREFIX + metadataName, jcrValues); 1283 } 1284 catch (RepositoryException e) 1285 { 1286 throw new AmetysRepositoryException("Unable to set property", e); 1287 } 1288 } 1289 1290 @Override 1291 public void setMetadata(String metadataName, UserIdentity value) throws AmetysRepositoryException 1292 { 1293 _checkMetadataName(metadataName); 1294 1295 try 1296 { 1297 _checkLock(); 1298 1299 Node userNode = null; 1300 if (_node.hasNode(METADATA_PREFIX + metadataName)) 1301 { 1302 userNode = _node.getNode(METADATA_PREFIX + metadataName); 1303 } 1304 else 1305 { 1306 userNode = _node.addNode(METADATA_PREFIX + metadataName, RepositoryConstants.USER_NODETYPE); 1307 } 1308 userNode.setProperty(METADATA_PREFIX + "login", value.getLogin()); 1309 userNode.setProperty(METADATA_PREFIX + "population", value.getPopulationId()); 1310 } 1311 catch (RepositoryException e) 1312 { 1313 throw new AmetysRepositoryException("Unable to set property", e); 1314 } 1315 } 1316 1317 @Override 1318 public void setMetadata(String metadataName, UserIdentity[] values) throws AmetysRepositoryException 1319 { 1320 if (values == null) 1321 { 1322 throw new NullPointerException("metadata value cannot be null"); 1323 } 1324 1325 _checkMetadataName(metadataName); 1326 1327 try 1328 { 1329 _checkLock(); 1330 1331 NodeIterator it = _node.getNodes(METADATA_PREFIX + metadataName); 1332 while (it.hasNext()) 1333 { 1334 Node next = (Node) it.next(); 1335 next.remove(); 1336 } 1337 1338 for (UserIdentity value : values) 1339 { 1340 Node userNode = _node.addNode(METADATA_PREFIX + metadataName, RepositoryConstants.USER_NODETYPE); 1341 userNode.setProperty(METADATA_PREFIX + "login", value.getLogin()); 1342 userNode.setProperty(METADATA_PREFIX + "population", value.getPopulationId()); 1343 } 1344 } 1345 catch (RepositoryException e) 1346 { 1347 throw new AmetysRepositoryException("Unable to set property", e); 1348 } 1349 } 1350 1351 @Override 1352 public void setMetadata(String metadataName, MultilingualString value) throws AmetysRepositoryException 1353 { 1354 if (value == null) 1355 { 1356 throw new NullPointerException("metadata value cannot be null"); 1357 } 1358 1359 _checkMetadataName(metadataName); 1360 1361 try 1362 { 1363 _checkLock(); 1364 1365 NodeIterator it = _node.getNodes(METADATA_PREFIX + metadataName); 1366 while (it.hasNext()) 1367 { 1368 Node next = (Node) it.next(); 1369 next.remove(); 1370 } 1371 1372 Node node = null; 1373 if (_node.hasNode(METADATA_PREFIX + metadataName)) 1374 { 1375 node = _node.getNode(METADATA_PREFIX + metadataName); 1376 } 1377 else 1378 { 1379 node = _node.addNode(METADATA_PREFIX + metadataName, MULTILINGUAL_STRING_METADATA_NODETYPE); 1380 } 1381 1382 for (Locale locale : value.getLocales()) 1383 { 1384 node.setProperty(locale.toString(), value.getValue(locale)); 1385 } 1386 } 1387 catch (RepositoryException e) 1388 { 1389 throw new AmetysRepositoryException("Unable to set property", e); 1390 } 1391 } 1392 1393 public String[] getMetadataNames() throws AmetysRepositoryException 1394 { 1395 try 1396 { 1397 PropertyIterator itProp = _node.getProperties(METADATA_PREFIX + "*"); 1398 NodeIterator itNode = _node.getNodes(METADATA_PREFIX + "*"); 1399 1400 Set<String> names = new HashSet<>(); 1401 1402 while (itProp.hasNext()) 1403 { 1404 Property property = itProp.nextProperty(); 1405 names.add(property.getName().substring(METADATA_PREFIX.length())); 1406 } 1407 1408 while (itNode.hasNext()) 1409 { 1410 Node node = itNode.nextNode(); 1411 1412 // Filtering out AmetysObjects: they're not metadata (except object collections and users). 1413 if (!NodeTypeHelper.isNodeType(node, AmetysObjectResolver.OBJECT_TYPE) || NodeTypeHelper.isNodeType(node, OBJECT_COLLECTION_METADATA_NODETYPE) || NodeTypeHelper.isNodeType(node, RepositoryConstants.USER_NODETYPE) || NodeTypeHelper.isNodeType(node, MULTILINGUAL_STRING_METADATA_NODETYPE)) 1414 { 1415 names.add(node.getName().substring(METADATA_PREFIX.length())); 1416 } 1417 } 1418 1419 String[] result = new String[names.size()]; 1420 names.toArray(result); 1421 1422 return result; 1423 } 1424 catch (RepositoryException e) 1425 { 1426 throw new AmetysRepositoryException("Unable to get metadata names", e); 1427 } 1428 } 1429 1430 public boolean isMultiple(String metadataName) throws AmetysRepositoryException 1431 { 1432 try 1433 { 1434 String realMetadataName = METADATA_PREFIX + metadataName; 1435 1436 if (_node.hasProperty(realMetadataName)) 1437 { 1438 Property property = _node.getProperty(realMetadataName); 1439 1440 if (property.getDefinition().isMultiple()) 1441 { 1442 return true; 1443 } 1444 1445 return false; 1446 } 1447 1448 if (_node.hasNode(realMetadataName)) 1449 { 1450 String nodeType = NodeTypeHelper.getNodeTypeName(_node.getNode(realMetadataName)); 1451 1452 // Object collection is multi-valued. 1453 if (OBJECT_COLLECTION_METADATA_NODETYPE.equals(nodeType)) 1454 { 1455 return true; 1456 } 1457 1458 // User metadata 1459 if (nodeType.equals(METADATA_PREFIX + "user")) 1460 { 1461 return _node.getNodes(realMetadataName).getSize() > 1; 1462 } 1463 1464 // All other complex metadata are single valued. 1465 return false; 1466 } 1467 1468 throw new UnknownMetadataException("No metadata for name: " + metadataName); 1469 } 1470 catch (RepositoryException e) 1471 { 1472 throw new AmetysRepositoryException("Unable to determine if metadata " + metadataName + " is multiple", e); 1473 } 1474 } 1475 1476 /** 1477 * Check if the metadata name is valid. 1478 * @param metadataName The metadata name to check. 1479 * @throws AmetysRepositoryException If the metadata name is invalid. 1480 */ 1481 protected void _checkMetadataName(String metadataName) throws AmetysRepositoryException 1482 { 1483 // Id null 1484 if (metadataName == null) 1485 { 1486 throw new AmetysRepositoryException("Invalid metadata name (null)"); 1487 } 1488 1489 // Id valide 1490 if (!_getMetadataNamePattern().matcher(metadataName).matches()) 1491 { 1492 throw new AmetysRepositoryException("Invalid metadata name '" + metadataName + "'. This value is not permitted: only [a-zA-Z][a-zA-Z0-9-_]* are allowed."); 1493 } 1494 } 1495 1496 /** 1497 * Get the metadata name pattern to test validity. 1498 * @return The metadata name pattern. 1499 */ 1500 protected static Pattern _getMetadataNamePattern() 1501 { 1502 if (__metadataNamePattern == null) 1503 { 1504 // [a-zA-Z][a-zA-Z0-9_]* 1505 __metadataNamePattern = Pattern.compile("[a-z][a-z0-9-_]*", Pattern.CASE_INSENSITIVE); 1506 } 1507 1508 return __metadataNamePattern; 1509 } 1510 1511 public ModifiableBinaryMetadata getBinaryMetadata(String metadataName) throws AmetysRepositoryException 1512 { 1513 return getBinaryMetadata(metadataName, false); 1514 } 1515 1516 public ModifiableBinaryMetadata getBinaryMetadata(String metadataName, boolean createNew) throws AmetysRepositoryException 1517 { 1518 try 1519 { 1520 if (_node.hasNode(METADATA_PREFIX + metadataName)) 1521 { 1522 Node node = _node.getNode(METADATA_PREFIX + metadataName); 1523 return new JCRBinaryMetadata(node); 1524 } 1525 else if (createNew) 1526 { 1527 _checkLock(); 1528 Node node = _node.addNode(METADATA_PREFIX + metadataName, METADATA_PREFIX + "binaryMetadata"); 1529 return new JCRBinaryMetadata(node); 1530 } 1531 else 1532 { 1533 throw new UnknownMetadataException("No BinaryMetadata named " + metadataName); 1534 } 1535 } 1536 catch (RepositoryException e) 1537 { 1538 throw new AmetysRepositoryException(e); 1539 } 1540 } 1541 1542 public ModifiableCompositeMetadata getCompositeMetadata(String metadataName) throws AmetysRepositoryException 1543 { 1544 return getCompositeMetadata(metadataName, false); 1545 } 1546 1547 public ModifiableCompositeMetadata getCompositeMetadata(String metadataName, boolean createNew) throws AmetysRepositoryException 1548 { 1549 try 1550 { 1551 if (_node.hasNode(METADATA_PREFIX + metadataName)) 1552 { 1553 Node node = _node.getNode(METADATA_PREFIX + metadataName); 1554 return new JCRCompositeMetadata(node, _resolver); 1555 } 1556 else if (createNew) 1557 { 1558 _checkLock(); 1559 Node node = _node.addNode(METADATA_PREFIX + metadataName, "ametys:compositeMetadata"); 1560 return new JCRCompositeMetadata(node, _resolver); 1561 } 1562 else 1563 { 1564 throw new UnknownMetadataException("No CompositeMetadata named " + metadataName); 1565 } 1566 } 1567 catch (RepositoryException e) 1568 { 1569 throw new AmetysRepositoryException(e); 1570 } 1571 } 1572 1573 public ModifiableRichText getRichText(String metadataName) throws UnknownMetadataException, AmetysRepositoryException 1574 { 1575 return getRichText(metadataName, false); 1576 } 1577 1578 public ModifiableRichText getRichText(String metadataName, boolean createNew) throws UnknownMetadataException, AmetysRepositoryException 1579 { 1580 try 1581 { 1582 if (_node.hasNode(METADATA_PREFIX + metadataName)) 1583 { 1584 Node node = _node.getNode(METADATA_PREFIX + metadataName); 1585 return new JCRRichText(node, _resolver); 1586 } 1587 else if (createNew) 1588 { 1589 _checkLock(); 1590 Node node = _node.addNode(METADATA_PREFIX + metadataName, METADATA_PREFIX + "richText"); 1591 return new JCRRichText(node, _resolver); 1592 } 1593 else 1594 { 1595 throw new UnknownMetadataException("No RichText named " + metadataName); 1596 } 1597 } 1598 catch (RepositoryException e) 1599 { 1600 throw new AmetysRepositoryException(e); 1601 } 1602 } 1603 1604 public ModifiableTraversableAmetysObject getObjectCollection(String metadataName) throws AmetysRepositoryException 1605 { 1606 return getObjectCollection(metadataName, false); 1607 } 1608 1609 public ModifiableTraversableAmetysObject getObjectCollection(String metadataName, boolean createNew) throws AmetysRepositoryException 1610 { 1611 try 1612 { 1613 if (_node.hasNode(METADATA_PREFIX + metadataName)) 1614 { 1615 Node node = _node.getNode(METADATA_PREFIX + metadataName); 1616 return _resolver.resolve(node, false); 1617 } 1618 else if (createNew) 1619 { 1620 _checkLock(); 1621 Node node = _node.addNode(METADATA_PREFIX + metadataName, OBJECT_COLLECTION_METADATA_NODETYPE); 1622 return _resolver.resolve(node, false); 1623 } 1624 else 1625 { 1626 throw new UnknownMetadataException("No object collection metadata named " + metadataName); 1627 } 1628 } 1629 catch (RepositoryException e) 1630 { 1631 throw new AmetysRepositoryException(e); 1632 } 1633 } 1634 1635 @Override 1636 public List<MetadataComment> getComments(String metadataName) 1637 { 1638 List<MetadataComment> comments = new ArrayList<>(); 1639 String commentsNodeName = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + metadataName + METADATA_COMMENTS_SUFFIX; 1640 1641 try 1642 { 1643 if (_node.hasNode(commentsNodeName)) 1644 { 1645 Node commentsNode = _node.getNode(commentsNodeName); 1646 NodeIterator iterator = commentsNode.getNodes(); 1647 1648 while (iterator.hasNext()) 1649 { 1650 Node node = iterator.nextNode(); 1651 1652 String text = node.getProperty(METADATA_PREFIX + "comment").getString(); 1653 Date date = node.getProperty(METADATA_PREFIX + "date").getDate().getTime(); 1654 String author = node.getProperty(METADATA_PREFIX + "author").getString(); 1655 1656 comments.add(new MetadataComment(text, date, author)); 1657 } 1658 } 1659 1660 return comments; 1661 } 1662 catch (RepositoryException e) 1663 { 1664 throw new AmetysRepositoryException("Unable to retrieves the comments for metadata : " + metadataName, e); 1665 } 1666 } 1667 1668 @Override 1669 public boolean hasComments(String metadataName) 1670 { 1671 String commentsNodeName = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + metadataName + METADATA_COMMENTS_SUFFIX; 1672 1673 try 1674 { 1675 if (_node.hasNode(commentsNodeName)) 1676 { 1677 Node commentsNode = _node.getNode(commentsNodeName); 1678 return commentsNode.getNodes().hasNext(); 1679 } 1680 1681 return false; 1682 } 1683 catch (RepositoryException e) 1684 { 1685 throw new AmetysRepositoryException("Unable to determine if this node has at least one comment for metadata : " + metadataName, e); 1686 } 1687 } 1688 1689 @Override 1690 public boolean hasComment(String metadataName, int index) 1691 { 1692 String name = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + metadataName + METADATA_COMMENTS_SUFFIX + '/' + RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + index; 1693 try 1694 { 1695 return _node.hasNode(name); 1696 } 1697 catch (RepositoryException e) 1698 { 1699 throw new AmetysRepositoryException("Unable to determine if this node has a comment for metadata : " + metadataName, e); 1700 } 1701 } 1702 1703 @Override 1704 public void addComment(String metadataName, String text, String author, Date date) 1705 { 1706 if (text == null) 1707 { 1708 throw new NullPointerException("text of the comment cannot be null"); 1709 } 1710 1711 String commentsNodeName = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + metadataName + METADATA_COMMENTS_SUFFIX; 1712 1713 try 1714 { 1715 _checkLock(); 1716 if (!_node.hasNode(commentsNodeName)) 1717 { 1718 _node.addNode(commentsNodeName, "ametys:compositeMetadata"); 1719 } 1720 1721 Node commentsNode = _node.getNode(commentsNodeName); 1722 String nodeName = null; 1723 int i = 0; 1724 1725 // Loop over existing comments 1726 do 1727 { 1728 nodeName = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + ++i; 1729 } while (commentsNode.hasNode(nodeName)); 1730 1731 // Add the new comment node at the end 1732 Node commentNode = commentsNode.addNode(nodeName, "ametys:compositeMetadata"); 1733 1734 GregorianCalendar calendar = new GregorianCalendar(); 1735 if (date != null) 1736 { 1737 calendar.setTime(date); 1738 } 1739 1740 commentNode.setProperty(METADATA_PREFIX + "comment", text); 1741 commentNode.setProperty(METADATA_PREFIX + "date", calendar); 1742 commentNode.setProperty(METADATA_PREFIX + "author", author); 1743 } 1744 catch (RepositoryException e) 1745 { 1746 throw new AmetysRepositoryException("Unable to add a comment for metadata : " + metadataName, e); 1747 } 1748 } 1749 1750 @Override 1751 public void editComment(String metadataName, int index, String text, String author, Date date) 1752 { 1753 if (text == null) 1754 { 1755 throw new NullPointerException("text of the comment cannot be null"); 1756 } 1757 1758 String commentNodeName = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + metadataName + METADATA_COMMENTS_SUFFIX + '/' + RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + index; 1759 1760 try 1761 { 1762 _checkLock(); 1763 Node commentNode = _node.getNode(commentNodeName); 1764 1765 GregorianCalendar calendar = new GregorianCalendar(); 1766 if (date != null) 1767 { 1768 calendar.setTime(date); 1769 } 1770 1771 commentNode.setProperty(METADATA_PREFIX + "comment", text); 1772 commentNode.setProperty(METADATA_PREFIX + "date", calendar); 1773 commentNode.setProperty(METADATA_PREFIX + "author", author); 1774 } 1775 catch (RepositoryException e) 1776 { 1777 throw new AmetysRepositoryException("Unable to edit the comment at index +" + index + " for metadata : " + metadataName, e); 1778 } 1779 } 1780 1781 @Override 1782 public void deleteComment(String metadataName, int index) 1783 { 1784 String commentNodeName = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + metadataName + METADATA_COMMENTS_SUFFIX + '/' + RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + index; 1785 1786 try 1787 { 1788 _checkLock(); 1789 _node.getNode(commentNodeName).remove(); 1790 } 1791 catch (RepositoryException e) 1792 { 1793 throw new AmetysRepositoryException("Unable to remove the comment at index +" + index + " for metadata : " + metadataName, e); 1794 } 1795 } 1796 1797 private void _checkLock() throws RepositoryException 1798 { 1799 if (!_lockAlreadyChecked && _node.isLocked()) 1800 { 1801 LockManager lockManager = _node.getSession().getWorkspace().getLockManager(); 1802 1803 Lock lock = lockManager.getLock(_node.getPath()); 1804 Node lockHolder = lock.getNode(); 1805 1806 lockManager.addLockToken(lockHolder.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString()); 1807 _lockAlreadyChecked = true; 1808 } 1809 } 1810}