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 GmbH & Co. KG, 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.file.CmsProperty;
031import org.opencms.flex.CmsFlexController;
032import org.opencms.i18n.CmsLocaleManager;
033import org.opencms.jsp.decorator.CmsHtmlDecorator;
034import org.opencms.jsp.decorator.I_CmsDecoratorConfiguration;
035import org.opencms.main.CmsLog;
036import org.opencms.util.CmsStringUtil;
037
038import java.util.Iterator;
039import java.util.List;
040import java.util.Locale;
041
042import javax.servlet.ServletRequest;
043import javax.servlet.jsp.JspException;
044import javax.servlet.jsp.tagext.BodyTagSupport;
045
046import org.apache.commons.logging.Log;
047
048/**
049 * Implements the <code>&lt;cms:decorate&gt;&lt;/cms:decorate&gt;</code>
050 * tag to decorate HTML content with configurated decoration maps.<p>
051 *
052 * @since 6.1.3
053 */
054public class CmsJspTagDecorate extends BodyTagSupport {
055
056    /** The name of the default decorator configuration. */
057    public static final String DEFAULT_DECORATOR_CONFIGURATION = "org.opencms.jsp.decorator.CmsDecoratorConfiguration";
058
059    /** The property to store the decorator classname .*/
060    public static final String PROPERTY_CATEGORY = "category";
061
062    /** The log object for this class. */
063    private static final Log LOG = CmsLog.getLog(CmsJspTagDecorate.class);
064
065    /** Serial version UID required for safe serialization. */
066    private static final long serialVersionUID = 3072561342127379294L;
067
068    /** Indicates the parse action should be disabled to allow inline editing in the container page editor. */
069    private boolean m_allowInlineEdit;
070
071    /** The configuration. */
072    private String m_file;
073
074    /** The decoration locale. */
075    private String m_locale;
076
077    /** List of upper case tag name strings of tags that should not be auto-corrected if closing divs are missing. */
078    private List<String> m_noAutoCloseTags;
079
080    /**
081     * Internal action method.<p>
082     *
083     * DEcorates a HTMl content block.<p>
084     *
085     * @param content the content to be decorated
086     * @param configFile the config file
087     * @param locale the locale to use for decoration or NOLOCALE if not locale should be used
088     * @param req the current request
089     *
090     * @return the decorated content
091     */
092    public String decorateTagAction(String content, String configFile, String locale, ServletRequest req) {
093
094        try {
095            Locale loc = null;
096            CmsFlexController controller = CmsFlexController.getController(req);
097            if (CmsStringUtil.isEmpty(locale)) {
098                loc = controller.getCmsObject().getRequestContext().getLocale();
099            } else {
100                loc = CmsLocaleManager.getLocale(locale);
101            }
102
103            // read the decorator configurator class
104            CmsProperty decoratorClass = controller.getCmsObject().readPropertyObject(
105                configFile,
106                PROPERTY_CATEGORY,
107                false);
108            String decoratorClassName = decoratorClass.getValue();
109            if (CmsStringUtil.isEmpty(decoratorClassName)) {
110                decoratorClassName = DEFAULT_DECORATOR_CONFIGURATION;
111            }
112
113            String encoding = controller.getCmsObject().getRequestContext().getEncoding();
114            // use the correct decorator configurator and initialize it
115            I_CmsDecoratorConfiguration config = (I_CmsDecoratorConfiguration)Class.forName(
116                decoratorClassName).newInstance();
117            config.init(controller.getCmsObject(), configFile, loc);
118
119            CmsHtmlDecorator decorator = new CmsHtmlDecorator(controller.getCmsObject(), config);
120
121            decorator.setNoAutoCloseTags(m_noAutoCloseTags);
122            return decorator.doDecoration(content, encoding);
123        } catch (Exception e) {
124            if (LOG.isErrorEnabled()) {
125                LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "decoration"), e);
126            }
127            return content;
128        }
129    }
130
131    /**
132     * @see javax.servlet.jsp.tagext.Tag#doEndTag()
133     * @return EVAL_PAGE
134     * @throws JspException in case something goes wrong
135     */
136    @Override
137    public int doEndTag() throws JspException {
138
139        ServletRequest req = pageContext.getRequest();
140        if (m_allowInlineEdit && CmsJspTagEditable.isEditableRequest(req)) {
141            // during inline editing the content should not be parsed
142            try {
143                getBodyContent().writeOut(pageContext.getOut());
144                release();
145            } catch (Exception ex) {
146                release();
147                if (LOG.isErrorEnabled()) {
148                    LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "decoration"), ex);
149                }
150                // this is severe
151                throw new JspException(ex);
152            }
153        } else {
154            // This will always be true if the page is called through OpenCms
155            if (CmsFlexController.isCmsRequest(req)) {
156                try {
157                    String content = decorateTagAction(getBodyContent().getString(), getFile(), getLocale(), req);
158                    getBodyContent().clear();
159                    getBodyContent().print(content);
160                    getBodyContent().writeOut(pageContext.getOut());
161
162                } catch (Exception ex) {
163                    if (LOG.isErrorEnabled()) {
164                        LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "decoration"), ex);
165                    }
166                    throw new JspException(ex);
167                }
168            }
169        }
170        return EVAL_PAGE;
171    }
172
173    /**
174     * Returns the file name.<p>
175     *
176     * @return the file name
177     */
178    public String getFile() {
179
180        return m_file;
181    }
182
183    /**
184     * Returns the locale name.<p>
185     *
186     * @return the locale name
187     */
188    public String getLocale() {
189
190        return m_locale;
191    }
192
193    /**
194     * Getter for the attribute "noAutoCloseTags" of the &lt;cms:parse&gt; tag.<p>
195     *
196     * Returns a <code>String</code> that consists of the comma-separated upper case tag names for which this
197     * tag will not correct missing closing tags. <p>
198     *
199     *
200     * @return a String that consists of the comma-separated upper case tag names for which this
201     *      tag will not correct missing closing tags.
202     */
203    public String getNoAutoCloseTags() {
204
205        StringBuffer result = new StringBuffer();
206        if ((m_noAutoCloseTags != null) && (m_noAutoCloseTags.size() > 0)) {
207            Iterator<String> it = m_noAutoCloseTags.iterator();
208            while (it.hasNext()) {
209                result.append(it.next()).append(',');
210            }
211        }
212        return result.toString();
213    }
214
215    /**
216     * Returns if the parse action should be disabled to allow inline editing in the container page editor.<p>
217     *
218     * @return <code>true</code> if the parse action should be disabled to allow inline editing in the container page editor
219     */
220    public boolean isAllowInlineEdit() {
221
222        return m_allowInlineEdit;
223    }
224
225    /**
226     * Sets if the parse action should be disabled to allow inline editing in the container page editor.<p>
227     *
228     * @param allowInlineEdit <code>true</code> to allow inline editing
229     */
230    public void setAllowInlineEdit(boolean allowInlineEdit) {
231
232        m_allowInlineEdit = allowInlineEdit;
233    }
234
235    /**
236     * Sets the file name.<p>
237     *
238     * @param file the file name
239     */
240    public void setFile(String file) {
241
242        if (file != null) {
243            m_file = file.toLowerCase();
244        } else {
245            m_file = null;
246        }
247    }
248
249    /**
250     * Sets the locale name.<p>
251     *
252     * @param locale the locale name
253     */
254    public void setLocale(String locale) {
255
256        m_locale = locale;
257    }
258
259    /**
260     * Setter for the attribute "noAutoCloseTags" of the &lt;cms:parse&gt; tag.<p>
261     *
262     * Awaits a <code>String</code> that consists of the comma-separated upper case tag names for which this
263     * tag should not correct missing closing tags.<p>
264     *
265     * @param noAutoCloseTagList a <code>String</code> that consists of the comma-separated upper case tag names for which this
266     *      tag should not correct missing closing tags.
267     */
268    public void setNoAutoCloseTags(String noAutoCloseTagList) {
269
270        m_noAutoCloseTags = CmsStringUtil.splitAsList(noAutoCloseTagList, ',');
271
272    }
273}