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