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