View Javadoc
1   /**
2    * This file Copyright (c) 2015 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
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.resources.app.workbench.ResourcesContainer;
45  import info.magnolia.ui.api.context.UiContext;
46  import info.magnolia.ui.api.event.AdmincentralEventBus;
47  import info.magnolia.ui.api.event.ContentChangedEvent;
48  import info.magnolia.ui.framework.action.MarkNodeAsDeletedAction;
49  import info.magnolia.ui.vaadin.integration.jcr.JcrItemAdapter;
50  import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
51  import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
52  
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  
63  import com.google.common.base.Predicate;
64  import com.google.common.collect.FluentIterable;
65  import com.google.common.collect.Lists;
66  import com.google.common.collect.Ordering;
67  import com.vaadin.data.Item;
68  
69  /**
70   * This action is used for marking the resource as deleted.
71   * <p>
72   * This will create a new Node version marked as deleted.
73   *
74   * @see MarkResourceAsDeletedActionDefinition
75   */
76  public class MarkResourceAsDeletedAction extends MarkNodeAsDeletedAction {
77  
78      private final List<JcrItemAdapter> jcrItemAdapters;
79      private final SimpleTranslator i18n;
80      private final boolean isDirectory;
81  
82      public MarkResourceAsDeletedAction(MarkResourceAsDeletedActionDefinition definition, List<Item> items, CommandsManager commandsManager, @Named(AdmincentralEventBus.NAME) EventBus eventBus, UiContext uiContext, SimpleTranslator i18n, Context context) {
83          this(definition, ResourceUtils.getJcrItemAdaptersFor(context, items), commandsManager, eventBus, uiContext, i18n, items.get(0));
84      }
85  
86      public MarkResourceAsDeletedAction(MarkResourceAsDeletedActionDefinition definition, Item item, CommandsManager commandsManager, @Named(AdmincentralEventBus.NAME) EventBus eventBus, UiContext uiContext, SimpleTranslator i18n, Context context) {
87          this(definition, ResourceUtils.getJcrItemAdaptersFor(context, Lists.newArrayList(item)), commandsManager, eventBus, uiContext, i18n, item);
88      }
89  
90      private MarkResourceAsDeletedAction(MarkResourceAsDeletedActionDefinition definition, List<JcrItemAdapter> jcrItemAdapters, CommandsManager commandsManager, EventBus eventBus, UiContext uiContext, SimpleTranslator i18n, Item item) {
91          super(definition, jcrItemAdapters, commandsManager, eventBus, uiContext, i18n);
92          this.isDirectory = ResourceUtils.isDirectory(item);
93          this.jcrItemAdapters = jcrItemAdapters;
94          this.i18n = i18n;
95      }
96  
97      @Override
98      protected void onPostExecute() throws Exception {
99          super.onPostExecute();
100         for (JcrItemAdapter itemAdapter : jcrItemAdapters) {
101             javax.jcr.Item jcrItem = itemAdapter.getJcrItem();
102             if (jcrItem != null) {
103                 eventBus.fireEvent(new ContentChangedEvent(jcrItem.getPath()));
104             } else {
105                 eventBus.fireEvent(new ContentChangedEvent(ResourcesContainer.ROOT_DIRECTORY));
106             }
107         }
108     }
109 
110     @Override
111     protected List<JcrItemAdapter> getItems() {
112         List<JcrItemAdapter> items = Lists.newArrayList();
113         for (JcrItemAdapter jcrItemAdapter : jcrItemAdapters) {
114             items.addAll(getItems(jcrItemAdapter));
115         }
116         return items;
117     }
118 
119     @Override
120     protected List<JcrItemAdapter> getSortedItems(Comparator<JcrItemAdapter> comparator) {
121         return Ordering.from(comparator).sortedCopy(getItems());
122     }
123 
124     @Override
125     protected Comparator<JcrItemAdapter> getItemComparator() {
126         return new Comparator<JcrItemAdapter>() {
127             @Override
128             public int compare(JcrItemAdapter o1, JcrItemAdapter o2) {
129                 try {
130                     return o2.getJcrItem().getDepth() - o1.getJcrItem().getDepth();
131                 } catch (RepositoryException e) {
132                     return 0;
133                 }
134             }
135         };
136     }
137 
138     private List<JcrItemAdapter> getItems(JcrItemAdapter jcrItemAdapter) {
139         List<JcrItemAdapter> items = Lists.newArrayList();
140 
141         try {
142             Session jcrSession = jcrItemAdapter.getJcrItem().getSession();
143             Node node = jcrSession.getNode(jcrItemAdapter.getJcrItem().getPath());
144 
145             boolean hasSiblings = !getSiblings(node).isEmpty();
146             if (hasSiblings) {
147                 items.add(jcrItemAdapter);
148             } else {
149                 findNodeAndEmptyAncestorsFromJcr(items, node, null);
150             }
151         } catch (RepositoryException e) {
152             uiContext.openNotification(MessageStyleTypeEnum.ERROR, false, i18n.translate("resources.actions.deleteResource.notification.error"));
153             throw new RuntimeException(e);
154         }
155         return items;
156     }
157 
158     private void findNodeAndEmptyAncestorsFromJcr(List<JcrItemAdapter> items, Node node, final Node removedChildNode) throws RepositoryException {
159         if (node.getDepth() == 0) {
160             return;
161         }
162 
163         List<Node> siblings = getSiblings(node);
164         List<Node> filteredSiblings = filterSiblings(siblings, removedChildNode);
165 
166         boolean hasNoMoreResources = filteredSiblings.size() < 1;
167         if (hasNoMoreResources) {
168             Node parent = node.getParent();
169             items.add(new JcrNodeAdapter(node));
170             findNodeAndEmptyAncestorsFromJcr(items, parent, node);
171         }
172     }
173 
174     private List<Node> filterSiblings(List<Node> siblings, final Node removedChildNode) {
175         return FluentIterable
176                 .from(siblings)
177                 .filter(filterRemovedNode(removedChildNode))
178                 .filter(markedAsDeleted())
179                 .toList();
180     }
181 
182     private List<Node> getSiblings(Node node) throws RepositoryException {
183         List<Node> resources = Lists.newArrayList(NodeUtil.getNodes(node, NodeTypes.Content.NAME));
184         List<Node> folders = Lists.newArrayList(NodeUtil.getNodes(node, NodeTypes.Folder.NAME));
185         resources.addAll(folders);
186 
187         return resources;
188     }
189 
190     @Override
191     protected String getSuccessMessage() {
192         if (isDirectory) {
193             return i18n.translate("resources.actions.markFolderAsDeleted.notification.success", super.getItems().size());
194         } else {
195             return i18n.translate("resources.actions.markFileAsDeleted.notification.success", super.getItems().size());
196         }
197     }
198 
199     @Override
200     protected String getFailureMessage() {
201         if (isDirectory) {
202             return i18n.translate("resources.actions.markFolderAsDeleted.notification.error", super.getItems().size());
203         } else {
204             return i18n.translate("resources.actions.markFileAsDeleted.notification.error", super.getItems().size());
205         }
206     }
207 
208     private Predicate<Node> markedAsDeleted() {
209         return new Predicate<Node>() {
210             @Override
211             public boolean apply(Node node) {
212                 try {
213                     return !node.hasProperty(NodeTypes.Deleted.NAME);
214                 } catch (RepositoryException e) {
215                     throw new RuntimeRepositoryException(e);
216                 }
217             }
218         };
219     }
220 
221     private Predicate<Node> filterRemovedNode(final Node removedChildNode) {
222         return new Predicate<Node>() {
223             @Override
224             public boolean apply(Node node) {
225                 try {
226                     if (StringUtils.equals(node.getPath(), removedChildNode.getPath())) {
227                         return false;
228                     }
229                 } catch (RepositoryException e) {
230                     throw new RuntimeRepositoryException(e);
231                 }
232                 return true;
233             }
234         };
235     }
236 }