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.resources.app.action;
35
36 import info.magnolia.commands.CommandsManager;
37 import info.magnolia.context.Context;
38 import info.magnolia.event.EventBus;
39 import info.magnolia.i18nsystem.SimpleTranslator;
40 import info.magnolia.jcr.RuntimeRepositoryException;
41 import info.magnolia.jcr.util.NodeTypes;
42 import info.magnolia.jcr.util.NodeUtil;
43 import info.magnolia.resources.app.utils.ResourceUtils;
44 import info.magnolia.ui.api.context.UiContext;
45 import info.magnolia.ui.api.event.AdmincentralEventBus;
46 import info.magnolia.ui.api.event.ContentChangedEvent;
47 import info.magnolia.ui.framework.action.MarkNodeAsDeletedAction;
48 import info.magnolia.ui.vaadin.integration.jcr.JcrItemAdapter;
49 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
50 import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
51
52 import java.util.ArrayList;
53 import java.util.Comparator;
54 import java.util.List;
55
56 import javax.inject.Named;
57 import javax.jcr.Node;
58 import javax.jcr.RepositoryException;
59 import javax.jcr.Session;
60
61 import org.apache.commons.lang3.StringUtils;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 import com.google.common.base.Predicate;
66 import com.google.common.collect.FluentIterable;
67 import com.google.common.collect.Lists;
68 import com.google.common.collect.Ordering;
69 import com.vaadin.v7.data.Item;
70
71
72
73
74
75
76
77
78 public class MarkResourceAsDeletedAction extends MarkNodeAsDeletedAction {
79
80 private static final Logger log = LoggerFactory.getLogger(MarkResourceAsDeletedAction.class);
81
82 private final List<JcrItemAdapter> jcrItemAdapters;
83 private final SimpleTranslator i18n;
84 private final boolean isDirectory;
85 private final List<String> changedItemPaths = new ArrayList<>();
86
87 public MarkResourceAsDeletedAction(MarkResourceAsDeletedActionDefinition definition, List<Item> items, CommandsManager commandsManager, @Named(AdmincentralEventBus.NAME) EventBus eventBus, UiContext uiContext, SimpleTranslator i18n, Context context) {
88 this(definition, ResourceUtils.getJcrItemAdaptersFor(context, items), commandsManager, eventBus, uiContext, i18n, items.get(0));
89 }
90
91 public MarkResourceAsDeletedAction(MarkResourceAsDeletedActionDefinition definition, Item item, CommandsManager commandsManager, @Named(AdmincentralEventBus.NAME) EventBus eventBus, UiContext uiContext, SimpleTranslator i18n, Context context) {
92 this(definition, ResourceUtils.getJcrItemAdaptersFor(context, Lists.newArrayList(item)), commandsManager, eventBus, uiContext, i18n, item);
93 }
94
95 private MarkResourceAsDeletedAction(MarkResourceAsDeletedActionDefinition definition, List<JcrItemAdapter> jcrItemAdapters, CommandsManager commandsManager, EventBus eventBus, UiContext uiContext, SimpleTranslator i18n, Item item) {
96 super(definition, jcrItemAdapters, commandsManager, eventBus, uiContext, i18n);
97 this.isDirectory = ResourceUtils.isDirectory(item);
98 this.jcrItemAdapters = jcrItemAdapters;
99 this.i18n = i18n;
100 for (JcrItemAdapter itemAdapter : jcrItemAdapters) {
101 try {
102 changedItemPaths.add(itemAdapter.getJcrItem().getPath());
103 } catch (RepositoryException e) {
104 log.warn("Unable to obtain path for item {}", itemAdapter.getItemId());
105 }
106 }
107 }
108
109 @Override
110 protected void onPostExecute() throws Exception {
111 eventBus.fireEvent(new ContentChangedEvent(changedItemPaths));
112 }
113
114 @Override
115 protected List<JcrItemAdapter> getItems() {
116 List<JcrItemAdapter> items = Lists.newArrayList();
117 for (JcrItemAdapter jcrItemAdapter : jcrItemAdapters) {
118 items.addAll(getItems(jcrItemAdapter));
119 }
120 return items;
121 }
122
123 @Override
124 protected List<JcrItemAdapter> getSortedItems(Comparator<JcrItemAdapter> comparator) {
125 return Ordering.from(comparator).sortedCopy(getItems());
126 }
127
128 @Override
129 protected Comparator<JcrItemAdapter> getItemComparator() {
130 return new Comparator<JcrItemAdapter>() {
131 @Override
132 public int compare(JcrItemAdapter o1, JcrItemAdapter o2) {
133 try {
134 return o2.getJcrItem().getDepth() - o1.getJcrItem().getDepth();
135 } catch (RepositoryException e) {
136 return 0;
137 }
138 }
139 };
140 }
141
142 private List<JcrItemAdapter> getItems(JcrItemAdapter jcrItemAdapter) {
143 List<JcrItemAdapter> items = Lists.newArrayList();
144
145 try {
146 Session jcrSession = jcrItemAdapter.getJcrItem().getSession();
147 Node node = jcrSession.getNode(jcrItemAdapter.getJcrItem().getPath());
148
149 boolean hasSiblings = !getSiblings(node).isEmpty();
150 if (hasSiblings) {
151 items.add(jcrItemAdapter);
152 } else {
153 findNodeAndEmptyAncestorsFromJcr(items, node, null);
154 }
155 } catch (RepositoryException e) {
156 uiContext.openNotification(MessageStyleTypeEnum.ERROR, false, i18n.translate("resources.actions.deleteResource.notification.error"));
157 throw new RuntimeException(e);
158 }
159 return items;
160 }
161
162 private void findNodeAndEmptyAncestorsFromJcr(List<JcrItemAdapter> items, Node node, final Node removedChildNode) throws RepositoryException {
163 if (node.getDepth() == 0) {
164 return;
165 }
166
167 List<Node> siblings = getSiblings(node);
168 List<Node> filteredSiblings = filterSiblings(siblings, removedChildNode);
169
170 boolean hasNoMoreResources = filteredSiblings.size() < 1;
171 if (hasNoMoreResources) {
172 Node parent = node.getParent();
173 items.add(new JcrNodeAdapter(node));
174 findNodeAndEmptyAncestorsFromJcr(items, parent, node);
175 }
176 }
177
178 private List<Node> filterSiblings(List<Node> siblings, final Node removedChildNode) {
179 return FluentIterable
180 .from(siblings)
181 .filter(filterRemovedNode(removedChildNode))
182 .filter(markedAsDeleted())
183 .toList();
184 }
185
186 private List<Node> getSiblings(Node node) throws RepositoryException {
187 List<Node> resources = Lists.newArrayList(NodeUtil.getNodes(node, NodeTypes.Content.NAME));
188 List<Node> folders = Lists.newArrayList(NodeUtil.getNodes(node, NodeTypes.Folder.NAME));
189 resources.addAll(folders);
190
191 return resources;
192 }
193
194 @Override
195 protected String getSuccessMessage() {
196 if (isDirectory) {
197 return i18n.translate("resources.actions.markFolderAsDeleted.notification.success", super.getItems().size());
198 } else {
199 return i18n.translate("resources.actions.markFileAsDeleted.notification.success", super.getItems().size());
200 }
201 }
202
203 @Override
204 protected String getFailureMessage() {
205 if (isDirectory) {
206 return i18n.translate("resources.actions.markFolderAsDeleted.notification.error", super.getItems().size());
207 } else {
208 return i18n.translate("resources.actions.markFileAsDeleted.notification.error", super.getItems().size());
209 }
210 }
211
212 private Predicate<Node> markedAsDeleted() {
213 return new Predicate<Node>() {
214 @Override
215 public boolean apply(Node node) {
216 try {
217 return !node.hasProperty(NodeTypes.Deleted.NAME);
218 } catch (RepositoryException e) {
219 throw new RuntimeRepositoryException(e);
220 }
221 }
222 };
223 }
224
225 private Predicate<Node> filterRemovedNode(final Node removedChildNode) {
226 return new Predicate<Node>() {
227 @Override
228 public boolean apply(Node node) {
229 try {
230 if (StringUtils.equals(node.getPath(), removedChildNode.getPath())) {
231 return false;
232 }
233 } catch (RepositoryException e) {
234 throw new RuntimeRepositoryException(e);
235 }
236 return true;
237 }
238 };
239 }
240 }