001/*
002 *  Copyright 2010 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.plugins.repository.query;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.List;
021
022import org.ametys.plugins.repository.RepositoryConstants;
023
024/**
025 * A sort criteria allows to sort query results.<br>
026 * Warning : methods of this class support a boolean "normalize" which suppose that the patch at https://issues.apache.org/jira/browse/JCR-3443 has been applied.
027 */
028public class SortCriteria
029{
030    private List<SortCriterion> _criteria = new ArrayList<>();
031
032    /**
033     * Add a sort criteria to the criteria list, using a metadata name. <br>
034     * Order of adding is important. First added has more weight during sort.
035     * @param metadataPath The name of the metadata to sort, or the path to the metadata if composite
036     * @param ascending The order for sorting results
037     * @param normalize <code>true</code> to normalize string properties (remove accents and lower case) 
038     */
039    public void addCriterion(String metadataPath, boolean ascending, boolean normalize)
040    {
041        _criteria.add(new SortCriterion(metadataPath, null, ascending, normalize));
042    }
043
044    /**
045     * Add a sort criteria to the criteria list, using a JCR property name. <br>
046     *  Order of adding is important. First added has more weight during sort.
047     * @param jcrProperty The name of the JCR property to sort
048     * @param ascending The order for sorting results
049     * @param normalize <code>true</code> to normalize string properties (remove accents and lower case) 
050     */
051    public void addJCRPropertyCriterion(String jcrProperty, boolean ascending, boolean normalize)
052    {
053        _criteria.add(new SortCriterion(null, jcrProperty, ascending, normalize));
054    }
055    
056    /**
057     * Get the criteria.
058     * @return an unmodifiable view of the criteria list.
059     */
060    public List<SortCriterion> getCriteria()
061    {
062        return Collections.unmodifiableList(_criteria);
063    }
064    
065    /**
066     * Build the criteria.
067     * @return The formal view of the criteria.
068     */
069    public String build()
070    {
071        if (_criteria.isEmpty())
072        {
073            return "";
074        }
075
076        StringBuffer exp = new StringBuffer("order by ");
077        for (int i = 0; i < _criteria.size(); i++)
078        {
079            if (i != 0)
080            {
081                exp.append(", ");
082            }
083            
084            SortCriterion criterion = _criteria.get(i);
085            
086            exp.append(criterion.build());
087        }
088        
089        return exp.toString();
090    }
091    
092    /**
093     * A sort criterion.
094     */
095    public class SortCriterion
096    {
097        
098        /** The metadata path. */
099        protected String _metadataPath;
100        
101        /** The JCR property. */
102        protected String _jcrProperty;
103        
104        /** True if the sort is made in ascending order, false otherwise. */
105        protected boolean _ascending;
106        
107        /** True to sort on normalized versions of the properties, false otherwise. */
108        protected boolean _normalize;
109        
110        /**
111         * Build a sort criterion.
112         * @param metadataPath the metadata path (can be null if a JCR property is provided).
113         * @param jcrProperty the JCR property (can be null if a metadata path is provided).
114         * @param ascending true to sort in ascending order, false otherwise.
115         * @param normalize true to sort on normalized properties, false otherwise.
116         */
117        public SortCriterion(String metadataPath, String jcrProperty, boolean ascending, boolean normalize)
118        {
119            this._metadataPath = metadataPath;
120            this._jcrProperty = jcrProperty;
121            this._ascending = ascending;
122            this._normalize = normalize;
123        }
124        
125        /**
126         * Get the metadataPath.
127         * @return the metadataPath
128         */
129        public String getMetadataPath()
130        {
131            return _metadataPath;
132        }
133        
134        /**
135         * Set the metadataPath.
136         * @param metadataPath the metadataPath to set
137         */
138        public void setMetadataPath(String metadataPath)
139        {
140            this._metadataPath = metadataPath;
141        }
142        
143        /**
144         * Get the jcrProperty.
145         * @return the jcrProperty
146         */
147        public String getJcrProperty()
148        {
149            return _jcrProperty;
150        }
151        
152        /**
153         * Set the jcrProperty.
154         * @param jcrProperty the jcrProperty to set
155         */
156        public void setJcrProperty(String jcrProperty)
157        {
158            this._jcrProperty = jcrProperty;
159        }
160        
161        /**
162         * Test if the results are to be sorted in ascending order.
163         * @return true to sort in ascending order, false otherwise.
164         */
165        public boolean isAscending()
166        {
167            return _ascending;
168        }
169        
170        /**
171         * Set the criterion to sort in ascending order.
172         * @param ascending true to sort in ascending order, false otherwise.
173         */
174        public void setAscending(boolean ascending)
175        {
176            this._ascending = ascending;
177        }
178        
179        /**
180         * Test if the results are to be sorted in normalized form.
181         * @return true to sort in normalized form, false otherwise.
182         */
183        public boolean isNormalizedSort()
184        {
185            return _normalize;
186        }
187        
188        /**
189         * Set the criterion to sort in normalized form.
190         * @param normalize true to sort in normalized form, false otherwise.
191         */
192        public void setNormalize(boolean normalize)
193        {
194            this._normalize = normalize;
195        }
196        
197        /**
198         * Build an XPath order string representing the criterion.
199         * @return an XPath order string.
200         */
201        public String build()
202        {
203            StringBuilder buff = new StringBuilder();
204            
205            String ascending = _ascending ? "ascending" : "descending";
206            
207            if (_metadataPath != null)
208            {
209                String metadata = "";
210                String[] path = _metadataPath.split("/");
211                for (int j = 0; j < path.length; j++)
212                {
213                    if (j == (path.length - 1))
214                    {
215                        metadata += "@" + RepositoryConstants.NAMESPACE_PREFIX + ':' + path[j];
216                    }
217                    else
218                    {
219                        metadata += RepositoryConstants.NAMESPACE_PREFIX + ':' + path[j] + "/";
220                    }
221                }
222                if (_normalize)
223                {
224                    buff.append("rep:normalize(" + metadata + ") " + ascending);
225                }
226                else
227                {
228                    buff.append(metadata + " " + ascending);
229                }
230            }
231            else
232            {
233                if (_normalize)
234                {
235                    buff.append("rep:normalize(@" + _jcrProperty + ") " + ascending);
236                }
237                else
238                {
239                    buff.append("@" + _jcrProperty + " " + ascending);
240                }
241            }
242            
243            return buff.toString();
244        }
245        
246    }
247    
248}