View Javadoc
1   /**
2    * This file Copyright (c) 2013-2018 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.ui.admincentral.shellapp.favorites;
35  
36  import static info.magnolia.ui.framework.AdmincentralNodeTypes.Favorite.*;
37  
38  import info.magnolia.cms.core.Path;
39  import info.magnolia.cms.security.JCRSessionOp;
40  import info.magnolia.context.MgnlContext;
41  import info.magnolia.jcr.RuntimeRepositoryException;
42  import info.magnolia.jcr.util.NodeUtil;
43  import info.magnolia.jcr.util.PropertyUtil;
44  import info.magnolia.ui.framework.AdmincentralNodeTypes.Favorite;
45  import info.magnolia.ui.framework.AdmincentralNodeTypes.FavoriteGroup;
46  import info.magnolia.ui.framework.favorite.FavoriteStore;
47  import info.magnolia.ui.vaadin.integration.jcr.AbstractJcrNodeAdapter;
48  import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
49  import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
50  import info.magnolia.ui.vaadin.integration.jcr.ModelConstants;
51  
52  import java.util.Map;
53  import java.util.TreeMap;
54  
55  import javax.inject.Inject;
56  import javax.jcr.Node;
57  import javax.jcr.NodeIterator;
58  import javax.jcr.RepositoryException;
59  import javax.jcr.Session;
60  
61  import org.apache.commons.lang3.StringUtils;
62  
63  import com.vaadin.v7.data.util.ObjectProperty;
64  
65  /**
66   * Implementation of a Manager for Favorites.
67   */
68  public final class FavoritesManagerImpl implements FavoritesManager {
69      private FavoriteStore favoriteStore;
70  
71      @Inject
72      public FavoritesManagerImpl(final FavoriteStore favoriteStore) {
73          this.favoriteStore = favoriteStore;
74      }
75  
76      @Override
77      public AbstractJcrNodeAdapter getFavorites() {
78          try {
79              Node bookmarksNode = favoriteStore.getBookmarkRoot();
80              JcrNodeAdapter favorites = new JcrNodeAdapter(bookmarksNode);
81  
82              Iterable<Node> bookmarks = NodeUtil.getNodes(bookmarksNode);
83              JcrNodeAdapter currentChild;
84              for (Node bookmark : bookmarks) {
85                  currentChild = new JcrNodeAdapter(bookmark);
86                  currentChild.addItemProperty(TITLE, new ObjectProperty<>(PropertyUtil.getString(bookmark, TITLE, "")));
87  
88                  final String bookmarkNodeType = bookmark.getPrimaryNodeType().getName();
89  
90                  if (Favorite.NAME.equals(bookmarkNodeType)) {
91                      currentChild.addItemProperty(URL, new ObjectProperty<>(PropertyUtil.getString(bookmark, URL, "")));
92                      currentChild.addItemProperty(ICON, new ObjectProperty<>(PropertyUtil.getString(bookmark, ICON, "")));
93                  } else if (FavoriteGroup.NAME.equals(bookmarkNodeType)) {
94                      Iterable<Node> bookmarksWithGroup = NodeUtil.getNodes(bookmark, Favorite.NAME);
95                      JcrNodeAdapter favoriteChild;
96                      for (Node bookmarkWithGroup : bookmarksWithGroup) {
97                          favoriteChild = new JcrNodeAdapter(bookmarkWithGroup);
98                          favoriteChild.addItemProperty(TITLE, new ObjectProperty<>(PropertyUtil.getString(bookmarkWithGroup, TITLE, "")));
99                          favoriteChild.addItemProperty(URL, new ObjectProperty<>(PropertyUtil.getString(bookmarkWithGroup, URL, "")));
100                         favoriteChild.addItemProperty(ICON, new ObjectProperty<>(PropertyUtil.getString(bookmarkWithGroup, ICON, "")));
101                         currentChild.addChild(favoriteChild);
102                     }
103                 }
104                 favorites.addChild(currentChild);
105             }
106             return favorites;
107         } catch (RepositoryException e) {
108             throw new RuntimeRepositoryException(e);
109         }
110     }
111 
112     @Override
113     public Map<String, String> getGroupsNames() {
114         Map<String, String> groupNames = new TreeMap<>();
115         Iterable<Node> groups;
116         try {
117             Node bookmarksNode = favoriteStore.getBookmarkRoot();
118             groups = NodeUtil.getNodes(bookmarksNode, FavoriteGroup.NAME);
119             for (Node group : groups) {
120                 groupNames.put(group.getName(), PropertyUtil.getString(group, TITLE));
121             }
122         } catch (RepositoryException e) {
123             throw new RuntimeRepositoryException(e);
124         }
125 
126         return groupNames;
127     }
128 
129     @Override
130     public void addFavorite(final JcrNewNodeAdapter favorite) {
131         try {
132             final String title = (String) favorite.getItemProperty(TITLE).getValue();
133             favorite.addItemProperty(ModelConstants.JCR_NAME, new ObjectProperty<>(Path.getValidatedLabel(title), String.class));
134             final Node newFavorite = MgnlContext.doInSystemContext(new JCRSessionOp<Node>(FavoriteStore.WORKSPACE_NAME) {
135                 @Override
136                 public Node exec(Session session) throws RepositoryException {
137                     return favorite.applyChanges();
138                 }
139             });
140 
141             Session session = newFavorite.getSession();
142             final String group = (String) favorite.getItemProperty(GROUP).getValue();
143             if (StringUtils.isNotBlank(group)) {
144                 Node parent = session.getNode(newFavorite.getParent().getPath() + "/" + group);
145                 NodeUtil.moveNode(newFavorite, parent);
146             }
147             session.save();
148         } catch (RepositoryException e) {
149             throw new RuntimeRepositoryException(e);
150         }
151     }
152 
153     @Override
154     public JcrNewNodeAdapter createFavoriteSuggestion(String location, String title, String icon) {
155         Node bookmarkRoot;
156         try {
157             bookmarkRoot = favoriteStore.getBookmarkRoot();
158         } catch (RepositoryException e) {
159             throw new RuntimeRepositoryException(e);
160         }
161 
162         JcrNewNodeAdapter newFavorite = new JcrNewNodeAdapter(bookmarkRoot, Favorite.NAME);
163         newFavorite.addItemProperty(TITLE, new ObjectProperty<>(title, String.class));
164         newFavorite.addItemProperty(URL, new ObjectProperty<>(location, String.class));
165         newFavorite.addItemProperty(GROUP, new ObjectProperty<>(null, String.class));
166         newFavorite.addItemProperty(ICON, new ObjectProperty<>(StringUtils.defaultIfEmpty(icon, "icon-app"), String.class));
167         return newFavorite;
168     }
169 
170     @Override
171     public void removeFavorite(String path) {
172         try {
173             Node bookmarkRoot = favoriteStore.getBookmarkRoot();
174             bookmarkRoot.getNode(path).remove();
175             bookmarkRoot.getSession().save();
176         } catch (RepositoryException e) {
177             throw new RuntimeRepositoryException(e);
178         }
179     }
180 
181     @Override
182     public void editFavorite(String path, String title) {
183         try {
184             // we get the props we need from the node being edited, then delete it and re-create it anew. This to ensure that title and jcr node name are kept in "sync",
185             // the latter being the title with jcr invalid characters replaced with dashes.
186             Node bookmarkRoot = favoriteStore.getBookmarkRoot();
187             Node staleFavorite = bookmarkRoot.getNode(path);
188             Node parent = staleFavorite.getParent();
189             String url = staleFavorite.getProperty(URL).getString();
190             String icon = staleFavorite.getProperty(ICON).getString();
191             String group = "";
192             if (staleFavorite.hasProperty(GROUP)) {
193                 group = staleFavorite.getProperty(GROUP).getString();
194             }
195             staleFavorite.remove();
196 
197             Node editedFavorite = parent.addNode(Path.getValidatedLabel(title), Favorite.NAME);
198             editedFavorite.setProperty(TITLE, title);
199             editedFavorite.setProperty(URL, url);
200             editedFavorite.setProperty(ICON, icon);
201             editedFavorite.setProperty(GROUP, group);
202 
203             bookmarkRoot.getSession().save();
204         } catch (RepositoryException e) {
205             throw new RuntimeRepositoryException(e);
206         }
207     }
208 
209     @Override
210     public JcrNewNodeAdapter createFavoriteGroupSuggestion(String title) {
211         Node bookmarkRoot;
212         try {
213             bookmarkRoot = favoriteStore.getBookmarkRoot();
214         } catch (RepositoryException e) {
215             throw new RuntimeRepositoryException(e);
216         }
217 
218         JcrNewNodeAdapter newGroup = new JcrNewNodeAdapter(bookmarkRoot, FavoriteGroup.NAME);
219         newGroup.addItemProperty(TITLE, new ObjectProperty<>(title, String.class));
220 
221         return newGroup;
222     }
223 
224     @Override
225     public void addGroup(final JcrNewNodeAdapter newGroup) {
226         MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
227 
228             @Override
229             public void doExec() {
230                 final String title = (String) newGroup.getItemProperty(TITLE).getValue();
231                 newGroup.addItemProperty(ModelConstants.JCR_NAME, new ObjectProperty<>(Path.getValidatedLabel(title), String.class));
232                 try {
233                     newGroup.applyChanges().getSession().save();
234                 } catch (RepositoryException e) {
235                     throw new RuntimeRepositoryException(e);
236                 }
237             }
238         });
239 
240     }
241 
242 
243     @Override
244     public void editGroup(String path, String newTitle) {
245         try {
246             // we get the props we need from the node being edited, then delete it and re-create it anew. This to ensure that title and jcr node name are kept in "sync",
247             // the latter being the title with jcr invalid characters replaced with dashes.
248             Node bookmarkRoot = favoriteStore.getBookmarkRoot();
249             Node oldGroup = bookmarkRoot.getNode(path);
250             NodeIterator favorites = oldGroup.getNodes();
251 
252             Node editedGroup = bookmarkRoot.addNode(Path.getValidatedLabel(newTitle), FavoriteGroup.NAME);
253             editedGroup.setProperty(TITLE, newTitle);
254             while (favorites.hasNext()) {
255                 Node favorite = favorites.nextNode();
256                 favorite.setProperty(GROUP, editedGroup.getName());
257                 NodeUtil.moveNode(favorite, editedGroup);
258             }
259             oldGroup.remove();
260             bookmarkRoot.getSession().save();
261         } catch (RepositoryException e) {
262             throw new RuntimeRepositoryException(e);
263         }
264 
265     }
266 
267     @Override
268     public void removeGroup(String path) {
269         try {
270             Node bookmarkRoot = favoriteStore.getBookmarkRoot();
271             Node groupToBeRemoved = bookmarkRoot.getNode(path);
272             // These ones will remain orphans :(
273             // NodeIterator favorites = groupToBeRemoved.getNodes(AdmincentralNodeTypes.Favorite.NAME);
274             groupToBeRemoved.remove();
275             bookmarkRoot.getSession().save();
276         } catch (RepositoryException e) {
277             throw new RuntimeRepositoryException(e);
278         }
279 
280     }
281 
282     @Override
283     public void moveFavorite(String relPath, String group) {
284         try {
285             Node favorite = favoriteStore.getBookmarkRoot().getNode(relPath);
286             Node newGroup;
287             if (StringUtils.isNotEmpty(group)) {
288                 newGroup = favoriteStore.getBookmarkRoot().getNode(group);
289             } else {
290                 newGroup = favoriteStore.getBookmarkRoot();
291             }
292             NodeUtil.moveNode(favorite, newGroup);
293             newGroup.getSession().save();
294         } catch (RepositoryException e) {
295             throw new RuntimeRepositoryException(e);
296         }
297     }
298 
299     @Override
300     public void orderFavoriteBefore(String relPath, String sibling) {
301         try {
302             Node favoriteToMove = favoriteStore.getBookmarkRoot().getNode(relPath);
303             NodeUtil.orderBefore(favoriteToMove, sibling);
304         } catch (RepositoryException e) {
305             throw new RuntimeRepositoryException(e);
306         }
307     }
308 
309     @Override
310     public void orderFavoriteAfter(String relPath, String sibling) {
311         try {
312             Node favoriteToMove = favoriteStore.getBookmarkRoot().getNode(relPath);
313             NodeUtil.orderAfter(favoriteToMove, sibling);
314         } catch (RepositoryException e) {
315             throw new RuntimeRepositoryException(e);
316         }
317     }
318 
319     @Override
320     public void orderGroupBefore(String relPath, String sibling) {
321         try {
322             Node groupToMove = favoriteStore.getBookmarkRoot().getNode(relPath);
323             NodeUtil.orderBefore(groupToMove, sibling);
324         } catch (RepositoryException e) {
325             throw new RuntimeRepositoryException(e);
326         }
327     }
328 
329     @Override
330     public void orderGroupAfter(String relPath, String sibling) {
331         try {
332             Node groupToMove = favoriteStore.getBookmarkRoot().getNode(relPath);
333             NodeUtil.orderAfter(groupToMove, sibling);
334         } catch (RepositoryException e) {
335             throw new RuntimeRepositoryException(e);
336         }
337 
338     }
339 }