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