001/*
002 *  Copyright 2015 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.cms.search.model;
017
018import java.util.Collection;
019import java.util.Collections;
020import java.util.Map;
021
022import org.apache.avalon.framework.configuration.Configuration;
023import org.apache.solr.common.SolrInputDocument;
024import org.xml.sax.ContentHandler;
025import org.xml.sax.SAXException;
026
027import org.ametys.cms.contenttype.MetadataType;
028import org.ametys.cms.repository.Content;
029import org.ametys.cms.search.SearchField;
030import org.ametys.cms.search.query.Query;
031import org.ametys.cms.search.query.Query.Operator;
032import org.ametys.cms.search.solr.schema.SchemaDefinition;
033import org.ametys.plugins.repository.metadata.MultilingualString;
034import org.ametys.runtime.i18n.I18nizableText;
035import org.ametys.runtime.parameter.Enumerator;
036
037/**
038 * Represents a universal property of a {@link Content} (content types, language, current workflow step, ...)
039 */
040public interface SystemProperty
041{
042    
043    /**
044     * Get the system property ID.
045     * @return The property ID.
046     */
047    String getId();
048    
049    /**
050     * Get the system property label.
051     * @return The property label.
052     */
053    I18nizableText getLabel();
054    
055    /**
056     * Get the system property description.
057     * @return The property description.
058     */
059    I18nizableText getDescription();
060    
061    /**
062     * Get the property type.
063     * @return the property type.
064     */
065    MetadataType getType();
066    
067    /**
068     * Get the multiple status of the property.
069     * @return <code>true</code> if the property can have multiple values, <code>false</code> otherwise.
070     */
071    boolean isMultiple();
072    
073    /**
074     * Get the definition of an enumerator.
075     * @param configuration The enumerator configuration.
076     * @return The enumerator definition or null if the property is not enumerated.
077     */
078    default EnumeratorDefinition getEnumeratorDefinition(Configuration configuration)
079    {
080        // Default null, override to set an enumerator.
081        return null;
082    }
083    
084    /**
085     * In case of a Content reference field, the content type ID.
086     * @return the content type ID.
087     */
088    default String getContentTypeId()
089    {
090        return null;
091    }
092    
093    /**
094     * Get if the property can be searched on (i.e. used in a SearchCriterion).
095     * @return <code>true</code> if the property can be searched on, <code>false</code> otherwise.
096     */
097    default boolean isSearchable()
098    {
099        // Default to true: override when the property is not searchable.
100        return true;
101    }
102    
103    /**
104     * Get if the property can be displayed (i.e. used in a ResultField).
105     * @return <code>true</code> if the property can be displayed, <code>false</code> otherwise.
106     */
107    default boolean isDisplayable()
108    {
109        // Default to true: override when the property is not displayable.
110        return true;
111    }
112    
113    /**
114     * Get if the property can be sorted on.
115     * @return <code>true</code> if the property can be sorted on, <code>false</code> otherwise.
116     */
117    default boolean isSortable()
118    {
119        // Default to true: override when the property is not sortable.
120        return true;
121    }
122    
123    /**
124     * Gets if the property can be facetable
125     * @return <code>true</code> if the property can be facetable, <code>false</code> otherwise.
126     */
127    default boolean isFacetable()
128    {
129        SearchField searchField = getSearchField();
130        return searchField != null ? searchField.getFacetField() != null : false;
131    }
132    
133    /**
134     * Get the {@link Query} associated to the given value.
135     * @param value the user-submitted value for this property.
136     * @param operator In advanced search mode, the operator chosen by the user. <code>null</code> to use the criterion-defined operator (simple search mode).
137     * @param language The current search language.
138     * @param contextualParameters the search contextual parameters.
139     * @return The {@link Query} associated to the given value.
140     */
141    Query getQuery(Object value, Operator operator, String language, Map<String, Object> contextualParameters);
142    
143    /**
144     * Get the default widget to use when rendering this property as a criterion.
145     * @return The default widget to use, or <code>null</code> if no specific widget is necessary.
146     */
147    default String getWidget()
148    {
149        return null;
150    }
151    
152    /**
153     * Get the widget parameters.
154     * @param configuration The system property configuration
155     * @return The widget parameters as a Map.
156     */
157    default Map<String, I18nizableText> getWidgetParameters(Configuration configuration)
158    {
159        return Collections.emptyMap();
160    }
161    
162    /**
163     * Get the renderer.
164     * @return The column renderer.
165     */
166    default String getRenderer()
167    {
168        return null;
169    }
170    
171    /**
172     * Get the property column converter.
173     * @return The property column converter.
174     */
175    default String getConverter()
176    {
177        return null;
178    }
179    
180    /**
181     * Get the column width.
182     * @return the default column width, can be null.
183     */
184    default Integer getColumnWidth()
185    {
186        return null;
187    }
188    
189    /**
190     * Index the system property in a solr document.
191     * @param content The content to index.
192     * @param document The solr document to index into.
193     */
194    void index(Content content, SolrInputDocument document);
195    
196//    /**
197//     * Get the name of the field to use when indexing this property.
198//     * @return The field name.
199//     */
200//    String getField();
201    
202    /**
203     * Get the {@link SearchField} representing this system property.
204     * @return The search field representing this system property.
205     */
206    SearchField getSearchField();
207    
208    /**
209     * Get the typed raw value for this field in the given result content.
210     * The returned object depends on this field's type:<br>
211     * - {@link MetadataType#STRING} must return String or String[] if multiple<br>
212     * - {@link MetadataType#DATE} or {@link MetadataType#DATETIME} must return Date or Date[] if multiple<br>
213     * - {@link MetadataType#LONG} must return Long or Long[] if multiple<br>
214     * - {@link MetadataType#DOUBLE} must return Double or Double[] if multiple<br>
215     * - {@link MetadataType#CONTENT} must return String or String[] if multiple<br>
216     * - {@link MetadataType#GEOCODE} must return Map&lt;String, Double&gt;<br>
217     * - {@link MetadataType#USER} must return UserIdentity or UserIdentity[] if multiple<br>
218     * - {@link MetadataType#MULTILINGUAL_STRING} must return {@link MultilingualString}<br>
219     * Others types are not supported.
220     * @param content The result content
221     * @return The typed value, cast to the appropriate object according its type.
222     */
223    Object getValue(Content content);
224    
225    /**
226     * Get the jsonified value 
227     * @param content the result content
228     * @param full <code>true</code> to get full value.
229     * @return the content field value
230     */
231    default Object getJsonValue(Content content, boolean full)
232    {
233        return getValue(content);
234    }
235    
236    /**
237     * SAX the value
238     * @param handler The content handler to sax into
239     * @param content The content
240     * @throws SAXException If an error occurred while saxing
241     */
242    void saxValue(ContentHandler handler, Content content) throws SAXException;
243    
244    /**
245     * Get the sort value represented by this field in the given result content.
246     * @param content the result content.
247     * @return the content sort value, must be scalar (String, long, double, Date).
248     */
249    default Object getSortValue(Content content)
250    {
251        // No sortable by default;
252        return null;
253    }
254    
255    /**
256     * Get the schema definitions brought by this property.
257     * @return The schema definitions used by this property.
258     */
259    Collection<SchemaDefinition> getSchemaDefinitions();
260    
261    /**
262     * Representation of an Enumerator, used to generate an Enumerator on the fly.
263     */
264    class EnumeratorDefinition
265    {
266        
267        private boolean _isStatic;
268        
269        private Class<? extends Enumerator> _enumeratorClass;
270        
271        private Configuration _configuration;
272        
273        private Map<String, I18nizableText> _staticEntries;
274        
275        /**
276         * Build a definition representing a dynamic Enumerator.
277         * @param enumeratorClass The enumerator class.
278         * @param configuration The enumerator configuration.
279         */
280        public EnumeratorDefinition(Class<? extends Enumerator> enumeratorClass, Configuration configuration)
281        {
282            this._enumeratorClass = enumeratorClass;
283            this._configuration = configuration;
284            this._isStatic = false;
285        }
286        
287        /**
288         * Build a definition representing a static Enumerator.
289         * @param staticEntries the enumerator entries.
290         */
291        public EnumeratorDefinition(Map<String, I18nizableText> staticEntries)
292        {
293            this._staticEntries = staticEntries;
294            this._isStatic = true;
295        }
296        
297        public boolean isStatic()
298        {
299            return _isStatic;
300        }
301        
302        public Class<? extends Enumerator> getEnumeratorClass()
303        {
304            return _enumeratorClass;
305        }
306        
307        public Configuration getConfiguration()
308        {
309            return _configuration;
310        }
311        
312        public Map<String, I18nizableText> getStaticEntries()
313        {
314            return Collections.unmodifiableMap(_staticEntries);
315        }
316        
317    }
318    
319}