View Javadoc

1   /**
2    * This file Copyright (c) 2010-2011 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.util.NodeDataUtil;
39  import info.magnolia.cms.util.NodeTypeFilter;
40  import info.magnolia.context.MgnlContext;
41  import info.magnolia.logging.AuditLoggingUtil;
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.lang.StringUtils;
56  
57  /**
58   * A base class by implementing some default behavior.
59   * A subclass must carefully implement {@link #newNodeDataInstance(String, int, boolean)},
60   * {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, String, java.util.Comparator)} and
61   * {@link #getNodeDataCollection(String)}.
62   *
63   * @author pbaerfuss
64   * @version $Id$
65   */
66  public abstract class AbstractContent extends ContentHandler implements Content {
67      private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractContent.class);
68  
69      public Content createContent(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException {
70          return createContent(name, ItemType.CONTENT);
71      }
72  
73      public Content createContent(String name, ItemType contentType) throws PathNotFoundException, RepositoryException, AccessDeniedException {
74          return createContent(name, contentType.getSystemName());
75      }
76  
77      public NodeData createNodeData(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException {
78          return setNodeData(name, "");
79      }
80  
81      public NodeData createNodeData(String name, Value value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
82          return setNodeData(name, value);
83      }
84  
85      /**
86       * @deprecated
87       */
88      @Deprecated
89      public NodeData createNodeData(String name, Value[] value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
90          return setNodeData(name, value);
91      }
92  
93      /**
94       * @deprecated
95       */
96      @Deprecated
97      public NodeData createNodeData(String name, int type) throws PathNotFoundException, RepositoryException, AccessDeniedException {
98          // set some default values to create the property
99          switch (type) {
100         case PropertyType.STRING:
101             return setNodeData(name, StringUtils.EMPTY);
102         case PropertyType.BOOLEAN:
103             return setNodeData(name, Boolean.FALSE);
104         case PropertyType.DATE:
105             return setNodeData(name, Calendar.getInstance());
106         case PropertyType.LONG:
107             return setNodeData(name, new Long(0));
108         case PropertyType.DOUBLE:
109             return setNodeData(name, new Double(0.0));
110         default:
111             return newNodeDataInstance(name, type, true);
112         }
113     }
114 
115     /**
116      * @deprecated
117      */
118     @Deprecated
119     public NodeData createNodeData(String name, Object valueObj) throws RepositoryException {
120         return setNodeData(name, valueObj);
121     }
122 
123     /**
124      * {@inheritDoc}
125      * 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
126      */
127     public NodeData getNodeData(String name) {
128         try {
129             // will try to determine the type if the node data exists, otherwise an non-mutable node data will be returned
130             return newNodeDataInstance(name, PropertyType.UNDEFINED, false);
131         }
132         catch(RepositoryException e){
133             throw new IllegalStateException("Can't instantiate node data " + name + " on node " + toString(), e);
134         }
135     }
136 
137     /**
138      * 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.
139      * 
140      * @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)
141      */
142     abstract public NodeData newNodeDataInstance(String name, int type, boolean createIfNotExisting) throws AccessDeniedException, RepositoryException;
143 
144     /**
145      * Delegates to {@link NodeData#isExist()}.
146      */
147     public boolean hasNodeData(String name) throws RepositoryException {
148         return getNodeData(name).isExist();
149     }
150 
151     public NodeData setNodeData(String name, Value value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
152         NodeData nodeData = newNodeDataInstance(name, value.getType(), true);
153         nodeData.setValue(value);
154         return nodeData;
155     }
156 
157     public NodeData setNodeData(String name, Value[] value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
158         if(value.length == 0){
159             throw new IllegalArgumentException("Value array can't be empty");
160         }
161         NodeData nodeData = newNodeDataInstance(name, value[0].getType(), true);
162         nodeData.setValue(value);
163         return nodeData;
164     }
165 
166     public NodeData setNodeData(String name, boolean value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
167         NodeData nodeData = newNodeDataInstance(name, PropertyType.BOOLEAN, true);
168         nodeData.setValue(value);
169         return nodeData;
170     }
171 
172     public NodeData setNodeData(String name, long value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
173         NodeData nodeData = newNodeDataInstance(name, PropertyType.LONG, true);
174         nodeData.setValue(value);
175         return nodeData;
176     }
177 
178     public NodeData setNodeData(String name, double value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
179         NodeData nodeData = newNodeDataInstance(name, PropertyType.DOUBLE, true);
180         nodeData.setValue(value);
181         return nodeData;
182     }
183 
184     public NodeData setNodeData(String name, String value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
185         NodeData nodeData = newNodeDataInstance(name, PropertyType.STRING, true);
186         nodeData.setValue(value);
187         return nodeData;
188     }
189 
190     public NodeData setNodeData(String name, InputStream value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
191         NodeData nodeData = newNodeDataInstance(name, PropertyType.BINARY, true);
192         nodeData.setValue(value);
193         return nodeData;
194     }
195 
196     public NodeData setNodeData(String name, Calendar value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
197         NodeData nodeData = newNodeDataInstance(name, PropertyType.DATE, true);
198         nodeData.setValue(value);
199         return nodeData;
200     }
201 
202     public NodeData setNodeData(String name, Content value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
203         NodeData nodeData = newNodeDataInstance(name, PropertyType.STRING, true);
204         nodeData.setValue(value.getUUID());
205         return nodeData;
206     }
207 
208     /**
209      * Uses the {@link NodeDataUtil} to create and set the node data based on the object type.
210      */
211     public NodeData setNodeData(String name, Object value) throws PathNotFoundException, RepositoryException, AccessDeniedException {
212         NodeData nodeData = newNodeDataInstance(name, NodeDataUtil.getJCRPropertyType(value), true);
213         NodeDataUtil.setValue(nodeData, value);
214         return nodeData;
215     }
216 
217     public void deleteNodeData(String name) throws PathNotFoundException, RepositoryException {
218         getNodeData(name).delete();
219     }
220 
221     /**
222      * {@inheritDoc}
223      * Delegates to {@link #getChildren(ItemType)} passing the current node's type.
224      */
225     public Collection<Content> getChildren() {
226         String type = null;
227 
228         try {
229             type = this.getNodeTypeName();
230         }
231         catch (RepositoryException re) {
232             throw new RuntimeException("Can't read type of node [" + toString() + "]", re);
233 
234         }
235         // fix all getChildren calls from the root node
236         if ("rep:root".equalsIgnoreCase(type)) { //$NON-NLS-1$
237             type = ItemType.CONTENT.getSystemName();
238         }
239         // --------------------------------------------------
240         return this.getChildren(type);
241     }
242 
243     /**
244      * {@inheritDoc}
245      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, java.util.Comparator).
246      */
247     public Collection<Content> getChildren(ContentFilter filter) {
248         return getChildren(filter, null);
249     }
250 
251     /**
252      * {@inheritDoc}
253      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, java.util.Comparator).
254      */
255     public Collection<Content> getChildren(ItemType itemType) {
256         return getChildren(new NodeTypeFilter(itemType), null);
257     }
258 
259     /**
260      * {@inheritDoc}
261      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, java.util.Comparator).
262      */
263     public Collection<Content> getChildren(String contentType) {
264         return getChildren(new NodeTypeFilter(contentType), null);
265     }
266 
267     /**
268      * {@inheritDoc}
269      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, String, java.util.Comparator)}.
270      */
271     public Collection<Content> getChildren(final String contentType, final String namePattern) {
272         return getChildren(new NodeTypeFilter(contentType), namePattern, null);
273     }
274 
275     /**
276      * {@inheritDoc}
277      * Delegates to {@link #getChildren(info.magnolia.cms.core.Content.ContentFilter, String, java.util.Comparator)}.
278      */
279     public Collection<Content> getChildren(ContentFilter filter, Comparator<Content> orderCriteria) {
280         return getChildren(filter, null, orderCriteria);
281     }
282 
283     /**
284      * @param namePattern ignored if null.
285      */
286     abstract public Collection<Content> getChildren(ContentFilter filter, String namePattern, Comparator<Content> orderCriteria);
287 
288     /**
289      * @deprecated
290      */
291     @Deprecated
292     public Content getChildByName(String namePattern) {
293         Collection<Content> children = getChildren("nt:base", namePattern);;
294         if (!children.isEmpty()) {
295             return children.iterator().next();
296         }
297         return null;
298     }
299 
300     public Collection<NodeData> getNodeDataCollection() {
301         return getNodeDataCollection(null);
302     }
303 
304     protected Collection<NodeData> getBinaryNodeDatas(String namePattern) throws RepositoryException {
305         Collection<NodeData> nodeDatas = new ArrayList<NodeData>();
306         Collection<Content> binaryNodes = getChildren(ItemType.NT_RESOURCE, namePattern);
307         for (Content binaryNode : binaryNodes) {
308             nodeDatas.add(newNodeDataInstance(binaryNode.getName(), PropertyType.BINARY, false));
309         }
310         return nodeDatas;
311     }
312 
313 
314     public boolean hasChildren() {
315         return (this.getChildren().size() > 0);
316     }
317 
318     public boolean hasChildren(String contentType) {
319         return (this.getChildren(contentType).size() > 0);
320     }
321 
322     public void delete(String path) throws RepositoryException {
323         if(isNodeData(path)){
324             deleteNodeData(path);
325         }
326         else{
327             getContent(path).delete();
328         }
329     }
330 
331     public boolean isNodeData(String path) throws AccessDeniedException, RepositoryException {
332         return hasNodeData(path);
333     }
334 
335     public String getTemplate() {
336         return this.getMetaData().getTemplate();
337     }
338 
339     public String getTitle() {
340         return I18nContentSupportFactory.getI18nSupport().getNodeData(this, "title").getString();
341     }
342 
343     public void updateMetaData() throws RepositoryException, AccessDeniedException {
344         MetaData md = this.getMetaData();
345         md.setModificationDate();
346         md.setAuthorId(MgnlContext.getUser().getName());
347         AuditLoggingUtil.log(AuditLoggingUtil.ACTION_MODIFY, getHierarchyManager().getName(), this.getItemType(), getHandle());
348     }
349 
350     public boolean isGranted(long permissions) {
351         return getHierarchyManager().getAccessManager().isGranted(getHandle(), permissions);
352     }
353 
354     public Workspace getWorkspace() throws RepositoryException {
355         return getHierarchyManager().getWorkspace();
356     }
357 
358     @Override
359     public String toString() {
360         StringBuffer buffer = new StringBuffer();
361         buffer.append(getHierarchyManager() == null ? "null" : getHierarchyManager().getName());
362         buffer.append(":" + getHandle());
363         String type = "";
364         try {
365             type = getItemType().getSystemName();
366         }
367         catch (RepositoryException e) {
368             // ignore
369         }
370         buffer.append("[");
371         buffer.append(type);
372         buffer.append("]");
373 
374         return buffer.toString();
375     }
376 
377 
378 }