View Javadoc
1   /**
2    * This file Copyright (c) 2011-2014 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.rendering.template.configured;
35  
36  import info.magnolia.cms.core.MgnlNodeType;
37  import info.magnolia.jcr.RuntimeRepositoryException;
38  import info.magnolia.jcr.predicate.AbstractPredicate;
39  import info.magnolia.jcr.util.NodeUtil;
40  import info.magnolia.objectfactory.Components;
41  import info.magnolia.rendering.template.InheritanceConfiguration;
42  
43  import java.util.Comparator;
44  
45  import javax.jcr.Node;
46  import javax.jcr.NodeIterator;
47  import javax.jcr.RepositoryException;
48  
49  import org.apache.commons.lang.StringUtils;
50  
51  /**
52   * Defines behavior for inheritance. Allows for enabling
53   *
54   * @version $Id$
55   */
56  public class ConfiguredInheritance implements InheritanceConfiguration {
57  
58      public static final String COMPONENTS_ALL = "all";
59      public static final String COMPONENTS_NONE = "none";
60      public static final String COMPONENTS_FILTERED = "filtered";
61  
62      public static final String PROPERTIES_ALL = "all";
63      public static final String PROPERTIES_NONE = "none";
64  
65      private Boolean enabled = false;
66      private String components = COMPONENTS_FILTERED;
67      private String properties = PROPERTIES_ALL;
68      private Class<? extends AbstractPredicate<Node>> predicateClass;
69      private Class<? extends Comparator<Node>> nodeComparatorClass;
70  
71      @Override
72      public Boolean isEnabled() {
73          return enabled;
74      }
75  
76      public void setEnabled(Boolean enabled) {
77          this.enabled = enabled;
78      }
79  
80      public void setComponents(String components) {
81          this.components = components;
82      }
83  
84      public void setProperties(String properties) {
85          this.properties = properties;
86      }
87  
88      @Override
89      public Boolean isInheritsProperties() {
90          return isEnabled() != null && isEnabled() && StringUtils.equalsIgnoreCase(StringUtils.trim(properties), PROPERTIES_ALL);
91      }
92  
93      @Override
94      public Boolean isInheritsComponents() {
95          return isEnabled() != null && isEnabled() && (StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_ALL) || StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_FILTERED));
96      }
97  
98      @Override
99      public AbstractPredicate<Node> getComponentPredicate() {
100         if (isEnabled() == null || !isEnabled()) {
101             return new InheritNothingInheritancePredicate();
102         }
103         if (predicateClass != null) {
104             return Components.newInstance(predicateClass);
105         }
106         if (StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_ALL)) {
107             return new AllComponentsAndResourcesPredicate();
108         }
109         if (StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_FILTERED)) {
110             return new FilteredComponentInheritancePredicate();
111         }
112         return new InheritNothingInheritancePredicate();
113     }
114 
115     public void setPredicateClass(Class<? extends AbstractPredicate<Node>> predicateClass) {
116         this.predicateClass = predicateClass;
117     }
118 
119     @Override
120     public Comparator<Node> getComponentComparator() {
121         if (nodeComparatorClass != null) {
122             return Components.newInstance(nodeComparatorClass);
123         }
124         return new NodeDepthComparator();
125     }
126 
127     public void setNodeComparatorClass(Class<? extends Comparator<Node>> nodeComparatorClass) {
128         this.nodeComparatorClass = nodeComparatorClass;
129     }
130 
131     /**
132      * Predicate for component inheritance that includes only nodes with a a property named 'inheritable' that needs to
133      * be present and set to 'true'.
134      */
135     public static class FilteredComponentInheritancePredicate extends AbstractPredicate<Node> {
136 
137         public static final String INHERITED_PROPERTY_NAME = "inheritable";
138 
139         @Override
140         public boolean evaluateTyped(Node node) {
141             try {
142                 return NodeUtil.isNodeType(node, MgnlNodeType.NT_COMPONENT) && (node.hasProperty(INHERITED_PROPERTY_NAME) && Boolean.parseBoolean(node.getProperty(INHERITED_PROPERTY_NAME).getString()));
143             } catch (RepositoryException e) {
144                 throw new RuntimeRepositoryException(e);
145             }
146         }
147     }
148 
149     /**
150      * Predicate for component inheritance that includes all components and resources.
151      */
152     public static class AllComponentsAndResourcesPredicate extends AbstractPredicate<Node> {
153 
154         @Override
155         public boolean evaluateTyped(Node node) {
156             try { // we need to inherit also resources (binaries for images for example)
157                 return NodeUtil.isNodeType(node, MgnlNodeType.NT_COMPONENT) || NodeUtil.isNodeType(node, MgnlNodeType.NT_RESOURCE);
158             } catch (RepositoryException e) {
159                 throw new RuntimeRepositoryException(e);
160             }
161         }
162     }
163 
164     /**
165      * Predicate for component inheritance that includes no components.
166      */
167     public static class InheritNothingInheritancePredicate extends AbstractPredicate<Node> {
168 
169         @Override
170         public boolean evaluateTyped(Node node) {
171             return false;
172         }
173     }
174 
175     /**
176      * Comparator for ordering nodes by depth placing nodes deeper in the hierarchy after those further up and ordering
177      * nodes on the same level by the order they appear as siblings.
178      */
179     public static class NodeDepthComparator implements Comparator<Node> {
180 
181         @Override
182         public int compare(Node lhs, Node rhs) {
183             try {
184                 if (lhs.getDepth() != rhs.getDepth())
185                     return lhs.getDepth() - rhs.getDepth();
186                 return getSiblingIndex(lhs) - getSiblingIndex(rhs);
187             } catch (RepositoryException e) {
188                 throw new RuntimeRepositoryException(e);
189             }
190         }
191 
192         private int getSiblingIndex(Node node) throws RepositoryException {
193             if (node.getDepth() == 0) {
194                 return 0;
195             }
196             int index = 0;
197             NodeIterator nodes = node.getParent().getNodes();
198             while (nodes.hasNext()) {
199                 if (NodeUtil.isSame(node, nodes.nextNode())) {
200                     return index;
201                 }
202                 index++;
203             }
204             return -1;
205         }
206     }
207 }