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.CmsContainerpageService;
032import org.opencms.ade.containerpage.CmsModelGroupHelper;
033import org.opencms.file.CmsObject;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.file.history.CmsHistoryResourceHandler;
037import org.opencms.file.types.CmsResourceTypeXmlContent;
038import org.opencms.file.types.I_CmsResourceType;
039import org.opencms.flex.CmsFlexController;
040import org.opencms.jsp.util.CmsJspStandardContextBean;
041import org.opencms.loader.CmsLoaderException;
042import org.opencms.main.CmsException;
043import org.opencms.main.CmsLog;
044import org.opencms.main.OpenCms;
045import org.opencms.util.CmsStringUtil;
046import org.opencms.util.CmsUUID;
047import org.opencms.xml.CmsXmlContentDefinition;
048import org.opencms.xml.containerpage.CmsADESessionCache;
049import org.opencms.xml.containerpage.CmsContainerBean;
050import org.opencms.xml.containerpage.CmsContainerElementBean;
051import org.opencms.xml.containerpage.CmsContainerPageBean;
052import org.opencms.xml.containerpage.CmsFormatterConfiguration;
053import org.opencms.xml.containerpage.CmsXmlContainerPage;
054import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
055import org.opencms.xml.containerpage.I_CmsFormatterBean;
056
057import java.io.IOException;
058import java.io.UnsupportedEncodingException;
059import java.net.URLEncoder;
060import java.util.ArrayList;
061import java.util.Collections;
062import java.util.HashMap;
063import java.util.LinkedHashMap;
064import java.util.LinkedHashSet;
065import java.util.List;
066import java.util.Map;
067import java.util.Map.Entry;
068import java.util.Set;
069
070import javax.servlet.ServletRequest;
071import javax.servlet.http.HttpServletRequest;
072import javax.servlet.jsp.JspException;
073import javax.servlet.jsp.tagext.BodyTagSupport;
074
075import org.apache.commons.logging.Log;
076
077import com.google.common.collect.Lists;
078
079/**
080 * This tag includes required CSS or JavaScript resources that are to be places in the HTML head.<p>
081 *
082 * Required resources can be configured in the resource type schema.
083 * Set attribute type to 'css' to include css resources or to 'javascript' to include JavaScript resources.<p>
084 *
085 * @since 8.0
086 */
087public class CmsJspTagHeadIncludes extends BodyTagSupport implements I_CmsJspTagParamParent {
088
089    /** The include type CSS. */
090    public static final String TYPE_CSS = "css";
091
092    /** The include type java-script. */
093    public static final String TYPE_JAVASCRIPT = "javascript";
094
095    /** The log object for this class. */
096    private static final Log LOG = CmsLog.getLog(CmsJspTagHeadIncludes.class);
097
098    /** Serial version UID required for safe serialisation. */
099    private static final long serialVersionUID = 5496349529835666345L;
100
101    /** The value of the closetags attribute. */
102    private String m_closeTags;
103
104    /** The default include resources separated by '|'. */
105    private String m_defaults;
106
107    /** The detail container type. */
108    private String m_detailType;
109
110    /** The detail container width. */
111    private String m_detailWidth;
112
113    /** Map to save parameters to the include in. */
114    private Map<String, String[]> m_parameterMap;
115
116    /** The include type. */
117    private String m_type;
118
119    /**
120     * Adds parameters to a parameter Map that can be used for a http request.<p>
121     *
122     * @param parameters the Map to add the parameters to
123     * @param name the name to add
124     * @param value the value to add
125     * @param overwrite if <code>true</code>, a parameter in the map will be overwritten by
126     *      a parameter with the same name, otherwise the request will have multiple parameters
127     *      with the same name (which is possible in http requests)
128     */
129    public static void addParameter(Map<String, String[]> parameters, String name, String value, boolean overwrite) {
130
131        // No null values allowed in parameters
132        if ((parameters == null) || (name == null) || (value == null)) {
133            return;
134        }
135
136        // Check if the parameter name (key) exists
137        if (parameters.containsKey(name) && (!overwrite)) {
138            // Yes: Check name values if value exists, if so do nothing, else add new value
139            String[] values = parameters.get(name);
140            String[] newValues = new String[values.length + 1];
141            System.arraycopy(values, 0, newValues, 0, values.length);
142            newValues[values.length] = value;
143            parameters.put(name, newValues);
144        } else {
145            // No: Add new parameter name / value pair
146            String[] values = new String[] {value};
147            parameters.put(name, values);
148        }
149    }
150
151    /**
152     * Gets the head includes for the given formatter bean.<p>
153     *
154     * @param formatter the formatter bean
155     * @param type the head include type
156     *
157     * @return the list of head includes
158     */
159    protected static List<String> getHeadIncludes(I_CmsFormatterBean formatter, String type) {
160
161        if (TYPE_CSS.equals(type)) {
162            return Lists.newArrayList(formatter.getCssHeadIncludes());
163        } else if (TYPE_JAVASCRIPT.equals(type)) {
164            return formatter.getJavascriptHeadIncludes();
165        }
166        return null;
167    }
168
169    /**
170     * Gets the inline CSS/Javascrip for the given formatter bean.<p>
171     *
172     * @param formatter the formatter bean
173     * @param type the type (CSS or Javascript)
174     *
175     * @return the inline data for the given formatter bean
176     */
177    protected static String getInlineData(I_CmsFormatterBean formatter, String type) {
178
179        if (TYPE_CSS.equals(type)) {
180            return formatter.getInlineCss();
181        } else if (TYPE_JAVASCRIPT.equals(type)) {
182            return formatter.getInlineJavascript();
183        }
184        return null;
185    }
186
187    /**
188     * @see org.opencms.jsp.I_CmsJspTagParamParent#addParameter(java.lang.String, java.lang.String)
189     */
190    public void addParameter(String name, String value) {
191
192        // No null values allowed in parameters
193        if ((name == null) || (value == null)) {
194            return;
195        }
196
197        // Check if internal map exists, create new one if not
198        if (m_parameterMap == null) {
199            m_parameterMap = new HashMap<String, String[]>();
200        }
201
202        addParameter(m_parameterMap, name, value, false);
203
204    }
205
206    /**
207     * @return <code>EVAL_PAGE</code>
208     *
209     * @see javax.servlet.jsp.tagext.Tag#doEndTag()
210     *
211     * @throws JspException by interface default
212     */
213    @Override
214    public int doEndTag() throws JspException {
215
216        ServletRequest req = pageContext.getRequest();
217        CmsFlexController controller = CmsFlexController.getController(req);
218        CmsObject cms = controller.getCmsObject();
219        try {
220            if (TYPE_CSS.equals(m_type)) {
221                tagCssAction(cms, req);
222            }
223            if (TYPE_JAVASCRIPT.equals(m_type)) {
224                tagJSAction(cms, req);
225            }
226        } catch (Exception e) {
227            throw new JspException(e);
228        } finally {
229            m_parameterMap = null;
230        }
231        return EVAL_PAGE;
232
233    }
234
235    /**
236     * Returns <code>{@link #EVAL_BODY_BUFFERED}</code>.<p>
237     *
238     * @return <code>{@link #EVAL_BODY_BUFFERED}</code>
239     *
240     * @see javax.servlet.jsp.tagext.Tag#doStartTag()
241     */
242    @Override
243    public int doStartTag() {
244
245        return EVAL_BODY_BUFFERED;
246    }
247
248    /**
249     * Returns the default include resources separated by '|'.<p>
250     *
251     * @return the default include resources
252     */
253    public String getDefaults() {
254
255        return m_defaults;
256    }
257
258    /**
259     * Returns the detail container type.<p>
260     *
261     * @return the detail container type
262     */
263    public String getDetailtype() {
264
265        return m_detailType;
266    }
267
268    /**
269     * Returns the detail container width.<p>
270     *
271     * @return the detail container width
272     */
273    public String getDetailwidth() {
274
275        return m_detailWidth;
276    }
277
278    /**
279     * Returns the type.<p>
280     *
281     * @return the type
282     */
283    public String getType() {
284
285        return m_type;
286    }
287
288    /**
289     * Sets the value of the closetags attribute.<p>
290     *
291     * @param closeTags the value of the closetags attribute
292     */
293    public void setClosetags(String closeTags) {
294
295        m_closeTags = closeTags;
296    }
297
298    /**
299     * Sets the default include resources separated by '|'.<p>
300     *
301     * @param defaults the default include resources to set
302     */
303    public void setDefaults(String defaults) {
304
305        m_defaults = defaults;
306    }
307
308    /**
309     * Sets the detail container type.<p>
310     *
311     * @param detailType the detail container type to set
312     */
313    public void setDetailtype(String detailType) {
314
315        m_detailType = detailType;
316    }
317
318    /**
319     * Sets the detail container width.<p>
320     *
321     * @param detailWidth the detail container width to set
322     */
323    public void setDetailwidth(String detailWidth) {
324
325        m_detailWidth = detailWidth;
326    }
327
328    /**
329     * Sets the type.<p>
330     *
331     * @param type the type to set
332     */
333    public void setType(String type) {
334
335        m_type = type;
336    }
337
338    /**
339     * Returns true if the headincludes tag should be closed.<p>
340     *
341     * @return true if the headincludes tag should be closed
342     */
343    public boolean shouldCloseTags() {
344
345        if (m_closeTags == null) {
346            return true;
347        }
348        return Boolean.parseBoolean(m_closeTags);
349    }
350
351    /**
352     * Action to include the CSS resources.<p>
353     *
354     * @param cms the current cms context
355     * @param req the current request
356     *
357     * @throws CmsException if something goes wrong reading the resources
358     * @throws IOException if something goes wrong writing to the response out
359     */
360    public void tagCssAction(CmsObject cms, ServletRequest req) throws CmsException, IOException {
361
362        String includeType = TYPE_CSS;
363
364        CmsJspStandardContextBean standardContext = getStandardContext(cms, req);
365        CmsContainerPageBean containerPage = standardContext.getPage();
366
367        Set<String> cssIncludes = new LinkedHashSet<String>();
368        Map<String, String> inlineCss = new LinkedHashMap<String, String>();
369        // add defaults
370        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_defaults)) {
371            String[] defaults = m_defaults.split("\\|");
372            for (int i = 0; i < defaults.length; i++) {
373                cssIncludes.add(defaults[i].trim());
374            }
375        }
376
377        collectHeadIncludesForContainerElement(
378            cms,
379            req,
380            standardContext,
381            containerPage,
382            includeType,
383            cssIncludes,
384            inlineCss);
385        if (standardContext.getDetailContentId() != null) {
386            try {
387                CmsResource detailContent = cms.readResource(
388                    standardContext.getDetailContentId(),
389                    CmsResourceFilter.ignoreExpirationOffline(cms));
390                CmsFormatterConfiguration config = OpenCms.getADEManager().lookupConfiguration(
391                    cms,
392                    cms.getRequestContext().getRootUri()).getFormatters(cms, detailContent);
393                boolean requiresAllIncludes = true;
394                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getDetailtype())
395                    && CmsStringUtil.isNotEmptyOrWhitespaceOnly(getDetailwidth())) {
396                    try {
397                        int width = Integer.parseInt(getDetailwidth());
398                        I_CmsFormatterBean formatter = config.getDetailFormatter(getDetailtype(), width);
399                        cssIncludes.addAll(formatter.getCssHeadIncludes());
400                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(formatter.getInlineCss())) {
401                            inlineCss.put(formatter.getId(), formatter.getInlineCss());
402                        }
403                        requiresAllIncludes = false;
404                    } catch (NumberFormatException ne) {
405                        // nothing to do, we will include CSS for all detail containers
406                    }
407                }
408                if (requiresAllIncludes) {
409                    for (I_CmsFormatterBean formatter : config.getDetailFormatters()) {
410                        cssIncludes.addAll(getHeadIncludes(formatter, includeType));
411                        String inlineIncludeData = getInlineData(formatter, includeType);
412                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(inlineIncludeData)) {
413                            inlineCss.put(formatter.getId(), inlineIncludeData);
414                        }
415                    }
416                }
417            } catch (CmsException e) {
418                LOG.error(
419                    Messages.get().getBundle().key(
420                        Messages.ERR_READING_REQUIRED_RESOURCE_1,
421                        standardContext.getDetailContentId()),
422                    e);
423            }
424        }
425        for (String cssUri : cssIncludes) {
426            pageContext.getOut().print(
427                "\n<link rel=\"stylesheet\" href=\""
428                    + CmsJspTagLink.linkTagAction(cssUri.trim(), req)
429                    + generateReqParams()
430                    + "\" type=\"text/css\">");
431            if (shouldCloseTags()) {
432                pageContext.getOut().print("</link>");
433            }
434        }
435        if (cms.getRequestContext().getCurrentProject().isOnlineProject()) {
436            if (!inlineCss.isEmpty()) {
437                StringBuffer inline = new StringBuffer("\n<style type=\"text/css\">\n");
438                for (Entry<String, String> cssEntry : inlineCss.entrySet()) {
439                    inline.append(cssEntry.getValue()).append("\n\n");
440                }
441                inline.append("\n</style>\n");
442                pageContext.getOut().print(inline.toString());
443            }
444        } else {
445            StringBuffer inline = new StringBuffer();
446            for (Entry<String, String> cssEntry : inlineCss.entrySet()) {
447                inline.append("\n<style type=\"text/css\" rel=\"" + cssEntry.getKey() + "\">\n");
448                inline.append(cssEntry.getValue()).append("\n\n");
449                inline.append("\n</style>\n");
450            }
451            pageContext.getOut().print(inline.toString());
452        }
453    }
454
455    /**
456     * Action to include the java-script resources.<p>
457     *
458     * @param cms the current cms context
459     * @param req the current request
460     *
461     * @throws CmsException if something goes wrong reading the resources
462     * @throws IOException if something goes wrong writing to the response out
463     */
464    public void tagJSAction(CmsObject cms, ServletRequest req) throws CmsException, IOException {
465
466        CmsJspStandardContextBean standardContext = getStandardContext(cms, req);
467        CmsContainerPageBean containerPage = standardContext.getPage();
468        String includeType = TYPE_JAVASCRIPT;
469        Set<String> jsIncludes = new LinkedHashSet<String>();
470        Map<String, String> inlineJS = new LinkedHashMap<String, String>();
471        // add defaults
472        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_defaults)) {
473            String[] defaults = m_defaults.split("\\|");
474            for (int i = 0; i < defaults.length; i++) {
475                jsIncludes.add(defaults[i].trim());
476            }
477        }
478        collectHeadIncludesForContainerElement(
479            cms,
480            req,
481            standardContext,
482            containerPage,
483            includeType,
484            jsIncludes,
485            inlineJS);
486        if (standardContext.getDetailContentId() != null) {
487            try {
488                CmsResource detailContent = cms.readResource(
489                    standardContext.getDetailContentId(),
490                    CmsResourceFilter.ignoreExpirationOffline(cms));
491                CmsFormatterConfiguration config = OpenCms.getADEManager().lookupConfiguration(
492                    cms,
493                    cms.getRequestContext().getRootUri()).getFormatters(cms, detailContent);
494                boolean requiresAllIncludes = true;
495                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getDetailtype())
496                    && CmsStringUtil.isNotEmptyOrWhitespaceOnly(getDetailwidth())) {
497                    try {
498                        int width = Integer.parseInt(getDetailwidth());
499                        I_CmsFormatterBean formatter = config.getDetailFormatter(getDetailtype(), width);
500                        jsIncludes.addAll(formatter.getJavascriptHeadIncludes());
501                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(formatter.getInlineJavascript())) {
502                            inlineJS.put(formatter.getId(), formatter.getInlineJavascript());
503                        }
504                        requiresAllIncludes = false;
505                    } catch (NumberFormatException ne) {
506                        // nothing to do, we will include JavaScript for all detail containers
507                    }
508                }
509                if (requiresAllIncludes) {
510                    for (I_CmsFormatterBean formatter : config.getDetailFormatters()) {
511                        jsIncludes.addAll(getHeadIncludes(formatter, includeType));
512                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(formatter.getInlineJavascript())) {
513                            inlineJS.put(formatter.getId(), formatter.getInlineJavascript());
514                        }
515                    }
516                }
517            } catch (CmsException e) {
518                LOG.error(
519                    Messages.get().getBundle().key(
520                        Messages.ERR_READING_REQUIRED_RESOURCE_1,
521                        standardContext.getDetailContentId()),
522                    e);
523            }
524        }
525        for (String jsUri : jsIncludes) {
526            pageContext.getOut().print(
527                "\n<script type=\"text/javascript\" src=\""
528                    + CmsJspTagLink.linkTagAction(jsUri.trim(), req)
529                    + generateReqParams()
530                    + "\"></script>");
531        }
532        if (!inlineJS.isEmpty()) {
533            StringBuffer inline = new StringBuffer();
534            for (Entry<String, String> jsEntry : inlineJS.entrySet()) {
535                inline.append("\n<script type=\"text/javascript\">\n");
536                inline.append(jsEntry.getValue()).append("\n\n");
537                inline.append("\n</script>\n");
538            }
539            pageContext.getOut().print(inline.toString());
540        }
541    }
542
543    /**
544     * Collects the head includes for a given container element.<p>
545     *
546     * @param cms the current CMS context
547     * @param req the current request
548     * @param standardContext the current standard context
549     * @param containerPage the current container page
550     * @param includeType the type of head includes (CSS or Javascript)
551     * @param headincludes the set to which normal head includes should be added
552     * @param inline the map to which inline head includes should be added
553     */
554    protected void collectHeadIncludesForContainerElement(
555        CmsObject cms,
556        ServletRequest req,
557        CmsJspStandardContextBean standardContext,
558        CmsContainerPageBean containerPage,
559        String includeType,
560        Set<String> headincludes,
561        Map<String, String> inline) {
562
563        CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
564            cms,
565            cms.getRequestContext().getRootUri());
566        if ((containerPage != null) && (containerPage.getElements() != null)) {
567            Map<CmsUUID, I_CmsFormatterBean> formatters = OpenCms.getADEManager().getCachedFormatters(
568                standardContext.getIsOnlineProject()).getFormatters();
569            List<CmsContainerBean> containers = new ArrayList<CmsContainerBean>(containerPage.getContainers().values());
570            // add detail only containers if available
571            if (standardContext.isDetailRequest()) {
572                CmsContainerPageBean detailOnly = CmsJspTagContainer.getDetailOnlyPage(cms, req);
573                if (detailOnly != null) {
574                    containers.addAll(detailOnly.getContainers().values());
575                }
576            }
577            for (CmsContainerBean container : containers) {
578                for (CmsContainerElementBean element : container.getElements()) {
579                    try {
580                        element.initResource(cms);
581                        if (!standardContext.getIsOnlineProject()
582                            || element.getResource().isReleasedAndNotExpired(
583                                cms.getRequestContext().getRequestTime())) {
584                            if (element.isGroupContainer(cms) || element.isInheritedContainer(cms)) {
585                                List<CmsContainerElementBean> subElements;
586                                if (element.isGroupContainer(cms)) {
587                                    subElements = CmsJspTagContainer.getGroupContainerElements(
588                                        cms,
589                                        element,
590                                        req,
591                                        container.getType());
592                                } else {
593                                    subElements = CmsJspTagContainer.getInheritedContainerElements(cms, element);
594                                }
595                                for (CmsContainerElementBean subElement : subElements) {
596                                    subElement.initResource(cms);
597                                    if (!standardContext.getIsOnlineProject()
598                                        || subElement.getResource().isReleasedAndNotExpired(
599                                            cms.getRequestContext().getRequestTime())) {
600                                        I_CmsFormatterBean formatter = getFormatterBeanForElement(
601                                            cms,
602                                            config,
603                                            subElement,
604                                            container,
605                                            false,
606                                            formatters);
607                                        if (formatter != null) {
608                                            headincludes.addAll(getHeadIncludes(formatter, includeType));
609                                            String inlineIncludeData = getInlineData(formatter, includeType);
610                                            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(inlineIncludeData)) {
611                                                inline.put(formatter.getId(), inlineIncludeData);
612                                            }
613                                        } else {
614
615                                            headincludes.addAll(
616                                                getSchemaHeadIncludes(cms, subElement.getResource(), includeType));
617                                        }
618                                    }
619                                }
620                            } else {
621                                I_CmsFormatterBean formatter = getFormatterBeanForElement(
622                                    cms,
623                                    config,
624                                    element,
625                                    container,
626                                    true,
627                                    formatters);
628                                if (formatter != null) {
629                                    headincludes.addAll(getHeadIncludes(formatter, includeType));
630                                    String inlineIncludeData = getInlineData(formatter, includeType);
631                                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(inlineIncludeData)) {
632                                        inline.put(formatter.getId(), inlineIncludeData);
633                                    }
634                                } else {
635
636                                    headincludes.addAll(getSchemaHeadIncludes(cms, element.getResource(), includeType));
637                                }
638                            }
639                        }
640                    } catch (CmsException e) {
641                        LOG.error(
642                            Messages.get().getBundle().key(
643                                Messages.ERR_READING_REQUIRED_RESOURCE_1,
644                                element.getSitePath()),
645                            e);
646                    }
647                }
648            }
649        }
650    }
651
652    /**
653     * Generates the request parameter string.<p>
654     *
655     * @return the request parameter string
656     *
657     * @throws UnsupportedEncodingException if something goes wrong encoding the request parameters
658     */
659    private String generateReqParams() throws UnsupportedEncodingException {
660
661        String params = "";
662        if ((m_parameterMap != null) && !m_parameterMap.isEmpty()) {
663            for (Entry<String, String[]> paramEntry : m_parameterMap.entrySet()) {
664                if (paramEntry.getValue() != null) {
665                    for (int i = 0; i < paramEntry.getValue().length; i++) {
666                        params += "&"
667                            + paramEntry.getKey()
668                            + "="
669                            + URLEncoder.encode(paramEntry.getValue()[i], "UTF-8");
670                    }
671                }
672            }
673            params = "?" + params.substring(1);
674        }
675        return params;
676    }
677
678    /**
679     * Returns the schema configured CSS head include resources.<p>
680     *
681     * @param cms the current cms context
682     * @param resource the resource
683     *
684     * @return the configured CSS head include resources
685     */
686    private Set<String> getCSSHeadIncludes(CmsObject cms, CmsResource resource) {
687
688        if (CmsResourceTypeXmlContent.isXmlContent(resource)) {
689            try {
690                CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.getContentDefinitionForResource(
691                    cms,
692                    resource);
693                return contentDefinition.getContentHandler().getCSSHeadIncludes(cms, resource);
694            } catch (CmsException e) {
695                LOG.warn(e.getLocalizedMessage(), e);
696                // NOOP, use the empty set
697            }
698        }
699        return Collections.emptySet();
700    }
701
702    /**
703     * Returns the formatter configuration for the given element, will return <code>null</code> for schema formatters.<p>
704     *
705     * @param cms the current CMS context
706     * @param config the current sitemap configuration
707     * @param element the element bean
708     * @param container the container bean
709     * @param allowNested if nested containers are allowed
710     * @param formatters the formatter map
711     *
712     * @return the formatter configuration bean
713     */
714    private I_CmsFormatterBean getFormatterBeanForElement(
715        CmsObject cms,
716        CmsADEConfigData config,
717        CmsContainerElementBean element,
718        CmsContainerBean container,
719        boolean allowNested,
720        Map<CmsUUID, I_CmsFormatterBean> formatters) {
721
722        int containerWidth = -1;
723        if (container.getWidth() == null) {
724            // the container width has not been set yet
725            containerWidth = CmsFormatterConfiguration.MATCH_ALL_CONTAINER_WIDTH;
726        } else {
727            try {
728
729                containerWidth = Integer.parseInt(container.getWidth());
730            } catch (NumberFormatException e) {
731                // do nothing, set width to -1
732            }
733        }
734        I_CmsFormatterBean result = CmsJspTagContainer.getFormatterConfigurationForElement(
735            cms,
736            element,
737            config,
738            container.getName(),
739            container.getType(),
740            containerWidth,
741            allowNested);
742        return result;
743    }
744
745    /**
746     * Returns the schema configured JavaScript head include resources.<p>
747     *
748     * @param cms the current cms context
749     * @param resource the resource
750     *
751     * @return the configured JavaScript head include resources
752     *
753     * @throws CmsLoaderException if something goes wrong reading the resource type
754     */
755    private Set<String> getJSHeadIncludes(CmsObject cms, CmsResource resource) throws CmsLoaderException {
756
757        I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(resource.getTypeId());
758        if (resType instanceof CmsResourceTypeXmlContent) {
759            try {
760                CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.getContentDefinitionForResource(
761                    cms,
762                    resource);
763                return contentDefinition.getContentHandler().getJSHeadIncludes(cms, resource);
764            } catch (CmsException e) {
765                LOG.warn(e.getLocalizedMessage(), e);
766                // NOOP, use the empty set
767            }
768        }
769        return Collections.emptySet();
770    }
771
772    /**
773     * Gets the head includes of a resource from the content definition.<p>
774     *
775     * @param cms the current CMS context
776     * @param res the resource for which the head includes should be fetched
777     * @param type the head include type (CSS or Javascript)
778     *
779     * @return the set of schema head includes
780     *
781     * @throws CmsLoaderException if something goes wrong
782     */
783    private Set<String> getSchemaHeadIncludes(CmsObject cms, CmsResource res, String type) throws CmsLoaderException {
784
785        if (type.equals(TYPE_CSS)) {
786            return getCSSHeadIncludes(cms, res);
787        } else if (type.equals(TYPE_JAVASCRIPT)) {
788            return getJSHeadIncludes(cms, res);
789        }
790        return null;
791    }
792
793    /**
794     * Returns the standard context bean.<p>
795     *
796     * @param cms the current cms context
797     * @param req the current request
798     *
799     * @return the standard context bean
800     *
801     * @throws CmsException if something goes wrong
802     */
803    private CmsJspStandardContextBean getStandardContext(CmsObject cms, ServletRequest req) throws CmsException {
804
805        String requestUri = cms.getRequestContext().getUri();
806        CmsJspStandardContextBean standardContext = CmsJspStandardContextBean.getInstance(req);
807        CmsContainerPageBean containerPage = standardContext.getPage();
808        if (containerPage == null) {
809            // get the container page itself, checking the history first
810            CmsResource pageResource = (CmsResource)CmsHistoryResourceHandler.getHistoryResource(req);
811            if (pageResource == null) {
812                pageResource = cms.readResource(requestUri);
813            }
814            CmsXmlContainerPage xmlContainerPage = CmsXmlContainerPageFactory.unmarshal(cms, pageResource, req);
815            containerPage = xmlContainerPage.getContainerPage(cms);
816            CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
817                cms,
818                OpenCms.getADEManager().lookupConfiguration(cms, cms.getRequestContext().getRootUri()),
819                CmsJspTagEditable.isEditableRequest(req)
820                ? CmsADESessionCache.getCache((HttpServletRequest)(pageContext.getRequest()), cms)
821                : null,
822                CmsContainerpageService.isEditingModelGroups(cms, pageResource));
823            containerPage = modelHelper.readModelGroups(xmlContainerPage.getContainerPage(cms));
824            standardContext.setPage(containerPage);
825        }
826        return standardContext;
827    }
828
829}