1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.rendering.template.assignment;
35
36 import info.magnolia.cms.security.PermissionUtil;
37 import info.magnolia.context.MgnlContext;
38 import info.magnolia.i18nsystem.SimpleTranslator;
39 import info.magnolia.jcr.util.NodeTypes;
40 import info.magnolia.jcr.util.NodeUtil;
41 import info.magnolia.objectfactory.Components;
42 import info.magnolia.registry.RegistrationException;
43 import info.magnolia.rendering.template.TemplateAvailability;
44 import info.magnolia.rendering.template.TemplateDefinition;
45 import info.magnolia.rendering.template.registry.TemplateDefinitionRegistry;
46
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.Comparator;
51
52 import javax.inject.Inject;
53 import javax.inject.Singleton;
54 import javax.jcr.Node;
55 import javax.jcr.RepositoryException;
56 import javax.jcr.Session;
57
58 import org.apache.commons.lang.StringUtils;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62
63
64
65 @Singleton
66 public class MetaDataBasedTemplateDefinitionAssignment implements TemplateDefinitionAssignment {
67
68 private static final String DELETED_PAGE_TEMPLATE = "adminInterface:mgnlDeleted";
69
70 private static final Logger log = LoggerFactory.getLogger(MetaDataBasedTemplateDefinitionAssignment.class);
71
72 private TemplateDefinitionRegistry templateDefinitionRegistry;
73
74 private SimpleTranslator simpleTranslator;
75
76 @Inject
77 public MetaDataBasedTemplateDefinitionAssignment(TemplateDefinitionRegistry templateDefinitionRegistry, SimpleTranslator simpleTranslator) {
78 this.templateDefinitionRegistry = templateDefinitionRegistry;
79 this.simpleTranslator = simpleTranslator;
80 }
81
82
83
84
85 @Deprecated
86 public MetaDataBasedTemplateDefinitionAssignment(TemplateDefinitionRegistry templateDefinitionRegistry) {
87 this.templateDefinitionRegistry = templateDefinitionRegistry;
88 this.simpleTranslator = Components.getComponent(SimpleTranslator.class);
89 }
90
91 @Override
92 public String getAssignedTemplate(Node content) throws RepositoryException {
93 return NodeTypes.Renderable.getTemplate(content);
94 }
95
96 @Override
97 public TemplateDefinition getAssignedTemplateDefinition(Node content) throws RegistrationException {
98 final String templateId;
99 try {
100 templateId = getAssignedTemplate(content);
101 } catch (RepositoryException e) {
102 throw new RegistrationException("Could not determine assigned template", e);
103 }
104 if (templateId == null) {
105 throw new RegistrationException("No template definition assigned");
106 }
107 return templateDefinitionRegistry.getTemplateDefinition(templateId);
108 }
109
110
111
112
113 @Override
114 public TemplateDefinition getDefaultTemplate(Node content) {
115
116
117 TemplateDefinition parentTemplate = null;
118 try {
119 parentTemplate = getAssignedTemplateDefinition(content.getParent());
120 } catch (RepositoryException e) {
121 log.error("Failed to determine template assigned to parent of node: " + NodeUtil.getNodePathIfPossible(content), e);
122 } catch (RegistrationException e) {
123
124 }
125
126 if (parentTemplate != null && isAvailable(content, parentTemplate)) {
127 return parentTemplate;
128 }
129
130
131 Collection<TemplateDefinition> templates = getAvailableTemplates(content);
132 if (templates.isEmpty()) {
133 return null;
134 }
135
136 return templates.iterator().next();
137 }
138
139 @Override
140 public Collection<TemplateDefinition> getAvailableTemplates(Node content) {
141
142 try {
143 if (content != null && NodeUtil.hasMixin(content, NodeTypes.Deleted.NAME)) {
144 return Collections.singleton(templateDefinitionRegistry.getTemplateDefinition(DELETED_PAGE_TEMPLATE));
145 }
146 } catch (RepositoryException e) {
147 log.error("Failed to check node for deletion status.", e);
148 } catch (RegistrationException e) {
149 log.error("Deleted content template is not correctly registered.", e);
150 }
151
152 final ArrayList<TemplateDefinition> availableTemplateDefinitions = new ArrayList<TemplateDefinition>();
153 final Collection<TemplateDefinition> templateDefinitions = templateDefinitionRegistry.getTemplateDefinitions();
154 for (TemplateDefinition templateDefinition : templateDefinitions) {
155 if (isTemplateAvailable(content, templateDefinition)) {
156 availableTemplateDefinitions.add(templateDefinition);
157 }
158 }
159
160 Collections.sort(availableTemplateDefinitions, new Comparator<TemplateDefinition>() {
161
162 @Override
163 public int compare(TemplateDefinition lhs, TemplateDefinition rhs) {
164 return getI18nTitle(lhs).compareTo(getI18nTitle(rhs));
165 }
166
167 private String getI18nTitle(TemplateDefinition templateDefinition) {
168 if (StringUtils.isBlank(templateDefinition.getTitle())) {
169 log.warn("No title was found in the definition for template at [{}]", templateDefinition.getId());
170 return templateDefinition.getId() + " (missing title)";
171 }
172 return simpleTranslator.translate(templateDefinition.getTitle());
173 }
174 });
175
176 return availableTemplateDefinitions;
177 }
178
179 protected boolean isTemplateAvailable(Node content, TemplateDefinition templateDefinition) {
180 return hasReadAccess(content) &&
181 isVisible(templateDefinition) &&
182 isAvailable(content, templateDefinition);
183 }
184
185 protected boolean isVisible(TemplateDefinition templateDefinition) {
186 return templateDefinition.getVisible() == null || templateDefinition.getVisible();
187 }
188
189 protected boolean isAvailable(Node content, TemplateDefinition templateDefinition) {
190 TemplateAvailability templateAvailability = templateDefinition.getTemplateAvailability();
191 return templateAvailability == null || templateAvailability.isAvailable(content, templateDefinition);
192 }
193
194 protected boolean hasReadAccess(Node content) {
195 try {
196
197
198 return PermissionUtil.isGranted(
199 MgnlContext.getJCRSession(content.getSession().getWorkspace().getName()),
200 content.getPath(),
201 Session.ACTION_READ);
202 } catch (RepositoryException e) {
203 return false;
204 }
205 }
206 }