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