View Javadoc
1   /**
2    * This file Copyright (c) 2012-2018 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.templating.elements;
35  
36  import info.magnolia.cms.beans.config.ServerConfiguration;
37  import info.magnolia.cms.security.operations.OperationPermissionDefinition;
38  import info.magnolia.context.WebContext;
39  import info.magnolia.i18nsystem.I18nizer;
40  import info.magnolia.objectfactory.Components;
41  import info.magnolia.registry.RegistrationException;
42  import info.magnolia.rendering.context.RenderingContext;
43  import info.magnolia.rendering.engine.AppendableOnlyOutputProvider;
44  import info.magnolia.rendering.engine.RenderException;
45  import info.magnolia.rendering.engine.RenderingEngine;
46  import info.magnolia.rendering.template.AreaDefinition;
47  import info.magnolia.rendering.template.ComponentAvailability;
48  import info.magnolia.rendering.template.assignment.TemplateDefinitionAssignment;
49  import info.magnolia.templating.module.TemplatingModule;
50  
51  import java.io.IOException;
52  import java.util.HashMap;
53  import java.util.Map;
54  
55  import javax.inject.Inject;
56  import javax.inject.Provider;
57  import javax.jcr.Node;
58  import javax.jcr.RepositoryException;
59  import javax.jcr.Session;
60  
61  import org.slf4j.Logger;
62  import org.slf4j.LoggerFactory;
63  
64  /**
65   * Renders a piece of content.
66   */
67  public class ComponentElement extends AbstractContentTemplatingElement {
68  
69      private static final Logger log = LoggerFactory.getLogger(ComponentElement.class);
70      public static final String CMS_COMPONENT_TAG = "cms:component";
71  
72      private Map<String, Object> contextAttributes = new HashMap<>();
73  
74      private boolean renderEditbar = true;
75      private OperationPermissionDefinition permissions;
76  
77      private final RenderingEngine renderingEngine;
78      private final TemplateDefinitionAssignment templateDefinitionAssignment;
79  
80      @Inject
81      public ComponentElement(ServerConfiguration server, RenderingContext renderingContext, RenderingEngine renderingEngine, TemplateDefinitionAssignment templateDefinitionAssignment, WebContext webContext, Provider<TemplatingModule> templatingModuleProvider) {
82          super(server, renderingContext, templatingModuleProvider, webContext);
83          this.renderingEngine = renderingEngine;
84          this.templateDefinitionAssignment = templateDefinitionAssignment;
85      }
86  
87      /**
88       * @deprecated since 6.1. Use {@link #ComponentElement(info.magnolia.cms.beans.config.ServerConfiguration, info.magnolia.rendering.context.RenderingContext, info.magnolia.rendering.engine.RenderingEngine, info.magnolia.rendering.template.assignment.TemplateDefinitionAssignment, info.magnolia.context.WebContext, javax.inject.Provider)} instead.
89       */
90      @Deprecated
91      public ComponentElement(ServerConfiguration server, RenderingContext renderingContext, RenderingEngine renderingEngine, TemplateDefinitionAssignment templateDefinitionAssignment, I18nizer i18nizer, WebContext webContext) {
92          this(server, renderingContext, renderingEngine, templateDefinitionAssignment, webContext, () -> Components.getComponent(TemplatingModule.class));
93      }
94  
95      @Override
96      public void begin(Appendable out) throws IOException, RenderException {
97  
98          setContent(getPassedContent());
99  
100         if (getContent() == null) {
101             throw new RenderException("The 'content' or 'workspace' and 'path' attribute have to be set to render a component.");
102         }
103 
104         if (renderComments()) { // add condition into renderComments() method when adding extra condition to make sure it's in sync with adding comments in end() method
105 
106             try {
107                 setTemplateDefinition(templateDefinitionAssignment.getAssignedTemplateDefinition(getContent()));
108             } catch (RegistrationException e) {
109                 throw new RenderException("No template definition found for the current content", e);
110             }
111 
112             MarkupHelper helper = new MarkupHelper(out);
113 
114             helper.openComment(CMS_COMPONENT_TAG);
115             setPageEditorAttributes(helper, getContent());
116             helper.append(" -->\n");
117         }
118 
119         // TODO not sure how to pass editable
120 
121         getWebContext().push(getWebContext().getRequest(), getWebContext().getResponse());
122         setAttributesInWebContext(contextAttributes, WebContext.LOCAL_SCOPE);
123 
124         try {
125             if (getTemplateDefinition() != null) {
126                 renderingEngine.render(getContent(), getTemplateDefinition() , new HashMap<>(), new AppendableOnlyOutputProvider(out));
127             } else {
128                 renderingEngine.render(getContent(), new AppendableOnlyOutputProvider(out));
129             }
130         } finally {
131             getWebContext().pop();
132             restoreAttributesInWebContext(contextAttributes, WebContext.LOCAL_SCOPE);
133         }
134     }
135 
136     protected void setPageEditorAttributes(MarkupHelper helper, Node node) throws IOException, RenderException {
137         final AreaDefinition areaDefinition = this.getRenderingContext().getParentAreaDefinition();
138         permissions = null;
139 
140         if (areaDefinition != null) {
141             String componentId = getTemplateDefinition().getId();
142             ComponentAvailability componentAvailability = null;
143             for (ComponentAvailability availability : areaDefinition.getAvailableComponents().values()) {
144                 if (availability.getId().equals(componentId)) {
145                     componentAvailability = availability;
146                     break;
147                 }
148             }
149             if (componentAvailability != null && componentAvailability.getPermissions() != null) {
150                 permissions = componentAvailability.getPermissions();
151             }
152         }
153 
154         super.setPageEditorAttributes(helper, "component");
155     }
156 
157     private boolean hasPermission(Node node) {
158         try {
159             return node.getSession().hasPermission(node.getPath(), Session.ACTION_SET_PROPERTY);
160         } catch (RepositoryException e) {
161             log.error("Could not determine permission for node {}", node);
162         }
163         return false;
164     }
165 
166     @Override
167     public void end(Appendable out) throws IOException, RenderException {
168         if (renderComments()) { // add condition into renderComments() method when adding extra condition to make sure it's in sync with adding comments in begin() method
169             new MarkupHelper(out).closeComment("cms:component");
170         }
171     }
172 
173     public Map<String, Object> getContextAttributes() {
174         return contextAttributes;
175     }
176 
177     public void setContextAttributes(Map<String, Object> contextAttributes) {
178         this.contextAttributes = contextAttributes;
179     }
180 
181     public boolean isRenderEditbar() {
182         return renderEditbar;
183     }
184 
185     public void setRenderEditbar(boolean renderEditbar) {
186         this.renderEditbar = renderEditbar;
187     }
188 
189     @Override
190     protected boolean renderComments() {
191         return this.renderEditbar && isAdmin() && !getWebContext().getAggregationState().isPreviewMode() && hasPermission(getContent());
192     }
193 
194     public OperationPermissionDefinition getPermissions() {
195         return permissions;
196     }
197 }