001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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.file.CmsResource;
032import org.opencms.file.types.CmsResourceTypeXmlContent;
033import org.opencms.xml.I_CmsXmlDocument;
034
035import java.util.Locale;
036
037import org.dom4j.Element;
038
039/**
040 * Provides access to the value of a specific XML content node.<p>
041 *
042 * @since 6.0.0
043 */
044public interface I_CmsXmlContentValue extends I_CmsXmlSchemaType {
045
046    /**
047     * Search content configuration for the value.
048     * The configuration determines how the conent's value should be added to the indexed content fields.
049     */
050    public static class CmsSearchContentConfig {
051
052        /** Configuration for not adding the value to the content fields. */
053        public static final CmsSearchContentConfig FALSE = new CmsSearchContentConfig(SearchContentType.FALSE, null);
054        /** Configuration for adding the extraction of the content linked by the value to the content fields. */
055        public static final CmsSearchContentConfig CONTENT = new CmsSearchContentConfig(
056            SearchContentType.CONTENT,
057            null);
058        /** Configuration for triggering re-indexing if the resource linked by the value to the content fields changes. */
059        public static final CmsSearchContentConfig UPDATE = new CmsSearchContentConfig(
060            SearchContentType.UPDATE,
061            null);
062        /** Configuration for adding the value unchanged to the content fields. */
063        public static final CmsSearchContentConfig TRUE = new CmsSearchContentConfig(SearchContentType.TRUE, null);
064        /** The search content type. */
065        private SearchContentType m_type;
066        /** The adjustment implementation for the value. */
067        private String m_adjustmentClass;
068
069        /**
070         * Constructs a new search content configuration.
071         * @param type the search content type
072         * @param adjustmentClass the adjustment implementation
073         */
074        private CmsSearchContentConfig(SearchContentType type, String adjustmentClass) {
075
076            m_type = type;
077            m_adjustmentClass = adjustmentClass;
078        }
079
080        /**
081         * Returns a flag, indicating if the the re-index relation should be added.
082         * @param config the search content config
083         * @return true, iff the re-indexing relation should be added.
084         */
085        public static boolean addReIndexRelation(CmsSearchContentConfig config) {
086
087            return null == config ? false : SearchContentType.addReIndexRelation(config.getSearchContentType());
088        }
089
090        /**
091         * Returns the configuration for the search content type.
092         * @param searchContentType the type to get the configuration for
093         * @return the configuration for the type
094         */
095        public static CmsSearchContentConfig get(SearchContentType searchContentType) {
096
097            return get(searchContentType, null);
098        }
099
100        /**
101         * Returns the configuration for the combination of search content type and adjustment class.
102         * @param searchContentType the type to get the configuration for
103         * @param adjustmentClass the adjustment class
104         * @return the configuration for the type/adjustment combination.
105         */
106        public static CmsSearchContentConfig get(SearchContentType searchContentType, String adjustmentClass) {
107
108            if (searchContentType == null) {
109                return adjustmentClass == null
110                ? null
111                : new CmsSearchContentConfig(SearchContentType.TRUE, adjustmentClass);
112            }
113            switch (searchContentType) {
114                case FALSE:
115                    return FALSE;
116                case TRUE:
117                    return adjustmentClass == null
118                    ? TRUE
119                    : new CmsSearchContentConfig(SearchContentType.TRUE, adjustmentClass);
120                case CONTENT:
121                    return CONTENT;
122                case UPDATE:
123                    return UPDATE;
124                default:
125                    return null;
126            }
127        }
128
129        /**
130         * @return the adjustment class.
131         */
132        public String getAdjustmentClass() {
133
134            return m_adjustmentClass;
135        }
136
137        /**
138         * @return the search content type.
139         */
140        public SearchContentType getSearchContentType() {
141
142            return m_type;
143        }
144
145        /**
146         * Checks if the re-index relation can be added for resources of the provided type.
147         * @param res the resource to add the relation to.
148         * @return true, iff the relation can be added.
149         */
150        public boolean isResourceSuitableForReIndexRelation(CmsResource res) {
151
152            switch (getSearchContentType()) {
153                case CONTENT:
154                    return CmsResourceTypeXmlContent.isXmlContent(res);
155                default:
156                    return true;
157            }
158        }
159    }
160
161    /**
162     * The available search types for element searchsetting.
163     */
164    public static enum SearchContentType {
165
166        /** Do not merge the value of the field into the content field. */
167        FALSE,
168        /** Merge the value of the field into the content field. */
169        TRUE,
170        /** Merge the extracted content of the resource linked by the element into the content field. */
171        CONTENT,
172        /** Do not merge the value of the field into the content field, but re-index if the resource linked in this field changed. */
173        UPDATE;
174
175        /**
176         * Returns a flag, indicating if the the re-index relation should be added.
177         * @param type the search content type
178         * @return true, iff the re-indexing relation should be added.
179         */
180        public static boolean addReIndexRelation(SearchContentType type) {
181
182            if (null == type) {
183                return false;
184            }
185            switch (type) {
186                case CONTENT:
187                case UPDATE:
188                    return true;
189                default:
190                    return false;
191            }
192        }
193
194        /**
195         * Converts the String into a SearchContentType. Returns <code>null</code> if conversion is not possible.
196         * @param type the search content type as String.
197         * @return the search content type specified by the provided String, or <code>null</code> if the String did not specify any search content type.
198         */
199        public static SearchContentType fromString(String type) {
200
201            if (null == type) {
202                return null;
203            }
204            switch (type.toLowerCase()) {
205                case "false":
206                    return FALSE;
207                case "true":
208                    return TRUE;
209                case "content":
210                    return CONTENT;
211                case "update":
212                    return UPDATE;
213                default:
214                    return null;
215            }
216        }
217    }
218
219    /**
220     * Returns the XML content instance this value belongs to.<p>
221     *
222     * @return the XML content instance this value belongs to
223     */
224    I_CmsXmlDocument getDocument();
225
226    /**
227     * Returns the original XML element of this XML content value.<p>
228     *
229     * @return the original XML element of this XML content value
230     */
231    Element getElement();
232
233    /**
234     * Returns the node index of this XML content value in the source XML document,
235     * starting with 0, with special handling of elements in choice groups.<p>
236     *
237     * This is useful in case there are more than one elements
238     * with the same XML node name in the source XML document.<p>
239     *
240     * Elements in XML choice groups will share the same number space, so a choice
241     * sequence will be numbered like this:
242     * <code>Title[1], Text[2], Title[3], Image[4]</code><p>
243     *
244     * @return the index of this XML content node in the source document with special handling of elements in choice groups
245     *
246     * @see #getXmlIndex()
247     */
248    int getIndex();
249
250    /**
251     * Returns the locale of this XML content value was generated for.<p>
252     *
253     * @return the locale of this XML content value was generated for
254     */
255    Locale getLocale();
256
257    /**
258     * Returns the total number of XML elements of this type that currently exist in the source document.<p>
259     *
260     * @return the total number of XML elements of this type that currently exist in the source document
261     */
262    int getMaxIndex();
263
264    /**
265     * Returns the path of this XML content value in the source document.<p>
266     *
267     * @return the path of this XML content value in the source document
268     */
269    String getPath();
270
271    /**
272     * Returns the value of this XML content node as a plain text String.<p>
273     *
274     * Plain text in this context means a pure textual representation
275     * of the content (i.e. without html tags).
276     * The plain text may be <code>null</code>, too, if there is no sound or useful
277     * textual representation (i.e. color values).<p>
278     *
279     * @param cms an initialized instance of a CmsObject
280     *
281     * @return the value of this XML content node as a plain text String
282     */
283    String getPlainText(CmsObject cms);
284
285    /**
286     * Returns the search content type for the value. Default implementation uses the historic isSearchable() method.
287     * @return the search content type
288     */
289    default CmsSearchContentConfig getSearchContentConfig() {
290
291        return new CmsSearchContentConfig(isSearchable() ? SearchContentType.TRUE : SearchContentType.FALSE, null);
292    }
293
294    /**
295     * Returns the value of this XML content node as a String.<p>
296     *
297     * @param cms an initialized instance of a CmsObject
298     *
299     * @return the value of this XML content node as a String
300     */
301    String getStringValue(CmsObject cms);
302
303    /**
304     * Returns the node index of this XML content value in the source XML document,
305     * starting with 0, based on the XML ordering.<p>
306     *
307     * Elements in choice groups will be numbered like this:
308     * <code>Title[1], Text[1], Title[2], Image[1]</code><p>
309     *
310     * @return the index of this XML content node in the source document with special handling of elements in choice groups
311     *
312     * @see #getIndex()
313     */
314    int getXmlIndex();
315
316    /**
317     * Returns <code>true</code> in case this value is searchable by default with
318     * the integrated full text search.<p>
319     *
320     * @return <code>true</code> in case this value is searchable by default
321     */
322    boolean isSearchable();
323
324    /**
325     * Moves this XML content value one position down in the source document, if possible.<p>
326     *
327     * If the XML content value is already the first in it's sequence, it is not moved.<p>
328     */
329    void moveDown();
330
331    /**
332     * Moves this XML content value one position up in the source document, if possible.<p>
333     *
334     * If the XML content value is already the last in it's sequence, it is not moved.<p>
335     */
336    void moveUp();
337
338    /**
339     * Sets the provided String as value of this XML content node.<p>
340     *
341     * This method does provide processing of the content based on the
342     * users current OpenCms context. This can be used e.g. for link
343     * extraction and replacement in the content.<p>
344     *
345     * @param cms an initialized instance of a CmsObject
346     * @param value the value to set
347     *
348     */
349    void setStringValue(CmsObject cms, String value);
350}