View Javadoc
1   /**
2    * This file Copyright (c) 2015-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.workbench.thumbnail;
35  
36  import info.magnolia.jcr.util.NodeTypes;
37  import info.magnolia.jcr.util.NodeUtil;
38  import info.magnolia.ui.imageprovider.ImageProvider;
39  import info.magnolia.ui.vaadin.integration.contentconnector.JcrContentConnectorDefinition;
40  import info.magnolia.ui.vaadin.integration.contentconnector.NodeTypeDefinition;
41  import info.magnolia.ui.vaadin.layout.data.PagingThumbnailContainer;
42  import info.magnolia.ui.workbench.container.Refreshable;
43  import info.magnolia.ui.workbench.list.FlatJcrContainer;
44  
45  import java.util.ArrayList;
46  import java.util.Collection;
47  import java.util.List;
48  
49  import javax.jcr.Item;
50  import javax.jcr.Node;
51  import javax.jcr.RepositoryException;
52  import javax.jcr.Session;
53  
54  import org.apache.commons.lang3.StringUtils;
55  import org.slf4j.Logger;
56  import org.slf4j.LoggerFactory;
57  
58  import com.google.common.collect.ImmutableSet;
59  import com.vaadin.v7.data.Property;
60  import com.vaadin.v7.data.util.AbstractProperty;
61  
62  /**
63   * JCR implementation of {@link ThumbnailContainer} delegating to a {@link FlatJcrContainer}.
64   */
65  public class JcrThumbnailContainer extends FlatJcrContainer implements Refreshable, PagingThumbnailContainer {
66  
67      public static final String THUMBNAIL_PROPERTY_ID = "thumbnail";
68  
69      private static final Logger log = LoggerFactory.getLogger(JcrThumbnailContainer.class);
70  
71      private final ImageProvider imageProvider;
72  
73      public JcrThumbnailContainer(ImageProvider imageProvider, final JcrContentConnectorDefinition definition) {
74          super(definition);
75          this.imageProvider = imageProvider;
76      }
77  
78      // FILTERING OF JCR NODE-TYPES TO BE DISPLAYED AS THUMBNAILS
79  
80      @Override
81      protected String getQueryWhereClauseNodeTypes() {
82          List<String> defs = new ArrayList<>();
83          for (NodeTypeDefinition type : getConfiguration().getNodeTypes()) {
84              if (type.isHideInList() || NodeTypes.Folder.NAME.equals(type.getName())) {
85                  log.debug("Skipping {} node type. Nodes of such type won't be searched for.", type.getName());
86                  continue;
87              }
88              defs.add("[jcr:primaryType] = '" + type.getName() + "'");
89          }
90          return StringUtils.join(defs, " or ");
91      }
92  
93      @Override
94      public int indexOfId(Object itemId) {
95          if (!containsId(itemId)) {
96              return -1;
97          }
98          return super.indexOfId(itemId);
99      }
100 
101     @Override
102     public boolean containsId(Object itemId) {
103         final Item item = getJcrItem(itemId);
104         if (!item.isNode()) {
105             return super.containsId(itemId);
106         }
107 
108         Node node = (Node) item;
109         try {
110             if (!getConfiguration().isIncludeSystemNodes() && node.getName().startsWith("jcr:") || node.getName().startsWith("rep:")) {
111                 return false;
112             }
113 
114             String primaryNodeTypeName = node.getPrimaryNodeType().getName();
115             for (NodeTypeDefinition nodeTypeDefinition : getConfiguration().getNodeTypes()) {
116                 if (nodeTypeDefinition.isStrict()) {
117                     if (primaryNodeTypeName.equals(nodeTypeDefinition.getName())) {
118                         return true;
119                     }
120                 } else if (NodeUtil.isNodeType(node, nodeTypeDefinition.getName())) {
121                     return true;
122                 }
123             }
124 
125         } catch (RepositoryException e) {
126             log.error("Failed to check presence of {} in container", itemId, e);
127         }
128         return false;
129     }
130 
131     // SUPPORT OF THE THUMBNAIL CONTAINER PROPERTY
132 
133     @Override
134     public Collection<?> getContainerPropertyIds() {
135         return ImmutableSet.builder().addAll(super.getContainerPropertyIds()).add(THUMBNAIL_PROPERTY_ID).build();
136     }
137 
138     @Override
139     public Property getContainerProperty(Object itemId, Object propertyId) {
140         if (THUMBNAIL_PROPERTY_ID.equals(propertyId)) {
141             return new ThumbnailContainerProperty(itemId, imageProvider);
142         }
143         return super.getContainerProperty(itemId, propertyId);
144     }
145 
146     @Override
147     public Class<?> getType(Object propertyId) {
148         if (THUMBNAIL_PROPERTY_ID.equals(propertyId)) {
149             return Object.class;
150         }
151         return super.getType(propertyId);
152     }
153 
154     @Override
155     public Object getThumbnailPropertyId() {
156         return THUMBNAIL_PROPERTY_ID;
157     }
158 
159     @Override
160     public Property getThumbnailProperty(Object itemId) {
161         return getContainerProperty(itemId, THUMBNAIL_PROPERTY_ID);
162     }
163 
164     @Override
165     public Property getCaptionProperty(Object itemId) {
166         return new ThumbnailCaptionProperty(itemId);
167     }
168 
169     @Override
170     public void setPageSize(int pageSize) {
171         // TODO WHY 3?
172         int pageLength = Double.valueOf(Math.ceil(pageSize / 3.0)).intValue();
173         setPageLength(pageLength);
174         setCacheRatio(3);
175     }
176 
177     /**
178      * ThumbnailContainer property. Can have a Resource or a String as value.
179      */
180     public class ThumbnailContainerProperty extends AbstractProperty<Object> {
181 
182         private Object resourceId;
183 
184         private final ImageProvider imageProvider;
185 
186         public ThumbnailContainerProperty(final Object resourceId, ImageProvider imageProvider) {
187             this.resourceId = resourceId;
188             this.imageProvider = imageProvider;
189         }
190 
191         @Override
192         public Object getValue() {
193             if (imageProvider == null) {
194                 return null;
195             }
196             return imageProvider.getThumbnailResource(resourceId, ImageProvider.THUMBNAIL_GENERATOR);
197         }
198 
199         @Override
200         public void setValue(Object newValue) throws ReadOnlyException {
201             this.resourceId = newValue;
202         }
203 
204         @Override
205         public Class<Object> getType() {
206             return Object.class;
207         }
208     }
209 
210     /**
211      * ThumbnailContainer property that builds a caption based on the filename and extension. Should ideally be configurable.
212      */
213     public class ThumbnailCaptionProperty extends AbstractProperty<Object> {
214 
215         private Object resourceId;
216 
217         public ThumbnailCaptionProperty(final Object resourceId) {
218             this.resourceId = resourceId;
219         }
220 
221         @Override
222         public Object getValue() {
223             try {
224                 Session session = getJcrItem(resourceId).getSession();
225                 Node thumbnail = session.getNode(String.format("%s/%s", getJcrItem(resourceId).getPath(), THUMBNAIL_PROPERTY_ID));
226                 String fileName = thumbnail.getProperty("fileName").getString();
227                 String extension = thumbnail.getProperty("extension").getString();
228                 return String.format("%s.%s", fileName, extension);
229             } catch (RepositoryException e) {
230                 log.debug("The caption for the thumbnail '%s' couldn't be built, returning the raw node name instead.", resourceId, e);
231             }
232 
233             try {
234                 return getJcrItem(resourceId).getName();
235             } catch (RepositoryException e) {
236                 log.debug("The node name for '%s' couldn't be fetched either, returning an empty string.", resourceId, e);
237             }
238 
239             return "";
240         }
241 
242         @Override
243         public void setValue(Object newValue) throws ReadOnlyException {
244             this.resourceId = newValue;
245         }
246 
247         @Override
248         public Class<Object> getType() {
249             return Object.class;
250         }
251     }
252 
253 }