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.jsp;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.containerpage.shared.CmsContainerElement;
032import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
033import org.opencms.file.CmsObject;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.file.collectors.I_CmsCollectorPostCreateHandler;
037import org.opencms.flex.CmsFlexController;
038import org.opencms.jsp.util.CmsJspContentAccessValueWrapper;
039import org.opencms.jsp.util.CmsJspStandardContextBean;
040import org.opencms.main.CmsException;
041import org.opencms.main.CmsLog;
042import org.opencms.main.OpenCms;
043import org.opencms.util.CmsRequestUtil;
044import org.opencms.util.CmsUUID;
045import org.opencms.workplace.editors.directedit.CmsAdvancedDirectEditProvider;
046import org.opencms.workplace.editors.directedit.CmsDirectEditMode;
047import org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider;
048import org.opencms.xml.containerpage.CmsADESessionCache;
049import org.opencms.xml.containerpage.CmsContainerElementBean;
050import org.opencms.xml.containerpage.CmsFormatterConfiguration;
051import org.opencms.xml.containerpage.I_CmsFormatterBean;
052import org.opencms.xml.types.CmsXmlDisplayFormatterValue;
053import org.opencms.xml.types.I_CmsXmlContentValue;
054
055import java.util.HashMap;
056import java.util.LinkedHashMap;
057import java.util.List;
058import java.util.Locale;
059import java.util.Map;
060import java.util.Map.Entry;
061
062import javax.servlet.ServletRequest;
063import javax.servlet.ServletResponse;
064import javax.servlet.http.HttpServletRequest;
065import javax.servlet.jsp.PageContext;
066import javax.servlet.jsp.tagext.BodyTagSupport;
067
068import org.apache.commons.logging.Log;
069
070/**
071 * The 'display' tag can be used to display a single resource using a formatter. It also allows to activate direct editing.<p>
072 */
073public class CmsJspTagDisplay extends BodyTagSupport implements I_CmsJspTagParamParent {
074
075    /** The log object for this class. */
076    private static final Log LOG = CmsLog.getLog(CmsJspTagDisplay.class);
077
078    /** The serial version id. */
079    private static final long serialVersionUID = 2285680951218629093L;
080
081    /** Flag, indicating if the create option should be displayed. */
082    private boolean m_canCreate;
083
084    /** Flag, indicating if the delete option should be displayed. */
085    private boolean m_canDelete;
086
087    /** The tag attribute's value, specifying the path to the (sub)sitemap where new content should be created. */
088    private String m_creationSiteMap;
089
090    /** The display formatter ids. */
091    private Map<String, CmsUUID> m_displayFormatterIds;
092
093    /** The display formatter paths. */
094    private Map<String, String> m_displayFormatterPaths;
095
096    /** The editable flag. */
097    private boolean m_editable;
098
099    /** The settings parameter map. */
100    private Map<String, String> m_parameterMap;
101
102    /** The pass settings flag. */
103    private boolean m_passSettings;
104
105    /** The fully qualified class name of the post create handler to use. */
106    private String m_postCreateHandler;
107
108    /** The element settings to be used. */
109    private Map<String, String> m_settings;
110
111    /** The site path to the resource to display. */
112    private String m_value;
113
114    /**
115     * Constructor.<p>
116     */
117    public CmsJspTagDisplay() {
118
119        m_parameterMap = new LinkedHashMap<String, String>();
120        m_displayFormatterPaths = new HashMap<String, String>();
121        m_displayFormatterIds = new HashMap<String, CmsUUID>();
122    }
123
124    /**
125     * Includes the formatter rendering the given element.<p>
126     *
127     * @param element the element
128     * @param formatter the formatter configuration bean
129     * @param editable if editable
130     * @param canCreate if new resources may be created
131     * @param canDelete if the resource may be deleted
132     * @param creationSiteMap the create location sub site
133     * @param postCreateHandler the post create handler
134     * @param context the page context
135     * @param request the request
136     * @param response the response
137     */
138    public static void displayAction(
139        CmsContainerElementBean element,
140        I_CmsFormatterBean formatter,
141        boolean editable,
142        boolean canCreate,
143        boolean canDelete,
144        String creationSiteMap,
145        String postCreateHandler,
146        PageContext context,
147        ServletRequest request,
148        ServletResponse response) {
149
150        if (CmsFlexController.isCmsRequest(request)) {
151            // this will always be true if the page is called through OpenCms
152            CmsObject cms = CmsFlexController.getCmsObject(request);
153            Locale locale = cms.getRequestContext().getLocale();
154            boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject();
155            CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(request);
156            CmsContainerElementBean parentElement = contextBean.getElement();
157
158            try {
159                if (formatter != null) {
160                    element.initResource(cms);
161                    element.initSettings(cms, formatter, locale, request, null);
162                    boolean openedEditable = false;
163                    contextBean.setElement(element);
164                    if (editable && contextBean.getIsEditMode()) {
165                        if (CmsJspTagEditable.getDirectEditProvider(context) == null) {
166                            I_CmsDirectEditProvider eb = new CmsAdvancedDirectEditProvider();
167                            eb.init(cms, CmsDirectEditMode.TRUE, element.getSitePath());
168                            request.setAttribute(I_CmsDirectEditProvider.ATTRIBUTE_DIRECT_EDIT_PROVIDER, eb);
169                        }
170
171                        openedEditable = CmsJspTagEdit.insertDirectEditStart(
172                            cms,
173                            context,
174                            element.getResource(),
175                            canCreate,
176                            canDelete,
177                            null,
178                            creationSiteMap,
179                            postCreateHandler);
180                        CmsADESessionCache.getCache(
181                            (HttpServletRequest)(context.getRequest()),
182                            cms).setCacheContainerElement(element.editorHash(), element);
183                    }
184                    try {
185                        CmsJspTagInclude.includeTagAction(
186                            context,
187                            cms.getRequestContext().removeSiteRoot(formatter.getJspRootPath()),
188                            null,
189                            locale,
190                            false,
191                            isOnline,
192                            CmsRequestUtil.createParameterMap(element.getSettings()),
193                            CmsRequestUtil.getAtrributeMap(request),
194                            request,
195                            response);
196                    } catch (Exception e) {
197                        LOG.error(e.getLocalizedMessage(), e);
198                    }
199                    if (openedEditable) {
200                        CmsJspTagEdit.insertDirectEditEnd(context);
201                    }
202                }
203            } catch (CmsException e) {
204                LOG.error(e.getLocalizedMessage(), e);
205            }
206            contextBean.setElement(parentElement);
207        }
208
209    }
210
211    /**
212     * Includes the formatter rendering the given element.<p>
213     *
214     * @param element the element
215     * @param formatter the formatter configuration bean
216     * @param context the page context
217     * @param request the request
218     * @param response the response
219     */
220    public static void displayAction(
221        CmsContainerElementBean element,
222        I_CmsFormatterBean formatter,
223        PageContext context,
224        ServletRequest request,
225        ServletResponse response) {
226
227        displayAction(element, formatter, false, false, false, null, null, context, request, response);
228    }
229
230    /**
231     * Includes the formatter rendering the given element.<p>
232     *
233     * @param elementResource the element resource
234     * @param formatter the formatter configuration bean
235     * @param settings the element settings
236     * @param editable if editable
237     * @param canCreate if new resources may be created
238     * @param canDelete if the resource may be deleted
239     * @param creationSiteMap the create location sub site
240     * @param postCreateHandler the post create handler
241     * @param context the page context
242     * @param request the request
243     * @param response the response
244     */
245    public static void displayAction(
246        CmsResource elementResource,
247        I_CmsFormatterBean formatter,
248        Map<String, String> settings,
249        boolean editable,
250        boolean canCreate,
251        boolean canDelete,
252        String creationSiteMap,
253        String postCreateHandler,
254        PageContext context,
255        ServletRequest request,
256        ServletResponse response) {
257
258        CmsContainerElementBean element = new CmsContainerElementBean(
259            elementResource.getStructureId(),
260            formatter.getJspStructureId(),
261            settings,
262            false);
263        displayAction(
264            element,
265            formatter,
266            editable,
267            canCreate,
268            canDelete,
269            creationSiteMap,
270            postCreateHandler,
271            context,
272            request,
273            response);
274    }
275
276    /**
277     * Adds a display formatter.<p>
278     *
279     * @param type the resource type
280     * @param path the path to the formatter configuration file.<p>
281     */
282    public void addDisplayFormatter(String type, String path) {
283
284        m_displayFormatterPaths.put(type, path);
285    }
286
287    /**
288     * @see org.opencms.jsp.I_CmsJspTagParamParent#addParameter(java.lang.String, java.lang.String)
289     */
290    public void addParameter(String name, String value) {
291
292        // No null values allowed in parameters
293        if ((name == null) || (value == null)) {
294            return;
295        }
296
297        m_parameterMap.put(name, value);
298    }
299
300    /**
301     * @see javax.servlet.jsp.tagext.BodyTagSupport#doEndTag()
302     */
303    @Override
304    public int doEndTag() {
305
306        ServletRequest request = pageContext.getRequest();
307        ServletResponse response = pageContext.getResponse();
308        if (CmsFlexController.isCmsRequest(request)) {
309            // this will always be true if the page is called through OpenCms
310            CmsObject cms = CmsFlexController.getCmsObject(request);
311            try {
312                boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject();
313                CmsResource res = null;
314                if (CmsUUID.isValidUUID(m_value)) {
315                    CmsUUID structureId = new CmsUUID(m_value);
316                    res = isOnline
317                    ? cms.readResource(structureId)
318                    : cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
319                } else {
320                    res = isOnline
321                    ? cms.readResource(m_value)
322                    : cms.readResource(m_value, CmsResourceFilter.IGNORE_EXPIRATION);
323                }
324                I_CmsFormatterBean formatter = getFormatterForType(cms, res, isOnline);
325                Map<String, String> settings = new HashMap<String, String>();
326                String formatterId = formatter.getId();
327                int prefixLength = formatterId.length() + 1;
328                for (Entry<String, String> entry : m_parameterMap.entrySet()) {
329                    if (CmsContainerElement.ELEMENT_INSTANCE_ID.equals(entry.getKey())) {
330                        // remove any instance id to make sure to generate a unique one
331                        continue;
332                    }
333                    if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
334                        settings.put(entry.getKey(), formatter.getId());
335                    } else if (entry.getKey().startsWith(formatterId)) {
336                        settings.put(entry.getKey().substring(prefixLength), entry.getValue());
337                    } else if (!settings.containsKey(entry.getKey())) {
338                        settings.put(entry.getKey(), entry.getValue());
339                    }
340                }
341
342                displayAction(
343                    res,
344                    formatter,
345                    settings,
346                    m_editable,
347                    m_canCreate,
348                    m_canDelete,
349                    m_creationSiteMap,
350                    m_postCreateHandler,
351                    pageContext,
352                    request,
353                    response);
354            } catch (CmsException e) {
355                LOG.error(e.getLocalizedMessage(), e);
356            }
357        }
358        release();
359        return EVAL_PAGE;
360    }
361
362    /**
363     * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag()
364     */
365    @Override
366    public int doStartTag() {
367
368        if (Boolean.valueOf(m_passSettings).booleanValue()) {
369            CmsContainerElementBean element = CmsJspStandardContextBean.getInstance(
370                pageContext.getRequest()).getElement();
371            if (element != null) {
372                m_parameterMap.putAll(element.getSettings());
373            }
374        }
375        if (m_settings != null) {
376            m_parameterMap.putAll(m_settings);
377        }
378
379        return EVAL_BODY_BUFFERED;
380    }
381
382    /**
383     * Returns the editable.<p>
384     *
385     * @return the editable
386     */
387    public boolean getEditable() {
388
389        return m_editable;
390    }
391
392    /**
393     * Returns the passSettings.<p>
394     *
395     * @return the passSettings
396     */
397    public boolean getPassSettings() {
398
399        return m_passSettings;
400    }
401
402    /**
403     * Returns the element settings to be used.<p>
404     *
405     * @return the element settings to be used
406     */
407    public Map<String, String> getSettings() {
408
409        return m_settings;
410    }
411
412    /**
413     * Returns the value.<p>
414     *
415     * @return the value
416     */
417    public String getValue() {
418
419        return m_value;
420    }
421
422    /**
423     * @see javax.servlet.jsp.tagext.BodyTagSupport#release()
424     */
425    @Override
426    public void release() {
427
428        super.release();
429        m_parameterMap.clear();
430        m_displayFormatterPaths.clear();
431        m_displayFormatterIds.clear();
432        m_settings = null;
433        m_passSettings = false;
434        m_editable = false;
435        m_value = null;
436    }
437
438    /** Setter for the "create" attribute of the tag.
439     * @param canCreate value of the tag's attribute "create".
440     */
441    public void setCreate(boolean canCreate) {
442
443        m_canCreate = canCreate;
444    }
445
446    /** Setter for the "create" attribute of the tag.
447     * @param canCreate value of the tag's attribute "create".
448     */
449    public void setCreate(String canCreate) {
450
451        m_canCreate = Boolean.valueOf(canCreate).booleanValue();
452    }
453
454    /** Setter for the "creationSiteMap" attribute of the tag.
455     * @param sitePath value of the "creationSiteMap" attribute of the tag.
456     */
457    public void setCreationSiteMap(String sitePath) {
458
459        m_creationSiteMap = sitePath;
460    }
461
462    /**Setter for the "delete" attribute of the tag.
463     * @param canDelete value of the "delete" attribute of the tag.
464     */
465    public void setDelete(boolean canDelete) {
466
467        m_canDelete = canDelete;
468    }
469
470    /**Setter for the "delete" attribute of the tag.
471     * @param canDelete value of the "delete" attribute of the tag.
472     */
473    public void setDelete(String canDelete) {
474
475        m_canDelete = Boolean.valueOf(canDelete).booleanValue();
476    }
477
478    /**
479     * Sets the items.<p>
480     *
481     * @param displayFormatters the items to set
482     */
483    public void setDisplayFormatters(Object displayFormatters) {
484
485        if (displayFormatters instanceof List) {
486            for (Object formatterItem : ((List<?>)displayFormatters)) {
487                if (formatterItem instanceof CmsJspContentAccessValueWrapper) {
488                    addFormatter((CmsJspContentAccessValueWrapper)formatterItem);
489                }
490            }
491        } else if (displayFormatters instanceof CmsJspContentAccessValueWrapper) {
492            addFormatter((CmsJspContentAccessValueWrapper)displayFormatters);
493        } else if (displayFormatters instanceof String) {
494            String[] temp = ((String)displayFormatters).split(CmsXmlDisplayFormatterValue.SEPARATOR);
495            if (temp.length == 2) {
496                addDisplayFormatter(temp[0], temp[1]);
497            }
498        }
499    }
500
501    /**
502     * Sets the editable.<p>
503     *
504     * @param editable the editable to set
505     */
506    public void setEditable(boolean editable) {
507
508        m_editable = editable;
509    }
510
511    /**
512     * Sets the editable.<p>
513     *
514     * @param editable the editable to set
515     */
516    public void setEditable(String editable) {
517
518        m_editable = Boolean.valueOf(editable).booleanValue();
519    }
520
521    /**
522     * Sets the passSettings.<p>
523     *
524     * @param passSettings the passSettings to set
525     */
526    public void setPassSettings(Boolean passSettings) {
527
528        m_passSettings = passSettings.booleanValue();
529    }
530
531    /** Setter for the "postCreateHandler" attribute of the tag.
532     * @param postCreateHandler fully qualified class name of the {@link I_CmsCollectorPostCreateHandler} to use.
533     */
534    public void setPostCreateHandler(final String postCreateHandler) {
535
536        m_postCreateHandler = postCreateHandler;
537    }
538
539    /**
540     * Sets the element settings to be used.<p>
541     *
542     * @param settings the element settings to be used
543     */
544    public void setSettings(Map<String, String> settings) {
545
546        m_settings = settings;
547    }
548
549    /**
550     * Sets the value.<p>
551     *
552     * @param value the value to set
553     */
554    public void setValue(String value) {
555
556        m_value = value;
557    }
558
559    /**
560     * Adds a formatter.<p>
561     *
562     * @param formatterItem the formatter value
563     */
564    private void addFormatter(CmsJspContentAccessValueWrapper formatterItem) {
565
566        I_CmsXmlContentValue val = formatterItem.getContentValue();
567        if (val instanceof CmsXmlDisplayFormatterValue) {
568            CmsXmlDisplayFormatterValue value = (CmsXmlDisplayFormatterValue)val;
569            String type = value.getDisplayType();
570            CmsUUID formatterId = value.getFormatterId();
571            if (formatterId != null) {
572                m_displayFormatterIds.put(type, formatterId);
573            }
574        }
575    }
576
577    /**
578     * Returns the config for the requested resource, or <code>null</code> if not available.<p>
579     *
580     * @param cms the cms context
581     * @param resource the resource
582     * @param isOnline the is online flag
583     *
584     * @return the formatter configuration bean
585     */
586    private I_CmsFormatterBean getFormatterForType(CmsObject cms, CmsResource resource, boolean isOnline) {
587
588        String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
589        I_CmsFormatterBean result = null;
590        if (m_displayFormatterPaths.containsKey(typeName)) {
591            try {
592                CmsResource res = cms.readResource(m_displayFormatterPaths.get(typeName));
593                result = OpenCms.getADEManager().getCachedFormatters(isOnline).getFormatters().get(
594                    res.getStructureId());
595            } catch (CmsException e) {
596                LOG.error(e.getLocalizedMessage(), e);
597            }
598        } else if (m_displayFormatterIds.containsKey(typeName)) {
599            result = OpenCms.getADEManager().getCachedFormatters(isOnline).getFormatters().get(
600                m_displayFormatterIds.get(typeName));
601        } else {
602            CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
603                cms,
604                cms.addSiteRoot(cms.getRequestContext().getFolderUri()));
605            if (config != null) {
606                CmsFormatterConfiguration formatters = config.getFormatters(cms, resource);
607                if (formatters != null) {
608                    result = formatters.getDisplayFormatter();
609                }
610            }
611        }
612        return result;
613    }
614}