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.xml.types;
029
030import org.opencms.file.CmsObject;
031import org.opencms.i18n.CmsEncoder;
032import org.opencms.loader.CmsImageScaler;
033import org.opencms.main.CmsIllegalArgumentException;
034import org.opencms.util.CmsRequestUtil;
035import org.opencms.util.CmsStringUtil;
036import org.opencms.xml.I_CmsXmlDocument;
037
038import java.util.HashMap;
039import java.util.Locale;
040import java.util.Map;
041
042import org.dom4j.Element;
043
044/**
045 * Describes the XML content type "OpenCmsVfsImage".<p>
046 *
047 * This type allows links to internal VFS images only.<p>
048 *
049 * @since 7.5.0
050 */
051public class CmsXmlVfsImageValue extends CmsXmlVfsFileValue {
052
053    /** Node name for the scale element. */
054    public static final String NODE_SCALE = "scale";
055
056    /** Request parameter name for the description parameter. */
057    public static final String PARAM_DESCRIPTION = "description";
058
059    /** Request parameter name for the format parameter. */
060    public static final String PARAM_FORMAT = "format";
061
062    /** The name of this type as used in the XML schema. */
063    public static final String TYPE_NAME_IMAGE = "OpenCmsVfsImage";
064
065    /** The schema definition String is located in a text for easier editing. */
066    private static String m_schemaDefinition;
067
068    /** The description text of the image. */
069    private String m_description;
070
071    /** The selected image format. */
072    private String m_format;
073
074    /** Holds the parameters of the URL. */
075    private Map<String, String[]> m_parameters;
076
077    /** The scale options of the image. */
078    private String m_scaleOptions;
079
080    /**
081     * Creates a new, empty schema type descriptor of type "OpenCmsVfsImage".<p>
082     */
083    public CmsXmlVfsImageValue() {
084
085        // empty constructor is required for class registration
086    }
087
088    /**
089     * Creates a new XML content value of type "OpenCmsVfsImage".<p>
090     *
091     * @param document the XML content instance this value belongs to
092     * @param element the XML element that contains this value
093     * @param locale the locale this value is created for
094     * @param type the type instance to create the value for
095     */
096    public CmsXmlVfsImageValue(I_CmsXmlDocument document, Element element, Locale locale, I_CmsXmlSchemaType type) {
097
098        super(document, element, locale, type);
099    }
100
101    /**
102     * Creates a new schema type descriptor for the type "OpenCmsVfsImage".<p>
103     *
104     * @param name the name of the XML node containing the value according to the XML schema
105     * @param minOccurs minimum number of occurrences of this type according to the XML schema
106     * @param maxOccurs maximum number of occurrences of this type according to the XML schema
107     */
108    public CmsXmlVfsImageValue(String name, String minOccurs, String maxOccurs) {
109
110        super(name, minOccurs, maxOccurs);
111    }
112
113    /**
114     * @see org.opencms.xml.types.A_CmsXmlContentValue#createValue(I_CmsXmlDocument, org.dom4j.Element, Locale)
115     */
116    @Override
117    public I_CmsXmlContentValue createValue(I_CmsXmlDocument document, Element element, Locale locale) {
118
119        return new CmsXmlVfsImageValue(document, element, locale, this);
120    }
121
122    /**
123     * Returns the description of the image.<p>
124     *
125     * @param cms the current users context
126     * @return the description of the image or an empty String
127     */
128    public String getDescription(CmsObject cms) {
129
130        if (m_description == null) {
131            if (m_element.element(PARAM_DESCRIPTION) != null) {
132                m_description = m_element.element(PARAM_DESCRIPTION).getText();
133            }
134            if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_description)) {
135                m_description = getParameterValue(cms, PARAM_DESCRIPTION);
136                m_description = CmsEncoder.unescape(m_description, CmsEncoder.ENCODING_UTF_8);
137            }
138        }
139        return m_description;
140    }
141
142    /**
143     * Returns the format information of the image.<p>
144     *
145     * @param cms the current users context
146     * @return the format information of the image or an empty String
147     */
148    public String getFormat(CmsObject cms) {
149
150        if (m_format == null) {
151            if (m_element.element(PARAM_FORMAT) != null) {
152                m_format = m_element.element(PARAM_FORMAT).getText();
153            }
154            if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_format)) {
155                m_format = getParameterValue(cms, PARAM_FORMAT);
156            }
157        }
158        return m_format;
159    }
160
161    /**
162     * Returns the link without parameters from the string value.<p>
163     *
164     * @param cms the current users context
165     * @return the link without parameters
166     */
167    public String getRequestLink(CmsObject cms) {
168
169        return CmsRequestUtil.getRequestLink(getStringValue(cms));
170    }
171
172    /**
173     * Returns the scale options of the image.<p>
174     *
175     * @param cms the current users context
176     * @return the scale options of the image or an empty String
177     */
178    public String getScaleOptions(CmsObject cms) {
179
180        if (m_scaleOptions == null) {
181            if (m_element.element(NODE_SCALE) != null) {
182                m_scaleOptions = m_element.element(NODE_SCALE).getText();
183            }
184            if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_scaleOptions)) {
185                m_scaleOptions = getParameterValue(cms, CmsImageScaler.PARAM_SCALE);
186            }
187        }
188        return m_scaleOptions;
189    }
190
191    /**
192     * @see org.opencms.xml.types.I_CmsXmlSchemaType#getSchemaDefinition()
193     */
194    @Override
195    public String getSchemaDefinition() {
196
197        // the schema definition is located in a separate file for easier editing
198        if (m_schemaDefinition == null) {
199            m_schemaDefinition = readSchemaDefinition("org/opencms/xml/types/XmlVfsImageValue.xsd");
200        }
201        return m_schemaDefinition;
202    }
203
204    /**
205     * @see org.opencms.xml.types.A_CmsXmlContentValue#getTypeName()
206     */
207    @Override
208    public String getTypeName() {
209
210        return TYPE_NAME_IMAGE;
211    }
212
213    /**
214     * @see org.opencms.xml.types.A_CmsXmlContentValue#newInstance(java.lang.String, java.lang.String, java.lang.String)
215     */
216    @Override
217    public I_CmsXmlSchemaType newInstance(String name, String minOccurs, String maxOccurs) {
218
219        return new CmsXmlVfsImageValue(name, minOccurs, maxOccurs);
220    }
221
222    /**
223     * Sets the description of the image.<p>
224     *
225     * @param cms the current users context
226     * @param description the description of the image
227     */
228    public void setDescription(CmsObject cms, String description) {
229
230        if (CmsStringUtil.isEmptyOrWhitespaceOnly(description)) {
231            m_description = "";
232            if (m_element.element(PARAM_DESCRIPTION) != null) {
233                m_element.remove(m_element.element(PARAM_DESCRIPTION));
234            }
235        } else {
236            m_description = description;
237            description = CmsEncoder.escapeWBlanks(description, CmsEncoder.ENCODING_UTF_8);
238        }
239        setParameterValue(cms, PARAM_DESCRIPTION, description);
240    }
241
242    /**
243     * Sets the format information of the image.<p>
244     *
245     * @param cms the current users contexts
246     * @param format the format information of the image
247     */
248    public void setFormat(CmsObject cms, String format) {
249
250        if (CmsStringUtil.isEmptyOrWhitespaceOnly(format)) {
251            m_format = "";
252            if (m_element.element(PARAM_FORMAT) != null) {
253                m_element.remove(m_element.element(PARAM_FORMAT));
254            }
255        } else {
256            m_format = format;
257        }
258        setParameterValue(cms, PARAM_FORMAT, format);
259    }
260
261    /**
262     * Sets the scale options of the image.<p>
263     *
264     * @param cms the current users context
265     * @param scaleOptions the scale options of the image
266     */
267    public void setScaleOptions(CmsObject cms, String scaleOptions) {
268
269        if (CmsStringUtil.isEmptyOrWhitespaceOnly(scaleOptions)) {
270            m_scaleOptions = "";
271            if (m_element.element(NODE_SCALE) != null) {
272                m_element.remove(m_element.element(NODE_SCALE));
273            }
274        } else {
275            m_scaleOptions = scaleOptions;
276        }
277        setParameterValue(cms, CmsImageScaler.PARAM_SCALE, scaleOptions);
278    }
279
280    /**
281     * @see org.opencms.xml.types.A_CmsXmlContentValue#setStringValue(org.opencms.file.CmsObject, java.lang.String)
282     */
283    @Override
284    public void setStringValue(CmsObject cms, String value) throws CmsIllegalArgumentException {
285
286        // call the super implementation to set the value
287        super.setStringValue(cms, value);
288        if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) {
289            // no valid value given
290            return;
291        }
292
293        // get the request parameters from the provided value
294        Map<String, String[]> params = getParameterMap(value);
295
296        // create description element if present as parameter
297        String desc = getParameterValue(cms, params, PARAM_DESCRIPTION);
298        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(desc)) {
299            desc = CmsEncoder.unescape(desc, CmsEncoder.ENCODING_UTF_8);
300            m_element.addElement(PARAM_DESCRIPTION).addCDATA(desc);
301        }
302        // create format name element if present as parameter
303        String format = getParameterValue(cms, params, PARAM_FORMAT);
304        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(format)) {
305            m_element.addElement(PARAM_FORMAT).addCDATA(format);
306        }
307        // create scale element if present as parameter
308        String scale = getParameterValue(cms, params, CmsImageScaler.PARAM_SCALE);
309        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(scale)) {
310            m_element.addElement(NODE_SCALE).addCDATA(scale);
311        }
312        // reset the parameter map
313        m_parameters = null;
314        // reset the members containing the element values
315        m_format = null;
316        m_description = null;
317        m_scaleOptions = null;
318    }
319
320    /**
321     * Returns the parameters as Map from the given url String.<p>
322     *
323     * @param url the url String to get the parameters from
324     * @return the parameters as Map
325     */
326    private Map<String, String[]> getParameterMap(String url) {
327
328        Map<String, String[]> result = new HashMap<String, String[]>();
329        if (CmsStringUtil.isNotEmpty(url)) {
330            int pos = url.indexOf(CmsRequestUtil.URL_DELIMITER);
331            if (pos >= 0) {
332                result = CmsRequestUtil.createParameterMap(url.substring(pos + 1));
333            }
334        }
335        return result;
336    }
337
338    /**
339     * Returns the value of the given parameter name from a parameter map.<p>
340     *
341     * @param cms the current users context
342     * @param parameterMap the map containing the parameters
343     * @param key the parameter name
344     * @return the value of the parameter or an empty String
345     */
346    private String getParameterValue(CmsObject cms, Map<String, String[]> parameterMap, String key) {
347
348        String result = null;
349        String[] params = parameterMap.get(key);
350        if ((params != null) && (params.length > 0)) {
351            result = params[0];
352        }
353        if (result == null) {
354            return "";
355        }
356        return result;
357    }
358
359    /**
360     * Returns the value of the given parameter name from the current parameter map.<p>
361     *
362     * @param cms the current users context
363     * @param key the parameter name
364     * @return the value of the parameter or an empty String
365     */
366    private String getParameterValue(CmsObject cms, String key) {
367
368        if (m_parameters == null) {
369            m_parameters = getParameterMap(getStringValue(cms));
370        }
371        return getParameterValue(cms, m_parameters, key);
372    }
373
374    /**
375     * Sets a parameter for the image with the provided key as name and the value.<p>
376     *
377     * @param cms the current users context
378     * @param key the parameter name to set
379     * @param value the value of the parameter
380     */
381    private void setParameterValue(CmsObject cms, String key, String value) {
382
383        if (m_parameters == null) {
384            m_parameters = getParameterMap(getStringValue(cms));
385        }
386        if (CmsStringUtil.isEmptyOrWhitespaceOnly(value) && m_parameters.containsKey(key)) {
387            m_parameters.remove(key);
388        } else if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(value)) {
389            m_parameters.put(key, new String[] {value});
390        }
391        String result = CmsRequestUtil.getRequestLink(getStringValue(cms));
392        result = CmsRequestUtil.appendParameters(result, m_parameters, false);
393        setStringValue(cms, result);
394    }
395
396}