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.explorer.resources.jcr; 017 018import java.io.InputStream; 019import java.util.Calendar; 020import java.util.Date; 021import java.util.GregorianCalendar; 022import java.util.List; 023import java.util.Set; 024 025import javax.jcr.Binary; 026import javax.jcr.Node; 027import javax.jcr.NodeIterator; 028import javax.jcr.Property; 029import javax.jcr.RepositoryException; 030import javax.jcr.Value; 031import javax.jcr.version.VersionHistory; 032 033import org.apache.commons.lang3.StringUtils; 034import org.apache.jackrabbit.JcrConstants; 035 036import org.ametys.core.user.UserIdentity; 037import org.ametys.plugins.explorer.ExplorerNode; 038import org.ametys.plugins.explorer.resources.ModifiableResource; 039import org.ametys.plugins.explorer.resources.Resource; 040import org.ametys.plugins.explorer.resources.ResourceHelper; 041import org.ametys.plugins.repository.AmetysObject; 042import org.ametys.plugins.repository.AmetysRepositoryException; 043import org.ametys.plugins.repository.CopiableAmetysObject; 044import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 045import org.ametys.plugins.repository.RepositoryConstants; 046import org.ametys.plugins.repository.dublincore.DCMITypes; 047import org.ametys.plugins.repository.jcr.DefaultLockableAmetysObject; 048import org.ametys.plugins.repository.jcr.DublinCoreHelper; 049import org.ametys.plugins.repository.jcr.NodeHelper; 050import org.ametys.plugins.repository.jcr.NodeTypeHelper; 051import org.ametys.plugins.repository.tag.TaggableAmetysObjectHelper; 052import org.ametys.plugins.repository.trash.ConflictingNameException; 053import org.ametys.plugins.repository.trash.TrashElement; 054import org.ametys.plugins.repository.trash.TrashableAmetysObject; 055import org.ametys.plugins.repository.trash.UnknownParentException; 056 057/** 058 * Default implementation of an {@link Resource}, backed by a JCR node.<br> 059 * @param <F> the actual type of factory. 060 */ 061public class JCRResource<F extends JCRResourceFactory> extends DefaultLockableAmetysObject<F> implements ModifiableResource, CopiableAmetysObject, TrashableAmetysObject 062{ 063 /** The name of node holding the creator */ 064 public static final String CREATOR_NODE_NAME = "creator"; 065 /** Constants for lastModified Metadata */ 066 public static final String CREATION_DATE = "creationDate"; 067 /** The name of node holding the last contributor */ 068 public static final String CONTRIBUTOR_NODE_NAME = "contributor"; 069 070 /** 071 * Creates an {@link JCRResource}. 072 * @param node the node backing this {@link AmetysObject} 073 * @param parentPath the parentPath in the Ametys hierarchy 074 * @param factory the DefaultAmetysObjectFactory which created the AmetysObject 075 */ 076 public JCRResource(Node node, String parentPath, F factory) 077 { 078 super(node, parentPath, factory); 079 } 080 081 @Override 082 public void setData(InputStream stream, String mimeType, Date lastModified, UserIdentity author) 083 { 084 Node fileNode = getNode(); 085 086 try 087 { 088 setLastContributor(author); 089 090 Node resourceNode = null; 091 092 if (fileNode.hasNode(JcrConstants.JCR_CONTENT)) 093 { 094 // Already exists 095 resourceNode = fileNode.getNode(JcrConstants.JCR_CONTENT); 096 } 097 else 098 { 099 resourceNode = fileNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE); 100 setCreator(author); 101 setCreationDate(new Date()); 102 } 103 104 GregorianCalendar gc = new GregorianCalendar(); 105 gc.setTime(lastModified); 106 resourceNode.setProperty(JcrConstants.JCR_LASTMODIFIED, gc); 107 108 resourceNode.setProperty(JcrConstants.JCR_MIMETYPE, mimeType); 109 110 Binary binary = resourceNode.getSession().getValueFactory().createBinary(stream); 111 resourceNode.setProperty(JcrConstants.JCR_DATA, binary); 112 } 113 catch (RepositoryException e) 114 { 115 throw new AmetysRepositoryException("Cannot set data for resource " + this.getName() + " (" + this.getId() + ")", e); 116 } 117 } 118 119 @Override 120 public void setLastModified(Date lastModified) 121 { 122 Node fileNode = getNode(); 123 124 try 125 { 126 Node resourceNode = fileNode.getNode(JcrConstants.JCR_CONTENT); 127 128 GregorianCalendar gc = new GregorianCalendar(); 129 gc.setTime(lastModified); 130 resourceNode.setProperty(JcrConstants.JCR_LASTMODIFIED, gc); 131 } 132 catch (RepositoryException e) 133 { 134 throw new AmetysRepositoryException("Cannot set lastmodified for resource " + this.getName() + " (" + this.getId() + ")", e); 135 } 136 } 137 138 @Override 139 public void setKeywords(String keywords) 140 { 141 String[] words = StringUtils.stripAll(StringUtils.split(keywords, ',')); 142 143 String[] trimWords = new String[words.length]; 144 for (int i = 0; i < words.length; i++) 145 { 146 trimWords[i] = words[i].trim(); 147 } 148 149 Node fileNode = getNode(); 150 try 151 { 152 fileNode.setProperty("ametys:keywords", trimWords); 153 } 154 catch (RepositoryException e) 155 { 156 throw new AmetysRepositoryException("Cannot set keywords for resource " + this.getName() + " (" + this.getId() + ")", e); 157 } 158 } 159 160 @Override 161 public void setKeywords(String[] keywords) 162 { 163 Node fileNode = getNode(); 164 try 165 { 166 fileNode.setProperty("ametys:keywords", keywords); 167 } 168 catch (RepositoryException e) 169 { 170 throw new AmetysRepositoryException("Cannot set keywords for resource " + this.getName() + " (" + this.getId() + ")", e); 171 } 172 } 173 174 @Override 175 public void setMimeType(String mimeType) 176 { 177 Node fileNode = getNode(); 178 179 try 180 { 181 Node resourceNode = fileNode.getNode(JcrConstants.JCR_CONTENT); 182 183 resourceNode.setProperty(JcrConstants.JCR_MIMETYPE, mimeType); 184 } 185 catch (RepositoryException e) 186 { 187 throw new AmetysRepositoryException("Cannot set mimetype for resource " + this.getName() + " (" + this.getId() + ")", e); 188 } 189 } 190 191 @Override 192 public void setCreator(UserIdentity author) 193 { 194 try 195 { 196 Node authorNode = null; 197 if (getNode().hasNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATOR_NODE_NAME)) 198 { 199 authorNode = getNode().getNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATOR_NODE_NAME); 200 } 201 else 202 { 203 authorNode = getNode().addNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATOR_NODE_NAME, RepositoryConstants.USER_NODETYPE); 204 } 205 authorNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login", author.getLogin()); 206 authorNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population", author.getPopulationId()); 207 } 208 catch (RepositoryException e) 209 { 210 throw new AmetysRepositoryException("Cannot set creator for resource " + this.getName() + " (" + this.getId() + ")", e); 211 } 212 } 213 214 @Override 215 public InputStream getInputStream () throws AmetysRepositoryException 216 { 217 Node fileNode = getNode(); 218 try 219 { 220 Node resourceNode = null; 221 222 if (fileNode.hasNode(JcrConstants.JCR_CONTENT)) 223 { 224 // Already exists 225 resourceNode = fileNode.getNode(JcrConstants.JCR_CONTENT); 226 return resourceNode.getProperty(JcrConstants.JCR_DATA).getBinary().getStream(); 227 } 228 return null; 229 } 230 catch (RepositoryException e) 231 { 232 throw new AmetysRepositoryException("Cannot get inputstream for resource " + this.getName() + " (" + this.getId() + ")", e); 233 } 234 } 235 236 @Override 237 public String getMimeType () throws AmetysRepositoryException 238 { 239 Node fileNode = getNode(); 240 try 241 { 242 Node resourceNode = null; 243 244 if (fileNode.hasNode(JcrConstants.JCR_CONTENT)) 245 { 246 // Already exists 247 resourceNode = fileNode.getNode(JcrConstants.JCR_CONTENT); 248 return resourceNode.getProperty(JcrConstants.JCR_MIMETYPE).getString(); 249 } 250 251 return null; 252 } 253 catch (RepositoryException e) 254 { 255 throw new AmetysRepositoryException("Cannot get mimetype for resource " + this.getName() + " (" + this.getId() + ")", e); 256 } 257 } 258 259 @Override 260 public Date getLastModified () throws AmetysRepositoryException 261 { 262 Node fileNode = getNode(); 263 try 264 { 265 Node resourceNode = null; 266 267 if (fileNode.hasNode(JcrConstants.JCR_CONTENT)) 268 { 269 resourceNode = fileNode.getNode(JcrConstants.JCR_CONTENT); 270 return resourceNode.getProperty(JcrConstants.JCR_LASTMODIFIED).getDate().getTime(); 271 } 272 273 return null; 274 } 275 catch (RepositoryException e) 276 { 277 throw new AmetysRepositoryException("Cannot get lastmodified for resource " + this.getName() + " (" + this.getId() + ")", e); 278 } 279 } 280 281 @Override 282 public long getLength() throws AmetysRepositoryException 283 { 284 Node fileNode = getNode(); 285 try 286 { 287 Node resourceNode = null; 288 289 if (fileNode.hasNode(JcrConstants.JCR_CONTENT)) 290 { 291 resourceNode = fileNode.getNode(JcrConstants.JCR_CONTENT); 292 return resourceNode.getProperty(JcrConstants.JCR_DATA).getLength(); 293 } 294 295 return 0; 296 } 297 catch (RepositoryException e) 298 { 299 throw new AmetysRepositoryException("Cannot get length for resource " + this.getName() + " (" + this.getId() + ")", e); 300 } 301 } 302 303 @Override 304 public UserIdentity getCreator() throws AmetysRepositoryException 305 { 306 try 307 { 308 Node authorNode = getNode().getNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATOR_NODE_NAME); 309 return new UserIdentity(authorNode.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login").getString(), authorNode.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population").getString()); 310 } 311 catch (RepositoryException e) 312 { 313 throw new AmetysRepositoryException("Cannot get creator for resource " + this.getName() + " (" + this.getId() + ")", e); 314 } 315 } 316 317 /** 318 * Get the author from old revision 319 * @param revision The revision 320 * @return The user identity of the author or <code>null</code> if not found 321 * @throws RepositoryException If an error occurred 322 */ 323 public UserIdentity getAuthorFromRevision (String revision) throws RepositoryException 324 { 325 try 326 { 327 switchToRevision(revision); 328 329 VersionHistory history = getVersionHistory(); 330 Node versionNode = history.getVersion(revision); 331 Node frozenNode = versionNode.getNode(JcrConstants.JCR_FROZENNODE); 332 333 if (frozenNode.hasNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATOR_NODE_NAME)) 334 { 335 Node authorNode = frozenNode.getNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATOR_NODE_NAME); 336 return new UserIdentity(authorNode.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login").getString(), authorNode.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population").getString()); 337 } 338 return null; 339 } 340 catch (RepositoryException e) 341 { 342 throw new AmetysRepositoryException("Unable to get author from revision: " + revision + " of resource " + this.getName() + " (" + this.getId() + ")", e); 343 } 344 } 345 346 @Override 347 public String[] getKeywords() throws AmetysRepositoryException 348 { 349 Node fileNode = getNode(); 350 try 351 { 352 if (!fileNode.hasProperty("ametys:keywords")) 353 { 354 return new String[0]; 355 } 356 357 Value[] values = fileNode.getProperty("ametys:keywords").getValues(); 358 String[] result = new String[values.length]; 359 360 for (int i = 0; i < values.length; i++) 361 { 362 result[i] = values[i].getString(); 363 } 364 365 return result; 366 } 367 catch (RepositoryException e) 368 { 369 throw new AmetysRepositoryException("Cannot get keywords for resource " + this.getName() + " (" + this.getId() + ")", e); 370 } 371 } 372 373 @Override 374 public String getKeywordsAsString() throws AmetysRepositoryException 375 { 376 Node fileNode = getNode(); 377 try 378 { 379 if (!fileNode.hasProperty("ametys:keywords")) 380 { 381 return StringUtils.EMPTY; 382 } 383 384 StringBuilder sb = new StringBuilder(); 385 Value[] values = fileNode.getProperty("ametys:keywords").getValues(); 386 387 for (Value value : values) 388 { 389 if (sb.length() > 0) 390 { 391 sb.append(", "); 392 } 393 394 sb.append(value.getString()); 395 } 396 397 return sb.toString(); 398 } 399 catch (RepositoryException e) 400 { 401 throw new AmetysRepositoryException("Cannot get keywords for resource " + this.getName() + " (" + this.getId() + ")", e); 402 } 403 } 404 405 @Override 406 protected void restoreFromNode(Node node) throws RepositoryException 407 { 408 super.restoreFromNode(node); 409 410 // First remove node 411 NodeIterator nit = getBaseNode().getNodes(JcrConstants.JCR_CONTENT); 412 while (nit.hasNext()) 413 { 414 nit.nextNode().remove(); 415 } 416 417 NodeIterator new_nit = node.getNodes(JcrConstants.JCR_CONTENT); 418 while (new_nit.hasNext()) 419 { 420 copyNode(getBaseNode(), new_nit.nextNode()); 421 } 422 } 423 424 @Override 425 public String getResourcePath() throws AmetysRepositoryException 426 { 427 return ((ExplorerNode) getParent()).getExplorerPath() + "/" + getName(); 428 } 429 430 @Override 431 public AmetysObject copyTo(ModifiableTraversableAmetysObject parent, String name) throws AmetysRepositoryException 432 { 433 try 434 { 435 String nodeTypeName = NodeTypeHelper.getNodeTypeName(getNode()); 436 437 JCRResource copiedResource = parent.createChild(name, nodeTypeName); 438 439 copiedResource.setKeywords(getKeywords()); 440 copiedResource.setData(getInputStream(), getMimeType(), getLastModified(), getCreator()); 441 442 parent.saveChanges(); 443 444 return copiedResource; 445 } 446 catch (RepositoryException e) 447 { 448 throw new AmetysRepositoryException("Error copying the collection " + getId() + " into " + parent.getId(), e); 449 } 450 } 451 452 @Override 453 public AmetysObject copyTo(ModifiableTraversableAmetysObject parent, String name, List<String> restrictTo) throws AmetysRepositoryException 454 { 455 return copyTo(parent, name); 456 } 457 458 // Dublin Core metadata. // 459 460 @Override 461 public String getDCTitle() throws AmetysRepositoryException 462 { 463 return DublinCoreHelper.getDCTitle(this, getName()); 464 } 465 466 @Override 467 public void setDCTitle(String title) throws AmetysRepositoryException 468 { 469 DublinCoreHelper.setDCTitle(this, title); 470 } 471 472 @Override 473 public String getDCCreator() throws AmetysRepositoryException 474 { 475 return DublinCoreHelper.getDCCreator(this); 476 } 477 478 @Override 479 public void setDCCreator(String creator) throws AmetysRepositoryException 480 { 481 DublinCoreHelper.setDCCreator(this, creator); 482 } 483 484 @Override 485 public String[] getDCSubject() throws AmetysRepositoryException 486 { 487 return DublinCoreHelper.getDCSubject(this, getKeywords()); 488 } 489 490 @Override 491 public void setDCSubject(String[] subject) throws AmetysRepositoryException 492 { 493 DublinCoreHelper.setDCSubject(this, subject); 494 } 495 496 @Override 497 public String getDCDescription() throws AmetysRepositoryException 498 { 499 return DublinCoreHelper.getDCDescription(this); 500 } 501 502 @Override 503 public void setDCDescription(String description) throws AmetysRepositoryException 504 { 505 DublinCoreHelper.setDCDescription(this, description); 506 } 507 508 @Override 509 public String getDCPublisher() throws AmetysRepositoryException 510 { 511 return DublinCoreHelper.getDCPublisher(this); 512 } 513 514 @Override 515 public void setDCPublisher(String publisher) throws AmetysRepositoryException 516 { 517 DublinCoreHelper.setDCPublisher(this, publisher); 518 } 519 520 @Override 521 public String getDCContributor() throws AmetysRepositoryException 522 { 523 return DublinCoreHelper.getDCContributor(this, UserIdentity.userIdentityToString(getCreator())); 524 } 525 526 @Override 527 public void setDCContributor(String contributor) throws AmetysRepositoryException 528 { 529 DublinCoreHelper.setDCContributor(this, contributor); 530 } 531 532 @Override 533 public Date getDCDate() throws AmetysRepositoryException 534 { 535 return DublinCoreHelper.getDCDate(this, getLastModified()); 536 } 537 538 @Override 539 public void setDCDate(Date date) throws AmetysRepositoryException 540 { 541 DublinCoreHelper.setDCDate(this, date); 542 } 543 544 @Override 545 public String getDCType() throws AmetysRepositoryException 546 { 547 return DublinCoreHelper.getDCType(this, _getDefaultDCType()); 548 } 549 550 private String _getDefaultDCType () 551 { 552 String mimetype = getMimeType(); 553 554 if (mimetype == null) 555 { 556 return DCMITypes.TEXT; 557 } 558 else if (mimetype.startsWith("image")) 559 { 560 return DCMITypes.IMAGE; 561 } 562 else if (mimetype.startsWith("video") || "application/x-shockwave-flash".equals(mimetype)) 563 { 564 return DCMITypes.INTERACTIVERESOURCE; 565 } 566 else if (mimetype.startsWith("audio")) 567 { 568 return DCMITypes.SOUND; 569 } 570 571 return DCMITypes.TEXT; 572 } 573 574 575 @Override 576 public void setDCType(String type) throws AmetysRepositoryException 577 { 578 DublinCoreHelper.setDCType(this, type); 579 } 580 581 @Override 582 public String getDCFormat() throws AmetysRepositoryException 583 { 584 return DublinCoreHelper.getDCFormat(this, getMimeType()); 585 } 586 587 @Override 588 public void setDCFormat(String format) throws AmetysRepositoryException 589 { 590 DublinCoreHelper.setDCFormat(this, format); 591 } 592 593 @Override 594 public String getDCIdentifier() throws AmetysRepositoryException 595 { 596 return DublinCoreHelper.getDCIdentifier(this, getId()); 597 } 598 599 @Override 600 public void setDCIdentifier(String identifier) throws AmetysRepositoryException 601 { 602 DublinCoreHelper.setDCIdentifier(this, identifier); 603 } 604 605 @Override 606 public String getDCSource() throws AmetysRepositoryException 607 { 608 return DublinCoreHelper.getDCSource(this); 609 } 610 611 @Override 612 public void setDCSource(String source) throws AmetysRepositoryException 613 { 614 DublinCoreHelper.setDCSource(this, source); 615 } 616 617 @Override 618 public String getDCLanguage() throws AmetysRepositoryException 619 { 620 return DublinCoreHelper.getDCLanguage(this); 621 } 622 623 @Override 624 public void setDCLanguage(String language) throws AmetysRepositoryException 625 { 626 DublinCoreHelper.setDCLanguage(this, language); 627 } 628 629 @Override 630 public String getDCRelation() throws AmetysRepositoryException 631 { 632 return DublinCoreHelper.getDCRelation(this); 633 } 634 635 @Override 636 public void setDCRelation(String relation) throws AmetysRepositoryException 637 { 638 DublinCoreHelper.setDCRelation(this, relation); 639 } 640 641 @Override 642 public String getDCCoverage() throws AmetysRepositoryException 643 { 644 return DublinCoreHelper.getDCCoverage(this, getDCLanguage()); 645 } 646 647 @Override 648 public void setDCCoverage(String coverage) throws AmetysRepositoryException 649 { 650 DublinCoreHelper.setDCCoverage(this, coverage); 651 } 652 653 @Override 654 public String getDCRights() throws AmetysRepositoryException 655 { 656 return DublinCoreHelper.getDCRights(this); 657 } 658 659 @Override 660 public void setDCRights(String rights) throws AmetysRepositoryException 661 { 662 DublinCoreHelper.setDCRights(this, rights); 663 } 664 665 public Date getCreationDate() throws AmetysRepositoryException 666 { 667 Node fileNode = getNode(); 668 try 669 { 670 if (!fileNode.hasProperty(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATION_DATE)) 671 { 672 return null; 673 } 674 675 return fileNode.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATION_DATE).getDate().getTime(); 676 } 677 catch (RepositoryException e) 678 { 679 throw new AmetysRepositoryException("Cannot get creation date for resource " + this.getName() + " (" + this.getId() + ")", e); 680 } 681 } 682 683 public void setCreationDate(Date creationDate) 684 { 685 Node fileNode = getNode(); 686 try 687 { 688 Calendar calendar = new GregorianCalendar(); 689 calendar.setTime(creationDate); 690 fileNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":" + CREATION_DATE, calendar); 691 } 692 catch (RepositoryException e) 693 { 694 throw new AmetysRepositoryException("Cannot set create date for resource " + this.getName() + " (" + this.getId() + ")", e); 695 } 696 } 697 698 public UserIdentity getLastContributor() throws AmetysRepositoryException 699 { 700 try 701 { 702 Node authorNode = getNode().getNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CONTRIBUTOR_NODE_NAME); 703 return new UserIdentity(authorNode.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login").getString(), authorNode.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population").getString()); 704 } 705 catch (RepositoryException e) 706 { 707 throw new AmetysRepositoryException("Cannot get last contributor for resource " + this.getName() + " (" + this.getId() + ")", e); 708 } 709 } 710 711 public void setLastContributor(UserIdentity lastContributor) 712 { 713 try 714 { 715 Node lastContributorNode = null; 716 if (getNode().hasNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CONTRIBUTOR_NODE_NAME)) 717 { 718 lastContributorNode = getNode().getNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CONTRIBUTOR_NODE_NAME); 719 } 720 else 721 { 722 lastContributorNode = getNode().addNode(RepositoryConstants.NAMESPACE_PREFIX + ":" + CONTRIBUTOR_NODE_NAME, RepositoryConstants.USER_NODETYPE); 723 } 724 lastContributorNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login", lastContributor.getLogin()); 725 lastContributorNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population", lastContributor.getPopulationId()); 726 } 727 catch (RepositoryException e) 728 { 729 throw new AmetysRepositoryException("Cannot set last contributor for resource " + this.getName() + " (" + this.getId() + ")", e); 730 } 731 } 732 733 public void tag(String tag) throws AmetysRepositoryException 734 { 735 TaggableAmetysObjectHelper.tag(this, tag); 736 } 737 738 public void untag(String tag) throws AmetysRepositoryException 739 { 740 TaggableAmetysObjectHelper.untag(this, tag); 741 } 742 743 public Set<String> getTags() throws AmetysRepositoryException 744 { 745 return TaggableAmetysObjectHelper.getTags(this); 746 } 747 748 public TrashElement moveToTrash() 749 { 750 TrashElement trashElement = _getFactory()._getTrashElementDAO().createTrashElement(this, getName()); 751 752 // Clone the ametys object from the original session to trash session 753 Node storedNode = NodeHelper.cloneNode(getNode(), trashElement.getNode()); 754 755 try 756 { 757 storedNode.setProperty("ametys-internal:path", this.getParentPath()); 758 } 759 catch (RepositoryException e) 760 { 761 throw new AmetysRepositoryException("failed to store the content path", e); 762 } 763 764 // Remove the node from the original session 765 remove(); 766 767 return trashElement; 768 } 769 770 public JCRResource restoreFromTrash(MergeComputationMode mergeComputationMode) throws UnknownParentException, ConflictingNameException 771 { 772 try 773 { 774 Property property = getNode().getProperty("ametys-internal:path"); 775 String parentPath = property.getValue().getString(); 776 property.remove(); 777 JCRResourcesCollection parent = ResourceHelper.getOrCreateResourcesCollection(_getFactory()._getResolver(), parentPath); 778 if (parent == null) 779 { 780 throw new UnknownParentException("No parent available at path " + parentPath); 781 } 782 783 JCRResource restoredResource = ResourceHelper.restoreResource(this, parent, mergeComputationMode, _getFactory()._getResourcesDAO()); 784 785 // Remove the node from the trash session 786 remove(); 787 788 restoredResource.saveChanges(); 789 return restoredResource; 790 } 791 catch (RepositoryException e) 792 { 793 throw new AmetysRepositoryException("Failed to restore JCRResource with id '" + getId() + "'", e); 794 } 795 } 796}