@Override public void afterCommit() { Set<String> deletedUserIds = TransactionalResourceHelper.getSet(KEY_DELETED_USER_IDS); if (deletedUserIds != null) { for (String user : deletedUserIds) { // MNT-9104 If username contains uppercase letters the action of joining a site will not // be displayed in "My activities" final String userId; if (!userNamesAreCaseSensitive) { userId = user.toLowerCase(); } else { userId = user; } transactionService .getRetryingTransactionHelper() .doInTransaction( new RetryingTransactionHelper.RetryingTransactionCallback<Void>() { public Void execute() throws Throwable { try { // Since we are in post-commit, we do best-effort feedDAO.deleteUserFeedEntries(userId); } catch (SQLException e) { logger.error( "Activities feed cleanup for user '" + userId + "' failed: ", e); } return null; } }, false, true); } } }
@Override public void afterCommit() { Set<String> deletedSiteIds = TransactionalResourceHelper.getSet(KEY_DELETED_SITE_IDS); if (deletedSiteIds != null) { for (final String siteId : deletedSiteIds) { transactionService .getRetryingTransactionHelper() .doInTransaction( new RetryingTransactionHelper.RetryingTransactionCallback<Void>() { public Void execute() throws Throwable { try { // Since we are in post-commit, we do best-effort int deletedCnt = feedDAO.deleteSiteFeedEntries(tenantService.getName(siteId)); if (logger.isDebugEnabled()) { logger.debug( "afterCommit: deleted " + deletedCnt + " site feed entries for site '" + siteId + "'"); } } catch (SQLException e) { logger.error( "Activities feed cleanup for site '" + siteId + "' failed: ", e); } return null; } }, false, true); } } }
/** * Helper method to transactionally record <code>NodeRef</code> properties so that they can later * be fixed up to point to the relative, after-copy locations. * * <p>When the copy has been completed, the second stage of the process can be applied. * * @param sourceNodeRef the node that is being copied * @param properties the node properties being copied * @param propertyQName the qualified name of the property to check * @see #repointNodeRefs(NodeRef, QName, Map, NodeService) */ public void recordNodeRefsForRepointing( NodeRef sourceNodeRef, Map<QName, Serializable> properties, QName propertyQName) { Serializable parameterValue = properties.get(propertyQName); if (parameterValue != null && (parameterValue instanceof Collection<?> || parameterValue instanceof NodeRef)) { String key = KEY_NODEREF_REPOINTING_PREFIX + propertyQName.toString(); // Store it for later Map<NodeRef, Serializable> map = TransactionalResourceHelper.getMap(key); map.put(sourceNodeRef, parameterValue); } }
/** Copy the aspect over only if the source document has also been checked out */ @Override public boolean getMustCopy(QName classQName, CopyDetails copyDetails) { if (copyDetails.getSourceNodeAspectQNames().contains(ContentModel.ASPECT_WORKING_COPY) && !copyDetails.isTargetNodeIsNew()) { // We are copying back from a working copy to the original node (probably) // We need to do a full merge of the discussions. Keep track of the nodes // that need this behaviour and complete the copy after the copy completes. Set<NodeRef> nodeRefs = TransactionalResourceHelper.getSet(KEY_WORKING_COPIES); nodeRefs.add(copyDetails.getSourceNodeRef()); } return false; }
/** * The second stage of the <code>NodeRef</code> repointing. Call this method to have any <code> * NodeRef</code> properties readjusted to reflect the copied node hierarchy. Only use this method * if it a requirement for the particular type or aspect that you are coding for. * * @param sourceNodeRef the source node * @param propertyQName the target node i.e. the copy of the source node * @param copyMap the full hierarchy copy map of source to copies * @see #recordNodeRefsForRepointing(NodeRef, Map, QName) */ @SuppressWarnings("unchecked") public void repointNodeRefs( NodeRef sourceNodeRef, NodeRef targetNodeRef, QName propertyQName, Map<NodeRef, NodeRef> copyMap, NodeService nodeService) { String key = KEY_NODEREF_REPOINTING_PREFIX + propertyQName.toString(); Map<NodeRef, Serializable> map = TransactionalResourceHelper.getMap(key); Serializable value = map.get(sourceNodeRef); if (value == null) { // Don't bother. The source node did not have a NodeRef property return; } Serializable newValue = null; if (value instanceof Collection) { Collection<Serializable> oldList = (Collection<Serializable>) value; List<Serializable> newList = new ArrayList<Serializable>(oldList.size()); for (Serializable oldListValue : oldList) { Serializable newListValue = oldListValue; if (oldListValue instanceof NodeRef) { newListValue = repointNodeRef(copyMap, (NodeRef) oldListValue); } // Put the value in the new list even though the new list might be discarded newList.add(newListValue); // Check if the value changed if (!newListValue.equals(oldListValue)) { // The value changed, so the new list will have to be set onto the target node newValue = (Serializable) newList; } } } else if (value instanceof NodeRef) { NodeRef newNodeRef = repointNodeRef(copyMap, (NodeRef) value); if (!newNodeRef.equals(value)) { // The value changed, so the new list will have to be set onto the target node newValue = newNodeRef; } } else { throw new IllegalStateException("Should only have Collections and NodeRef values"); } // Fix the node property on the target, if necessary if (newValue != null) { nodeService.setProperty(targetNodeRef, propertyQName, newValue); } }
public void onCopyComplete( QName classRef, NodeRef sourceNodeRef, NodeRef targetNodeRef, boolean copyToNewNode, Map<NodeRef, NodeRef> copyMap) { Set<NodeRef> workingCopyNodeRefs = TransactionalResourceHelper.getSet(KEY_WORKING_COPIES); if (!workingCopyNodeRefs.contains(sourceNodeRef)) { // This is not one of the nodes that needs to have discussions copied over return; } // First check that the source node has forums NodeRef sourceForumNodeRef = getForum(sourceNodeRef); if (sourceForumNodeRef == null) { // Missing! Clean the source node up! nodeService.removeAspect(sourceNodeRef, ForumModel.ASPECT_DISCUSSABLE); return; } // The aspect may or may not exist on the target node if (!nodeService.hasAspect(targetNodeRef, ForumModel.ASPECT_DISCUSSABLE)) { // Add the aspect nodeService.addAspect(targetNodeRef, ForumModel.ASPECT_DISCUSSABLE, null); } // Get the forum node NodeRef targetForumNodeRef = getForum(targetNodeRef); // Merge the forum topics List<ChildAssociationRef> topicAssocRefs = nodeService.getChildAssocs( sourceForumNodeRef, Collections.singleton(ForumModel.TYPE_TOPIC)); int copied = 0; for (ChildAssociationRef topicAssocRef : topicAssocRefs) { NodeRef topicNodeRef = topicAssocRef.getChildRef(); try { // work out the name for the copied topic String topicName; String topicNodeName = nodeService.getProperty(topicNodeRef, ContentModel.PROP_NAME).toString(); Serializable labelProp = nodeService.getProperty(targetNodeRef, ContentModel.PROP_VERSION_LABEL); if (labelProp == null) { SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss"); topicName = topicNodeName + " - " + dateFormat.format(new Date()); } else { topicName = topicNodeName + " (" + labelProp.toString() + ")"; } if (fileFolderService.searchSimple(targetForumNodeRef, topicName) != null) { // A topic with that name already exists continue; } fileFolderService.copy(topicNodeRef, targetForumNodeRef, topicName); copied++; } catch (FileExistsException e) { // We checked for this, so this is a concurrency condition throw new ConcurrencyFailureException("Target topic exists: " + e.getMessage(), e); } catch (FileNotFoundException e) { // The node was there, but now it's gone throw new ConcurrencyFailureException("Forum was deleted: " + e.getMessage(), e); } } }