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