View Javadoc
1   /**
2    * This file Copyright (c) 2011-2016 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.jcr.RuntimeRepositoryException;
37  import info.magnolia.jcr.predicate.AbstractPredicate;
38  import info.magnolia.jcr.util.NodeTypes;
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.Arrays;
44  import java.util.Comparator;
45  import java.util.List;
46  
47  import javax.jcr.Node;
48  import javax.jcr.NodeIterator;
49  import javax.jcr.RepositoryException;
50  
51  import org.apache.commons.lang3.StringUtils;
52  
53  /**
54   * Defines behavior for inheritance. Allows for enabling
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 List<String> nodeTypes = Arrays.asList(NodeTypes.Component.NAME, NodeTypes.Resource.NAME);
69      private Class<? extends AbstractPredicate<Node>> predicateClass;
70      private Class<? extends Comparator<Node>> nodeComparatorClass;
71  
72      @Override
73      public Boolean isEnabled() {
74          return enabled;
75      }
76  
77      public void setEnabled(Boolean enabled) {
78          this.enabled = enabled;
79      }
80  
81      public void setComponents(String components) {
82          this.components = components;
83      }
84  
85      public void setProperties(String properties) {
86          this.properties = properties;
87      }
88  
89      @Override
90      public Boolean isInheritsProperties() {
91          return isEnabled() != null && isEnabled() && StringUtils.equalsIgnoreCase(StringUtils.trim(properties), PROPERTIES_ALL);
92      }
93  
94      @Override
95      public Boolean isInheritsComponents() {
96          return isEnabled() != null && isEnabled() && (StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_ALL) || StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_FILTERED));
97      }
98  
99      @Override
100     public AbstractPredicate<Node> getComponentPredicate() {
101         if (isEnabled() == null || !isEnabled()) {
102             return new InheritNothingInheritancePredicate();
103         }
104         if (predicateClass != null) {
105             return Components.newInstance(predicateClass);
106         }
107         if (StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_ALL)) {
108             InheritancePredicate inheritancePredicate = new InheritancePredicate();
109             inheritancePredicate.setNodeTypes(getNodeTypes());
110             return inheritancePredicate;
111         }
112         if (StringUtils.equalsIgnoreCase(StringUtils.trim(components), COMPONENTS_FILTERED)) {
113             FilteredInheritancePredicate filteredInheritancePredicate = new FilteredInheritancePredicate();
114             filteredInheritancePredicate.setNodeTypes(getNodeTypes());
115             return filteredInheritancePredicate;
116         }
117         return new InheritNothingInheritancePredicate();
118     }
119 
120     public void setPredicateClass(Class<? extends AbstractPredicate<Node>> predicateClass) {
121         this.predicateClass = predicateClass;
122     }
123 
124     @Override
125     public Comparator<Node> getComponentComparator() {
126         if (nodeComparatorClass != null) {
127             return Components.newInstance(nodeComparatorClass);
128         }
129         return new NodeDepthComparator();
130     }
131 
132     public void setNodeComparatorClass(Class<? extends Comparator<Node>> nodeComparatorClass) {
133         this.nodeComparatorClass = nodeComparatorClass;
134     }
135 
136     public List<String> getNodeTypes() {
137         return nodeTypes;
138     }
139 
140     public void setNodeTypes(List<String> nodeTypes) {
141         this.nodeTypes = nodeTypes;
142     }
143 
144     /**
145      * Predicate for component inheritance that includes only nodes with a a property named 'inheritable' that needs to
146      * be present and set to 'true'.
147      * 
148      * @deprecated since 5.3.5. Use {@link FilteredInheritancePredicate} instead.
149      */
150     public static class FilteredComponentInheritancePredicate extends AbstractPredicate<Node> {
151 
152         public static final String INHERITED_PROPERTY_NAME = "inheritable";
153 
154         @Override
155         public boolean evaluateTyped(Node node) {
156             try {
157                 return NodeUtil.isNodeType(node, NodeTypes.Component.NAME) && (node.hasProperty(INHERITED_PROPERTY_NAME) && Boolean.parseBoolean(node.getProperty(INHERITED_PROPERTY_NAME).getString()));
158             } catch (RepositoryException e) {
159                 throw new RuntimeRepositoryException(e);
160             }
161         }
162     }
163 
164     /**
165      * Predicate for component inheritance that includes all components.
166      * 
167      * @deprecated since 5.3.5. Use {@link InheritancePredicate} instead.
168      */
169     public static class AllComponentsAndResourcesInheritancePredicate extends AbstractPredicate<Node> {
170 
171         @Override
172         public boolean evaluateTyped(Node node) {
173             try {
174                 return NodeUtil.isNodeType(node, NodeTypes.Component.NAME) || NodeUtil.isNodeType(node, NodeTypes.Resource.NAME);
175             } catch (RepositoryException e) {
176                 throw new RuntimeRepositoryException(e);
177             }
178         }
179     }
180 
181     /**
182      * Predicate for component inheritance that includes no components.
183      */
184     public static class InheritNothingInheritancePredicate extends AbstractPredicate<Node> {
185 
186         @Override
187         public boolean evaluateTyped(Node node) {
188             return false;
189         }
190     }
191 
192     /**
193      * Comparator for ordering nodes by depth placing nodes deeper in the hierarchy after those further up and ordering
194      * nodes on the same level by the order they appear as siblings.
195      */
196     public static class NodeDepthComparator implements Comparator<Node> {
197 
198         @Override
199         public int compare(Node lhs, Node rhs) {
200             try {
201                 if (lhs.getDepth() != rhs.getDepth())
202                     return lhs.getDepth() - rhs.getDepth();
203                 return getSiblingIndex(lhs) - getSiblingIndex(rhs);
204             } catch (RepositoryException e) {
205                 throw new RuntimeRepositoryException(e);
206             }
207         }
208 
209         private int getSiblingIndex(Node node) throws RepositoryException {
210             if (node.getDepth() == 0) {
211                 return 0;
212             }
213             int index = 0;
214             NodeIterator nodes = node.getParent().getNodes();
215             while (nodes.hasNext()) {
216                 if (NodeUtil.isSame(node, nodes.nextNode())) {
217                     return index;
218                 }
219                 index++;
220             }
221             return -1;
222         }
223     }
224 }