1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.commands.impl;
35
36 import info.magnolia.cms.beans.config.VersionConfig;
37 import info.magnolia.cms.core.version.VersionManager;
38 import info.magnolia.cms.exchange.ActivationManagerFactory;
39 import info.magnolia.cms.exchange.Subscriber;
40 import info.magnolia.cms.security.AccessDeniedException;
41 import info.magnolia.cms.security.Permission;
42 import info.magnolia.cms.security.PermissionUtil;
43 import info.magnolia.cms.security.User;
44 import info.magnolia.cms.util.Rule;
45 import info.magnolia.context.Context;
46 import info.magnolia.context.MgnlContext;
47 import info.magnolia.jcr.iterator.FilteringNodeIterator;
48 import info.magnolia.jcr.iterator.FilteringPropertyIterator;
49 import info.magnolia.jcr.predicate.JCRMgnlPropertyHidingPredicate;
50 import info.magnolia.jcr.predicate.RuleBasedNodePredicate;
51 import info.magnolia.jcr.util.NodeTypes;
52 import info.magnolia.objectfactory.Components;
53
54 import java.util.Iterator;
55
56 import javax.jcr.Node;
57 import javax.jcr.Property;
58 import javax.jcr.RepositoryException;
59 import javax.jcr.lock.Lock;
60 import javax.jcr.lock.LockManager;
61
62 import org.apache.commons.lang3.StringUtils;
63
64
65
66
67
68
69
70
71
72
73 public class MarkNodeAsDeletedCommand extends RuleBasedCommand {
74
75 public static final String DELETED_NODE_TEMPLATE = "ui-admincentral:deleted";
76 public static final String DELETED_NODE_PROP_NAME = "deleteNode";
77 public static final int HOLD_LOCK_IN_SECONDS = 30;
78
79 private boolean versionManually = true;
80
81 private boolean forcePreDelete;
82
83 private VersionManager versionManager;
84
85 @Override
86 public boolean execute(Context context) throws Exception {
87 versionManager = Components.getComponent(VersionManager.class);
88
89 final Node parentNode = getJCRNode(context);
90 final Node node = parentNode.getNode((String) context.get(DELETED_NODE_PROP_NAME));
91 final LockManager manager = node.getSession().getWorkspace().getLockManager();
92
93
94 User currentUser = MgnlContext.getUser();
95 if (currentUser == null) {
96 throw new AccessDeniedException(String.format("Current user in context %s was null, denying execution of command %s", context, this));
97 } else if (!PermissionUtil.isGranted(node, Permission.WRITE)) {
98 throw new AccessDeniedException(String.format("%s: not allowed to delete item", node.getPath()));
99 }
100
101 boolean hasActiveSubscriber = false;
102 for (Subscriber subscriber : ActivationManagerFactory.getActivationManager().getSubscribers()) {
103 if (subscriber.isActive()) {
104 hasActiveSubscriber = true;
105 break;
106 }
107 }
108
109 if (hasActiveSubscriber || isForcePreDelete()) {
110 try {
111 Lock lock = manager.lock(node.getPath(), true, false, HOLD_LOCK_IN_SECONDS, null);
112 preDeleteNode(node, context, lock);
113 } finally {
114 if (manager.isLocked(node.getPath())) {
115 manager.unlock(node.getPath());
116 }
117 }
118 } else {
119 this.deleteNode(node);
120 parentNode.getSession().save();
121 }
122
123 return true;
124 }
125
126 protected void deleteNode(Node node) throws RepositoryException {
127 node.remove();
128 }
129
130 protected void preDeleteNode(Node node, Context context, Lock lock) throws RepositoryException {
131
132 if (lock != null) {
133 lock.refresh();
134 }
135
136 VersionConfig versionConfig = Components.getComponent(VersionConfig.class);
137 if (versionConfig.isActive()) {
138 version(node, context);
139 }
140
141 markAsDeleted(node);
142 purgeContent(node);
143 storeDeletionInfo(node, context);
144
145 node.getSession().save();
146
147
148 Rule rule = new Rule(StringUtils.split(getItemTypes() + "," + NodeTypes.MetaData.NAME + "," + NodeTypes.Resource.NAME, ", "));
149 rule.reverse();
150 for (Iterator<Node> iter = new FilteringNodeIterator(node.getNodes(), new RuleBasedNodePredicate(rule)); iter.hasNext(); ) {
151 preDeleteNode(iter.next(), context, lock);
152 }
153 }
154
155
156
157
158 @Deprecated
159 protected void preDeleteNode(Node node, Context context) throws RepositoryException {
160 log.warn("Usage of deprecated method detected, Locked node at'{}' will be automatically unlocked after '{}' seconds.", node.getPath(), HOLD_LOCK_IN_SECONDS);
161 preDeleteNode(node, context, null);
162 }
163
164 protected void storeDeletionInfo(Node node, Context context) throws RepositoryException {
165 String comment = (String) context.get("comment");
166
167 NodeTypes.Deleted.set(node, comment);
168 }
169
170 protected void version(Node node, Context context) throws RepositoryException {
171 if (isVersionManually()) {
172 String comment = (String) context.get("comment");
173 if (comment == null) {
174 comment = "versions.comment.deleted";
175 }
176 node.setProperty(NodeTypes.Deleted.COMMENT, comment);
177 node.getSession().save();
178
179 versionManager.addVersion(node, getRule());
180 }
181 }
182
183 protected void markAsDeleted(Node node) throws RepositoryException {
184
185 node.addMixin(NodeTypes.Deleted.NAME);
186
187 if (node.isNodeType(NodeTypes.Renderable.NAME)) {
188 NodeTypes.Renderable.set(node, DELETED_NODE_TEMPLATE);
189 }
190 }
191
192 protected void purgeContent(Node node) throws RepositoryException {
193
194 for (Iterator<Node> iter = new FilteringNodeIterator(node.getNodes(), new RuleBasedNodePredicate(getRule())); iter.hasNext(); ) {
195 iter.next().remove();
196 }
197
198 for (Iterator<Property> iter = new FilteringPropertyIterator(node.getProperties(), new JCRMgnlPropertyHidingPredicate()); iter.hasNext(); ) {
199 Property property = iter.next();
200 property.remove();
201 }
202 }
203
204 public boolean isVersionManually() {
205 return versionManually;
206 }
207
208 public void setVersionManually(boolean versionManually) {
209 this.versionManually = versionManually;
210 }
211
212 public boolean isForcePreDelete() {
213 return forcePreDelete;
214 }
215
216 public void setForcePreDelete(boolean forcePreDelete) {
217 this.forcePreDelete = forcePreDelete;
218 }
219 }