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