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)
134    throws JspException {
135
136        if (editPermissions == null) {
137            // we do not have direct edit permissions
138            return null;
139        }
140
141        ServletRequest req = context.getRequest();
142        ServletResponse res = context.getResponse();
143        CmsFlexController controller = CmsFlexController.getController(req);
144
145        // append "direct edit" permissions to element
146        element = element + "_" + editPermissions;
147
148        // set request parameters required by the included direct edit JSP
149        Map<String, String[]> parameterMap = new HashMap<String, String[]>();
150        CmsJspTagInclude.addParameter(parameterMap, I_CmsResourceLoader.PARAMETER_ELEMENT, element, true);
151        CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_TARGET, editTarget, true);
152        CmsJspTagInclude.addParameter(
153            parameterMap,
154            DIRECT_EDIT_PARAM_LOCALE,
155            controller.getCmsObject().getRequestContext().getLocale().toString(),
156            true);
157        CmsUserSettings settings = new CmsUserSettings(controller.getCmsObject());
158        CmsJspTagInclude.addParameter(
159            parameterMap,
160            DIRECT_EDIT_PARAM_BUTTONSTYLE,
161            String.valueOf(settings.getDirectEditButtonStyle()),
162            true);
163        if (editElement != null) {
164            CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_ELEMENT, editElement, true);
165        }
166        if (editOptions != null) {
167            CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_OPTIONS, editOptions, true);
168        }
169        if (createLink != null) {
170            CmsJspTagInclude.addParameter(parameterMap, DIRECT_EDIT_PARAM_NEWLINK, CmsEncoder.encode(createLink), true);
171        }
172
173        // save old parameters from current request
174        Map<String, String[]> oldParameterMap = controller.getCurrentRequest().getParameterMap();
175
176        try {
177            controller.getCurrentRequest().addParameterMap(parameterMap);
178            context.getOut().print(CmsFlexResponse.FLEX_CACHE_DELIMITER);
179            controller.getCurrentResponse().addToIncludeList(
180                jspIncludeFile,
181                parameterMap,
182                CmsRequestUtil.getAtrributeMap(req));
183            controller.getCurrentRequest().getRequestDispatcher(jspIncludeFile).include(req, res);
184        } catch (ServletException e) {
185            Throwable t;
186            if (e.getRootCause() != null) {
187                t = e.getRootCause();
188            } else {
189                t = e;
190            }
191            t = controller.setThrowable(t, jspIncludeFile);
192            throw new JspException(t);
193        } catch (IOException e) {
194            Throwable t = controller.setThrowable(e, jspIncludeFile);
195            throw new JspException(t);
196        } finally {
197            // restore old parameter map (if required)
198            if (oldParameterMap != null) {
199                controller.getCurrentRequest().setParameterMap(oldParameterMap);
200            }
201        }
202
203        return editPermissions;
204    }
205
206    /**
207     * @see org.opencms.workplace.editors.directedit.A_CmsDirectEditProvider#init(org.opencms.file.CmsObject, org.opencms.workplace.editors.directedit.CmsDirectEditMode, java.lang.String)
208     */
209    @Override
210    public void init(CmsObject cms, CmsDirectEditMode mode, String fileName) {
211
212        m_cms = cms;
213        m_fileName = fileName;
214        if (CmsStringUtil.isEmpty(m_fileName)) {
215            m_fileName = DIRECT_EDIT_INCLUDE_FILE_URI_DEFAULT;
216        }
217        m_mode = mode != null ? mode : CmsDirectEditMode.AUTO;
218    }
219
220    /**
221     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditEnd(javax.servlet.jsp.PageContext)
222     */
223    public void insertDirectEditEnd(PageContext context) throws JspException {
224
225        if (m_editTarget != null) {
226            // otherwise no valid direct edit element has been opened
227            includeDirectEditElement(
228                context,
229                m_fileName,
230                DIRECT_EDIT_AREA_END,
231                m_editTarget,
232                m_editElement,
233                null,
234                m_permissions,
235                null);
236            m_editTarget = null;
237            m_permissions = null;
238            m_editElement = null;
239        }
240    }
241
242    /**
243     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditIncludes(javax.servlet.jsp.PageContext, org.opencms.workplace.editors.directedit.CmsDirectEditParams)
244     */
245    public void insertDirectEditIncludes(PageContext context, CmsDirectEditParams params) throws JspException {
246
247        try {
248            CmsJspTagInclude.includeTagAction(
249                context,
250                m_fileName,
251                DIRECT_EDIT_INCLUDES,
252                false,
253                null,
254                null,
255                context.getRequest(),
256                context.getResponse());
257        } catch (Throwable t) {
258            // should never happen
259            throw new JspException(t);
260        }
261    }
262
263    /**
264     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditStart(javax.servlet.jsp.PageContext, org.opencms.workplace.editors.directedit.CmsDirectEditParams)
265     */
266    public boolean insertDirectEditStart(PageContext context, CmsDirectEditParams params) throws JspException {
267
268        String result = null;
269        CmsDirectEditPermissions permissions = getResourceInfo(params, params.getResourceName()).getPermissions();
270        if (permissions.getPermission() > 0) {
271            // permission to direct edit is granted
272            m_permissions = permissions.toString();
273            m_editTarget = params.getResourceName();
274            m_editElement = params.getElement();
275
276            result = includeDirectEditElement(
277                context,
278                m_fileName,
279                DIRECT_EDIT_AREA_START,
280                m_editTarget,
281                m_editElement,
282                params.getButtonSelection().toString(),
283                m_permissions,
284                params.getLinkForNew());
285
286        } else {
287            // no direct edit permissions
288            m_editTarget = null;
289            m_permissions = null;
290            m_editElement = null;
291        }
292        return result != null;
293    }
294
295    /**
296     * Returns <code>false</code> because the JSP include provider does not support manual button placement.<p>
297     *
298     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#isManual(org.opencms.workplace.editors.directedit.CmsDirectEditMode)
299     */
300    @Override
301    public boolean isManual(CmsDirectEditMode mode) {
302
303        return false;
304    }
305
306    /**
307     * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#newInstance()
308     */
309    public I_CmsDirectEditProvider newInstance() {
310
311        CmsDirectEditJspIncludeProvider result = new CmsDirectEditJspIncludeProvider();
312        result.m_configurationParameters = m_configurationParameters;
313        return result;
314    }
315}