View Javadoc
1   /**
2    * This file Copyright (c) 2010-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.cms.core;
35  
36  import info.magnolia.cms.i18n.I18nContentSupportFactory;
37  import info.magnolia.cms.security.AccessDeniedException;
38  import info.magnolia.cms.security.PermissionUtil;
39  import info.magnolia.cms.util.NodeDataUtil;
40  import info.magnolia.cms.util.NodeTypeFilter;
41  import info.magnolia.context.MgnlContext;
42  
43  import java.io.InputStream;
44  import java.util.ArrayList;
45  import java.util.Calendar;
46  import java.util.Collection;
47  import java.util.Comparator;
48  
49  import javax.jcr.PathNotFoundException;
50  import javax.jcr.PropertyType;
51  import javax.jcr.RepositoryException;
52  import javax.jcr.Value;
53  import javax.jcr.Workspace;
54  
55  import org.apache.commons.lang3.StringUtils;
56  
57  /**
58   * A base class by implementing some default behavior. A subclass must carefully implement {@link #newNodeDataInstance(String, int, boolean)}, {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, String, java.util.Comparator)} and
59   * {@link #getNodeDataCollection(String)}.
60   * 
61   * @deprecated since 4.5 (by proxy of deprecating implementing interface {@link Content}. Declared deprecated since 5.5.4.
62   */
63  @Deprecated
64  public abstract class AbstractContent extends ContentHandler implements Content {
65      private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractContent.class);
66  
67      @Override
68      public Content createContent(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException {
69          return createContent(name, ItemType.CONTENT);
70      }
71  
72      @Override
73      public Content createContent(String name, ItemType contentType) throws PathNotFoundException, RepositoryException, AccessDeniedException {
74          return createContent(name, contentType.getSystemName());
75      }
76  
77      @Override
78      public NodeData createNodeData(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException {
79          return setNodeData(name, "");
80      }
81  
82      @Override
83      public NodeData createNodeData(String name, Value value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
84          return setNodeData(name, value);
85      }
86  
87      /**
88       * @deprecated
89       */
90      @Override
91      @Deprecated
92      public NodeData createNodeData(String name, Value[] value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
93          return setNodeData(name, value);
94      }
95  
96      /**
97       * @deprecated
98       */
99      @Override
100     @Deprecated
101     public NodeData createNodeData(String name, int type) throws PathNotFoundException, RepositoryException, AccessDeniedException {
102         // set some default values to create the property
103         switch (type) {
104         case PropertyType.STRING:
105             return setNodeData(name, StringUtils.EMPTY);
106         case PropertyType.BOOLEAN:
107             return setNodeData(name, Boolean.FALSE);
108         case PropertyType.DATE:
109             return setNodeData(name, Calendar.getInstance());
110         case PropertyType.LONG:
111             return setNodeData(name, Long.valueOf(0));
112         case PropertyType.DOUBLE:
113             return setNodeData(name, Double.valueOf(0.0));
114         default:
115             return newNodeDataInstance(name, type, true);
116         }
117     }
118 
119     /**
120      * @deprecated
121      */
122     @Override
123     @Deprecated
124     public NodeData createNodeData(String name, Object valueObj) throws RepositoryException {
125         return setNodeData(name, valueObj);
126     }
127 
128     /**
129      * {@inheritDoc}
130      * Delegates to {@link #newNodeDataInstance(String, int, boolean)} by setting the type to PropertyType.UNDEFINED. A subclass has to handle this by trying to determine the type if the node data exists. The reason for this is that implementations want to instantiate different node data classes per type
131      */
132     @Override
133     public NodeData getNodeData(String name) {
134         try {
135             // will try to determine the type if the node data exists, otherwise an non-mutable node data will be returned
136             return newNodeDataInstance(name, PropertyType.UNDEFINED, false);
137         } catch (RepositoryException e) {
138             throw new IllegalStateException("Can't instantiate node data " + name + " on node " + toString(), e);
139         }
140     }
141 
142     /**
143      * As defined in {@link Content#getNodeData(String)} this method always returns a node data object. If the type is {@link PropertyType#UNDEFINED} the implementation should check if the node data exists and determine the type to use.
144      *
145      * @param createIfNotExisting if false an empty non-mutable node data will be returned if the node data doesn't exist otherwise a mutable nodedata object is returned (depending on the type)
146      */
147     abstract public NodeData newNodeDataInstance(String name, int type, boolean createIfNotExisting) throws AccessDeniedException, RepositoryException;
148 
149     /**
150      * Delegates to {@link NodeData#isExist()}.
151      */
152     @Override
153     public boolean hasNodeData(String name) throws RepositoryException {
154         return getNodeData(name).isExist();
155     }
156 
157     @Override
158     public NodeData setNodeData(String name, Value value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
159         NodeData nodeData = newNodeDataInstance(name, value.getType(), true);
160         nodeData.setValue(value);
161         return nodeData;
162     }
163 
164     @Override
165     public NodeData setNodeData(String name, Value[] value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
166         if (value.length == 0) {
167             throw new IllegalArgumentException("Value array can't be empty");
168         }
169         NodeData nodeData = newNodeDataInstance(name, value[0].getType(), true);
170         nodeData.setValue(value);
171         return nodeData;
172     }
173 
174     @Override
175     public NodeData setNodeData(String name, boolean value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
176         NodeData nodeData = newNodeDataInstance(name, PropertyType.BOOLEAN, true);
177         nodeData.setValue(value);
178         return nodeData;
179     }
180 
181     @Override
182     public NodeData setNodeData(String name, long value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
183         NodeData nodeData = newNodeDataInstance(name, PropertyType.LONG, true);
184         nodeData.setValue(value);
185         return nodeData;
186     }
187 
188     @Override
189     public NodeData setNodeData(String name, double value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
190         NodeData nodeData = newNodeDataInstance(name, PropertyType.DOUBLE, true);
191         nodeData.setValue(value);
192         return nodeData;
193     }
194 
195     @Override
196     public NodeData setNodeData(String name, String value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
197         NodeData nodeData = newNodeDataInstance(name, PropertyType.STRING, true);
198         nodeData.setValue(value);
199         return nodeData;
200     }
201 
202     @Override
203     public NodeData setNodeData(String name, InputStream value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
204         NodeData nodeData = newNodeDataInstance(name, PropertyType.BINARY, true);
205         nodeData.setValue(value);
206         return nodeData;
207     }
208 
209     @Override
210     public NodeData setNodeData(String name, Calendar value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
211         NodeData nodeData = newNodeDataInstance(name, PropertyType.DATE, true);
212         nodeData.setValue(value);
213         return nodeData;
214     }
215 
216     @Override
217     public NodeData setNodeData(String name, Content value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
218         NodeData nodeData = newNodeDataInstance(name, PropertyType.REFERENCE, true);
219         nodeData.setValue(value);
220         return nodeData;
221     }
222 
223     /**
224      * Uses the {@link NodeDataUtil} to create and set the node data based on the object type.
225      */
226     @Override
227     public NodeData setNodeData(String name, Object value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
228         NodeData nodeData = newNodeDataInstance(name, NodeDataUtil.getJCRPropertyType(value), true);
229         NodeDataUtil.setValue(nodeData, value);
230         return nodeData;
231     }
232 
233     @Override
234     public void deleteNodeData(String name) throws PathNotFoundException, RepositoryException {
235         getNodeData(name).delete();
236     }
237 
238     /**
239      * {@inheritDoc}
240      * Delegates to {@link #getChildren(ItemType)} passing the current node's type.
241      */
242     @Override
243     public Collection<Content> getChildren() {
244         String type = null;
245 
246         try {
247             type = this.getNodeTypeName();
248         } catch (RepositoryException re) {
249             throw new RuntimeException("Can't read type of node [" + toString() + "]", re);
250 
251         }
252         // fix all getChildren calls from the root node
253         if ("rep:root".equalsIgnoreCase(type)) {
254             type = ItemType.CONTENT.getSystemName();
255         }
256         // --------------------------------------------------
257         return this.getChildren(type);
258     }
259 
260     /**
261      * {@inheritDoc}
262      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, java.util.Comparator)}.
263      */
264     @Override
265     public Collection<Content> getChildren(ContentFilter filter) {
266         return getChildren(filter, null);
267     }
268 
269     /**
270      * {@inheritDoc}
271      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, java.util.Comparator)}.
272      */
273     @Override
274     public Collection<Content> getChildren(ItemType itemType) {
275         return getChildren(new NodeTypeFilter(itemType), null);
276     }
277 
278     /**
279      * {@inheritDoc}
280      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, java.util.Comparator)}.
281      */
282     @Override
283     public Collection<Content> getChildren(String contentType) {
284         return getChildren(new NodeTypeFilter(contentType), null);
285     }
286 
287     /**
288      * {@inheritDoc}
289      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, String, java.util.Comparator)}.
290      */
291     @Override
292     public Collection<Content> getChildren(final String contentType, final String namePattern) {
293         return getChildren(new NodeTypeFilter(contentType), namePattern, null);
294     }
295 
296     /**
297      * {@inheritDoc}
298      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, String, java.util.Comparator)}.
299      */
300     @Override
301     public Collection<Content> getChildren(ContentFilter filter, Comparator<Content> orderCriteria) {
302         return getChildren(filter, null, orderCriteria);
303     }
304 
305     /**
306      * @param namePattern ignored if null.
307      */
308     abstract public Collection<Content> getChildren(ContentFilter filter, String namePattern, Comparator<Content> orderCriteria);
309 
310     /**
311      * @deprecated
312      */
313     @Override
314     @Deprecated
315     public Content getChildByName(String namePattern) {
316         Collection<Content> children = getChildren("nt:base", namePattern);
317         if (!children.isEmpty()) {
318             return children.iterator().next();
319         }
320         return null;
321     }
322 
323     @Override
324     public Collection<NodeData> getNodeDataCollection() {
325         return getNodeDataCollection(null);
326     }
327 
328     protected Collection<NodeData> getBinaryNodeDatas(String namePattern) throws RepositoryException {
329         Collection<NodeData> nodeDatas = new ArrayList<NodeData>();
330         Collection<Content> binaryNodes = getChildren(ItemType.NT_RESOURCE, namePattern);
331         for (Content binaryNode : binaryNodes) {
332             nodeDatas.add(newNodeDataInstance(binaryNode.getName(), PropertyType.BINARY, false));
333         }
334         return nodeDatas;
335     }
336 
337 
338     @Override
339     public boolean hasChildren() {
340         return (this.getChildren().size() > 0);
341     }
342 
343     @Override
344     public boolean hasChildren(String contentType) {
345         return (this.getChildren(contentType).size() > 0);
346     }
347 
348     @Override
349     public void delete(String path) throws RepositoryException {
350         if (isNodeData(path)) {
351             deleteNodeData(path);
352         } else {
353             getContent(path).delete();
354         }
355     }
356 
357     @Override
358     public boolean isNodeData(String path) throws AccessDeniedException, RepositoryException {
359         return hasNodeData(path);
360     }
361 
362     @Override
363     public String getTemplate() {
364         return this.getMetaData().getTemplate();
365     }
366 
367     @Override
368     public String getTitle() {
369         try {
370             return I18nContentSupportFactory.getI18nSupport().getProperty(this.getJCRNode(), "title").getString();
371         } catch (RepositoryException e) {
372             log.error("An error occurred while trying to access title property from {}", this, e);
373             return "";
374         }
375     }
376 
377     @Override
378     public void updateMetaData() throws RepositoryException, AccessDeniedException {
379         MetaData md = this.getMetaData();
380         md.setModificationDate();
381         md.setAuthorId(MgnlContext.getUser().getName());
382     }
383 
384     @Override
385     public boolean isGranted(long permissions) {
386         // In case getHandle() was manipulated by the subclass (e.g. ContentVersion we need to make sure permissions are checked on the said path)
387         final String handle = getHandle();
388         try {
389             return PermissionUtil.isGranted(this.getJCRNode().getSession(), handle, permissions);
390         } catch (RepositoryException e) {
391             log.error("An error occurred while trying to access path {} with permissions {}", handle, permissions, e);
392             return false;
393         }
394     }
395 
396     @Override
397     public Workspace getWorkspace() throws RepositoryException {
398         return getJCRNode().getSession().getWorkspace();
399     }
400 
401     @Override
402     public String toString() {
403         String type = "";
404         String workspaceName = "";
405 
406         try {
407             workspaceName = getWorkspace() == null ? "null" : getWorkspace().getName();
408             type = getItemType().getSystemName();
409         } catch (RepositoryException e) {
410             // ignore
411         }
412         StringBuilder builder = new StringBuilder();
413         builder.append(workspaceName);
414         builder.append(':').append(getHandle());
415         builder.append('[');
416         builder.append(type);
417         builder.append(']');
418 
419         return builder.toString();
420     }
421 
422 
423 }