001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.workplace.editors.directedit;
029
030import org.opencms.db.CmsUserSettings;
031import org.opencms.file.CmsObject;
032import org.opencms.flex.CmsFlexController;
033import org.opencms.flex.CmsFlexResponse;
034import org.opencms.i18n.CmsEncoder;
035import org.opencms.jsp.CmsJspTagInclude;
036import org.opencms.loader.I_CmsResourceLoader;
037import org.opencms.util.CmsRequestUtil;
038import org.opencms.util.CmsStringUtil;
039
040import java.io.IOException;
041import java.util.HashMap;
042import java.util.Map;
043
044import javax.servlet.ServletException;
045import javax.servlet.ServletRequest;
046import javax.servlet.ServletResponse;
047import javax.servlet.jsp.JspException;
048import javax.servlet.jsp.PageContext;
049
050/**
051 * Direct edit provider that uses the same JSP include based logic that has been
052 * the default before the 6.2.3 release.<p>
053 *
054 * Even though placing the HTML of the direct edit buttons appears to be more "flexible" at first,
055 * there is a large overhead invloved using this provider as compared to an implementation
056 * like {@link CmsDirectEditDefaultProvider}. For every direct edit button on a page,
057 * a JSP include is processed <i>twice</i> using this provider,
058 * one include for the opening and one for the closing HTML. A JSP include is a costly operation, which means
059 * the performance of a website is be impacted if many content managers work on the system that makes great
060 * use of direct edit with a lot of elements on a page. In order to avoid this performance impact,
061 * OpenCms since version 6.2.3 uses the {@link CmsDirectEditDefaultProvider} by default.<p>
062 *
063 * This provider DOES NOT support {@link CmsDirectEditMode#MANUAL} mode.<p>
064 *
065 * @since 6.2.3
066 */
067public class CmsDirectEditJspIncludeProvider extends A_CmsDirectEditProvider {
068
069    /** Prefix for direct edit end elements, used on JPS pages that supply the direct edit html. */
070    public static final String DIRECT_EDIT_AREA_END = "end_directedit";
071
072    /** Prefix for direct edit start elements, used on JPS pages that supply the direct edit html. */
073    public static final String DIRECT_EDIT_AREA_START = "start_directedit";
074
075    /** Default direct edit include file URI. */
076    public static final String DIRECT_EDIT_INCLUDE_FILE_URI_DEFAULT = "/system/workplace/editors/direct_edit.jsp";
077
078    /** Element name for direct edit includes. */
079    public static final String DIRECT_EDIT_INCLUDES = "directedit_includes";
080
081    /** Key to identify the edit button style, used on JPS pages that supply the direct edit html. */
082    public static final String DIRECT_EDIT_PARAM_BUTTONSTYLE = "__directEditButtonStyle";
083
084    /** Key to identify the edit element, used on JPS pages that supply the direct edit html. */
085    public static final String DIRECT_EDIT_PARAM_ELEMENT = "__directEditElement";
086
087    /** Key to identify the edit language, used on JPS pages that supply the direct edit html. */
088    public static final String DIRECT_EDIT_PARAM_LOCALE = "__directEditLocale";
089
090    /** Key to identify the link to use for the "new" button (if enabled). */
091    public static final String DIRECT_EDIT_PARAM_NEWLINK = "__directEditNewLink";
092
093    /** Key to identify additional direct edit options, used e.g. to control which direct edit buttons are displayed */
094    public static final String DIRECT_EDIT_PARAM_OPTIONS = "__directEditOptions";
095
096    /** Key to identify the edit target, used on JPS pages that supply the direct edit html. */
097    public static final String DIRECT_EDIT_PARAM_TARGET = "__directEditTarget";
098
099    /** The last direct edit element. */
100    protected String m_editElement;
101
102    /** The last direct edit target. */
103    protected String m_editTarget;
104
105    /** The last calculated direct edit permissions. */
106    protected String m_permissions;
107
108    /**
109     * Includes the "direct edit" element that adds HTML for the editable area to
110     * the output page.<p>
111     *
112     * @param context the current JSP page context
113     * @param jspIncludeFile the VFS path of the JSP that contains the direct edit HTML fragments
114     * @param element the editor element to include
115     * @param editTarget the direct edit target
116     * @param editElement the direct edit element
117     * @param editOptions the direct edit options
118     * @param editPermissions the direct edit permissions
119     * @param createLink the direct edit create link
120     *
121     * @throws JspException in case something goes wrong
122     *
123     * @return the direct edit permissions
124     */
125    public static String includeDirectEditElement(
126        PageContext context,
127        String jspIncludeFile,
128        String element,
129        String editTarget,
130        String editElement,
131        String editOptions,
132        String editPermissions,
133        String createLink) throws JspException {
134
135        if (editPermissions == null) {
136            // we do not have direct edit permissions
137            return null;
138        }
139
140        ServletRequest req = context.getRequest();
141        ServletResponse res = context.getResponse();
142        CmsFlexController controller = CmsFlexController.getController(req);
143
144        // append "direct edit" permissions to element
145        element = element + "_" + editPermissions;
146
147        // set request parameters required by the included direct edit JSP
148        Map<String, String[]> parameterMap = new HashMap<String, String[]>();
149        CmsJspTagInclude.addParameter(parameterMap, I_CmsResourceLoader.PARAMETER_ELEMENT, element, true);
150        CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_TARGET, editTarget, true);
151        CmsJspTagInclude.addParameter(
152            parameterMap,
153            DIRECT_EDIT_PARAM_LOCALE,
154            controller.getCmsObject().getRequestContext().getLocale().toString(),
155            true);
156        CmsUserSettings settings = new CmsUserSettings(controller.getCmsObject());
157        CmsJspTagInclude.addParameter(
158            parameterMap,
159            DIRECT_EDIT_PARAM_BUTTONSTYLE,
160            String.valueOf(settings.getDirectEditButtonStyle()),
161            true);
162        if (editElement != null) {
163            CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_ELEMENT, editElement, true);
164        }
165        if (editOptions != null) {
166            CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_OPTIONS, editOptions, true);
167        }
168        if (createLink != null) {
169            CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_NEWLINK, CmsEncoder.encode(createLink), true);
170        }
171
172        // save old parameters from current request
173        Map<String, String[]> oldParameterMap = controller.getCurrentRequest().getParameterMap();
174
175        try {
176            controller.getCurrentRequest().addParameterMap(parameterMap);
177            context.getOut().print(CmsFlexResponse.FLEX_CACHE_DELIMITER);
178            controller.getCurrentResponse().addToIncludeList(
179                jspIncludeFile,
180                parameterMap,
181                CmsRequestUtil.getAtrributeMap(req));
182            controller.getCurrentRequest().getRequestDispatcher(jspIncludeFile).include(req, res);
183        } catch (ServletException e) {
184            Throwable t;
185            if (e.getRootCause() != null) {
186                t = e.getRootCause();
187            } else {
188                t = e;
189            }
190            t = controller.setThrowable(t, jspIncludeFile);
191            throw new JspException(t);
192        } catch (IOException e) {
193            Throwable t = controller.setThrowable(e, jspIncludeFile);
194            throw new JspException(t);
195        } finally {
196            // restore old parameter map (if required)
197            if (oldParameterMap != null) {
198                controller.getCurrentRequest().setParameterMap(oldParameterMap);
199            }
200        }
201
202        return editPermissions;
203    }
204
205    /**
206     * @see org.opencms.workplace.editors.directedit.A_CmsDirectEditProvider#init(org.opencms.file.CmsObject, org.opencms.workplace.editors.directedit.CmsDirectEditMode, java.lang.String)
207     */
208    @Override
209    public void init(CmsObject cms, CmsDirectEditMode mode, String fileName) {
210
211        m_cms = cms;
212        m_fileName = fileName;
213        if (CmsStringUtil.isEmpty(m_fileName)) {
214            m_fileName = DIRECT_EDIT_INCLUDE_FILE_URI_DEFAULT;
215        }
216        m_mode = mode != null ? mode : CmsDirectEditMode.AUTO;
217    }
218
219    /**
220     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditEnd(javax.servlet.jsp.PageContext)
221     */
222    public void insertDirectEditEnd(PageContext context) throws JspException {
223
224        if (m_editTarget != null) {
225            // otherwise no valid direct edit element has been opened
226            includeDirectEditElement(
227                context,
228                m_fileName,
229                DIRECT_EDIT_AREA_END,
230                m_editTarget,
231                m_editElement,
232                null,
233                m_permissions,
234                null);
235            m_editTarget = null;
236            m_permissions = null;
237            m_editElement = null;
238        }
239    }
240
241    /**
242     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditIncludes(javax.servlet.jsp.PageContext, org.opencms.workplace.editors.directedit.CmsDirectEditParams)
243     */
244    public void insertDirectEditIncludes(PageContext context, CmsDirectEditParams params) throws JspException {
245
246        try {
247            CmsJspTagInclude.includeTagAction(
248                context,
249                m_fileName,
250                DIRECT_EDIT_INCLUDES,
251                false,
252                null,
253                null,
254                context.getRequest(),
255                context.getResponse());
256        } catch (Throwable t) {
257            // should never happen
258            throw new JspException(t);
259        }
260    }
261
262    /**
263     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditStart(javax.servlet.jsp.PageContext, org.opencms.workplace.editors.directedit.CmsDirectEditParams)
264     */
265    public boolean insertDirectEditStart(PageContext context, CmsDirectEditParams params) throws JspException {
266
267        String result = null;
268        CmsDirectEditPermissions permissions = getResourceInfo(params.getResourceName()).getPermissions();
269        if (permissions.getPermission() > 0) {
270            // permission to direct edit is granted
271            m_permissions = permissions.toString();
272            m_editTarget = params.getResourceName();
273            m_editElement = params.getElement();
274
275            result = includeDirectEditElement(
276                context,
277                m_fileName,
278                DIRECT_EDIT_AREA_START,
279                m_editTarget,
280                m_editElement,
281                params.getButtonSelection().toString(),
282                m_permissions,
283                params.getLinkForNew());
284
285        } else {
286            // no direct edit permissions
287            m_editTarget = null;
288            m_permissions = null;
289            m_editElement = null;
290        }
291        return result != null;
292    }
293
294    /**
295     * Returns <code>false</code> because the JSP include provider does not support manual button placement.<p>
296     *
297     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#isManual(org.opencms.workplace.editors.directedit.CmsDirectEditMode)
298     */
299    @Override
300    public boolean isManual(CmsDirectEditMode mode) {
301
302        return false;
303    }
304
305    /**
306     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#newInstance()
307     */
308    public I_CmsDirectEditProvider newInstance() {
309
310        CmsDirectEditJspIncludeProvider result = new CmsDirectEditJspIncludeProvider();
311        result.m_configurationParameters = m_configurationParameters;
312        return result;
313    }
314}