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.templating.elements;
35
36 import info.magnolia.cms.beans.config.ServerConfiguration;
37 import info.magnolia.cms.security.User;
38 import info.magnolia.cms.security.operations.OperationPermissionDefinition;
39 import info.magnolia.context.MgnlContext;
40 import info.magnolia.context.WebContext;
41 import info.magnolia.i18nsystem.I18nizer;
42 import info.magnolia.jcr.inheritance.InheritanceNodeWrapper;
43 import info.magnolia.objectfactory.Components;
44 import info.magnolia.registry.RegistrationException;
45 import info.magnolia.rendering.context.RenderingContext;
46 import info.magnolia.rendering.engine.AppendableOnlyOutputProvider;
47 import info.magnolia.rendering.engine.RenderException;
48 import info.magnolia.rendering.engine.RenderingEngine;
49 import info.magnolia.rendering.template.AreaDefinition;
50 import info.magnolia.rendering.template.ComponentAvailability;
51 import info.magnolia.rendering.template.RenderableDefinition;
52 import info.magnolia.rendering.template.TemplateDefinition;
53 import info.magnolia.rendering.template.assignment.TemplateDefinitionAssignment;
54 import info.magnolia.templating.freemarker.AreaDirective;
55
56 import java.io.IOException;
57 import java.util.HashMap;
58 import java.util.Iterator;
59 import java.util.Map;
60
61 import javax.inject.Inject;
62 import javax.jcr.Node;
63 import javax.jcr.RepositoryException;
64 import javax.jcr.Session;
65
66 import org.apache.commons.lang3.StringUtils;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71
72
73 public class ComponentElement extends AbstractContentTemplatingElement {
74
75 private static final Logger log = LoggerFactory.getLogger(ComponentElement.class);
76
77 private Map<String, Object> contextAttributes = new HashMap<String, Object>();
78 private Node content;
79 private TemplateDefinition componentDefinition;
80
81 private boolean renderEditbar = true;
82 private String dialog;
83 private Boolean editable;
84 private Boolean moveable, writable, deletable;
85
86 private final RenderingEngine renderingEngine;
87 private final TemplateDefinitionAssignment templateDefinitionAssignment;
88
89 @Inject
90 public ComponentElement(ServerConfiguration server, RenderingContext renderingContext, RenderingEngine renderingEngine, TemplateDefinitionAssignment templateDefinitionAssignment, I18nizer i18nizer) {
91 super(server, renderingContext, i18nizer);
92 this.renderingEngine = renderingEngine;
93 this.templateDefinitionAssignment = templateDefinitionAssignment;
94 }
95
96
97
98
99 @Deprecated
100 public ComponentElement(ServerConfiguration server, RenderingContext renderingContext, RenderingEngine renderingEngine, TemplateDefinitionAssignment templateDefinitionAssignment) {
101 this(server, renderingContext, renderingEngine, templateDefinitionAssignment, Components.getComponent(I18nizer.class));
102 }
103
104 @Override
105 public void begin(Appendable out) throws IOException, RenderException {
106
107 content = getPassedContent();
108
109 if (content == null) {
110 throw new RenderException("The 'content' or 'workspace' and 'path' attribute have to be set to render a component.");
111 }
112
113 if (renderComments()) {
114
115 try {
116 this.componentDefinition = templateDefinitionAssignment.getAssignedTemplateDefinition(content);
117 } catch (RegistrationException e) {
118 throw new RenderException("No template definition found for the current content", e);
119 }
120
121 MarkupHelper helper = new MarkupHelper(out);
122
123 helper.openComment("cms:component");
124
125 helper.attribute(AreaDirective.CONTENT_ATTRIBUTE, getNodePath(content));
126
127 if (content instanceof InheritanceNodeWrapper) {
128 if (((InheritanceNodeWrapper) content).isInherited()) {
129 helper.attribute("inherited", "true");
130 }
131 }
132
133 this.editable = resolveEditable();
134 if (this.editable != null) {
135 helper.attribute("editable", String.valueOf(this.editable));
136 }
137
138 final AreaDefinition areaDefinition = this.getRenderingContext().getParentAreaDefinition();
139 OperationPermissionDefinition permissions = null;
140 User user = null;
141
142 if (areaDefinition != null) {
143 String componentId = componentDefinition.getId();
144 ComponentAvailability componentAvailability = null;
145 Iterator<ComponentAvailability> iterator = areaDefinition.getAvailableComponents().values().iterator();
146 while (iterator.hasNext()) {
147 ComponentAvailability availability = iterator.next();
148 if (availability.getId().equals(componentId)) {
149 componentAvailability = availability;
150 break;
151 }
152 }
153 if (componentAvailability != null && componentAvailability.getPermissions() != null) {
154 permissions = componentAvailability.getPermissions();
155 user = MgnlContext.getUser();
156 }
157 }
158
159 this.moveable = this.resolveMoveable(permissions, user);
160 if (this.moveable != null) {
161 helper.attribute(OperationPermissionDefinition.MOVEABLE, String.valueOf(this.moveable));
162 }
163
164 this.writable = this.resolveWritable(permissions, user);
165 if (this.writable != null) {
166 helper.attribute(OperationPermissionDefinition.WRITABLE, String.valueOf(this.writable));
167 }
168
169 this.deletable = this.resolveDeletable(permissions, user);
170 if (this.deletable != null) {
171 helper.attribute(OperationPermissionDefinition.DELETABLE, String.valueOf(this.deletable));
172 }
173
174 if (StringUtils.isEmpty(dialog)) {
175 dialog = resolveDialog();
176 }
177 helper.attribute("dialog", dialog);
178
179 RenderableDefinition i18nizedDefinition = this.i18nize(componentDefinition);
180 String label = i18nizedDefinition.getTitle();
181
182
183 final String i18nBasename = StringUtils.isNotEmpty(componentDefinition.getI18nBasename()) ? componentDefinition.getI18nBasename() : (areaDefinition == null ? null : areaDefinition.getI18nBasename());
184 label = this.legacyTranslate(label, i18nBasename);
185
186 if (label == null || isMessageKey(label)) {
187 label = componentDefinition.getName();
188 }
189 helper.attribute("label", label);
190
191
192 String description = i18nizedDefinition.getDescription();
193 description = this.legacyTranslate(description, i18nBasename);
194
195 if (!isMessageKey(i18nizedDefinition.getDescription())) {
196 helper.attribute("description", description);
197 }
198
199 helper.attribute("activationStatus", getActivationStatus(content));
200
201 helper.append(" -->\n");
202 }
203
204
205
206 WebContext webContext = MgnlContext.getWebContext();
207 webContext.push(webContext.getRequest(), webContext.getResponse());
208 setAttributesInWebContext(contextAttributes, WebContext.LOCAL_SCOPE);
209
210 try {
211 if (componentDefinition != null) {
212 renderingEngine.render(content, componentDefinition, new HashMap<String, Object>(), new AppendableOnlyOutputProvider(out));
213 } else {
214 renderingEngine.render(content, new AppendableOnlyOutputProvider(out));
215 }
216 } finally {
217 webContext.pop();
218 webContext.setPageContext(null);
219 restoreAttributesInWebContext(contextAttributes, WebContext.LOCAL_SCOPE);
220 }
221 }
222
223 private boolean hasPermission(Node node) {
224 try {
225 return node.getSession().hasPermission(node.getPath(), Session.ACTION_SET_PROPERTY);
226 } catch (RepositoryException e) {
227 log.error("Could not determine permission for node {}", node);
228 }
229 return false;
230 }
231
232 private Boolean resolveEditable() {
233 return editable != null ? editable : componentDefinition != null && componentDefinition.getEditable() != null ? componentDefinition.getEditable() : null;
234 }
235
236 private Boolean resolveMoveable(final OperationPermissionDefinition permissions, User user) {
237
238 Boolean moveable = this.moveable != null ? this.moveable : componentDefinition != null && componentDefinition.getMoveable() != null ? componentDefinition.getMoveable() : null;
239 if (moveable != null || permissions == null) {
240 return moveable;
241 }
242
243
244 if (!permissions.canMove(user)) {
245 return false;
246 }
247 return true;
248 }
249
250 private Boolean resolveWritable(final OperationPermissionDefinition permissions, User user) {
251
252 Boolean writable = this.writable != null ? this.writable : componentDefinition != null && componentDefinition.getWritable() != null ? componentDefinition.getWritable() : null;
253 if (writable != null || permissions == null) {
254 return writable;
255 }
256
257 if (!permissions.canWrite(user)) {
258 return false;
259 }
260 return true;
261 }
262
263 private Boolean resolveDeletable(final OperationPermissionDefinition permissions, User user) {
264
265 Boolean deletable = this.deletable != null ? this.deletable : componentDefinition != null && componentDefinition.getDeletable() != null ? componentDefinition.getDeletable() : null;
266 if (deletable != null || permissions == null) {
267 return deletable;
268 }
269
270 if (!permissions.canDelete(user)) {
271 return false;
272 }
273 return true;
274 }
275
276 @Override
277 public void end(Appendable out) throws IOException, RenderException {
278 if (renderComments()) {
279 new MarkupHelper(out).closeComment("cms:component");
280 }
281 }
282
283 public Map<String, Object> getContextAttributes() {
284 return contextAttributes;
285 }
286
287 public void setContextAttributes(Map<String, Object> contextAttributes) {
288 this.contextAttributes = contextAttributes;
289 }
290
291 private String resolveDialog() {
292 if (StringUtils.isNotEmpty(this.dialog)) {
293 return this.dialog;
294 }
295 String dialog = componentDefinition.getDialog();
296 if (StringUtils.isNotEmpty(dialog)) {
297 return dialog;
298 }
299 return null;
300 }
301
302 public void setDialog(String dialog) {
303 this.dialog = dialog;
304 }
305
306 public void setEditable(Boolean editable) {
307 this.editable = editable;
308 }
309
310 public Boolean getEditable() {
311 return editable;
312 }
313
314 public boolean isRenderEditbar() {
315 return renderEditbar;
316 }
317
318 public void setRenderEditbar(boolean renderEditbar) {
319 this.renderEditbar = renderEditbar;
320 }
321
322 @Override
323 protected boolean renderComments() {
324 return this.renderEditbar && isAdmin() && !MgnlContext.getAggregationState().isPreviewMode() && hasPermission(this.content);
325 }
326 }