1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.extension.repository.internal

File RepositoryUtils.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart8.png
54% of files have more coverage

Code metrics

52
83
16
1
380
189
44
0.53
5.19
16
2.75

Classes

Class Line # Actions
RepositoryUtils 46 83 0% 44 34
0.7748344577.5%
 

Contributing tests

This file is covered by 16 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.extension.repository.internal;
21   
22    import java.util.ArrayList;
23    import java.util.Collection;
24    import java.util.Collections;
25    import java.util.LinkedHashSet;
26    import java.util.List;
27    import java.util.regex.Pattern;
28   
29    import org.apache.commons.lang3.StringUtils;
30    import org.xwiki.extension.Extension;
31    import org.xwiki.extension.internal.converter.ExtensionIdConverter;
32    import org.xwiki.extension.repository.result.AggregatedIterableResult;
33    import org.xwiki.extension.repository.result.CollectionIterableResult;
34    import org.xwiki.extension.repository.result.IterableResult;
35    import org.xwiki.extension.repository.search.ExtensionQuery;
36    import org.xwiki.extension.repository.search.ExtensionQuery.COMPARISON;
37    import org.xwiki.extension.repository.search.ExtensionQuery.Filter;
38    import org.xwiki.extension.repository.search.ExtensionQuery.SortClause;
39   
40    /**
41    * A set of Repository related tools.
42    *
43    * @version $Id: eb45b3482e57f94a66c5fe3f3f3344e3aa6cf0e0 $
44    * @since 4.0M2
45    */
 
46    public final class RepositoryUtils
47    {
48    /**
49    * The suffix and prefix to add to the regex when searching for a core extension.
50    */
51    public static final String SEARCH_PATTERN_SUFFIXNPREFIX = ".*";
52   
53    /**
54    * Utility class.
55    */
 
56  0 toggle private RepositoryUtils()
57    {
58    }
59   
60    /**
61    * @param pattern the pattern to match
62    * @param offset the offset where to start returning elements
63    * @param nb the number of maximum element to return
64    * @param extensions the extension collection to search in
65    * @return the search result
66    * @param <E> the type of element in the {@link Collection}
67    */
 
68  0 toggle public static <E extends Extension> CollectionIterableResult<E> searchInCollection(String pattern, int offset,
69    int nb, Collection<E> extensions)
70    {
71  0 return searchInCollection(pattern, offset, nb, extensions, false);
72    }
73   
74    /**
75    * @param pattern the pattern to match
76    * @param offset the offset where to start returning elements
77    * @param nb the number of maximum element to return
78    * @param extensions the extension collection to search in
79    * @param forceUnique make sure returned elements are unique
80    * @return the search result
81    * @since 6.4.1
82    * @param <E> the type of element in the {@link Collection}
83    */
 
84  6 toggle public static <E extends Extension> CollectionIterableResult<E> searchInCollection(String pattern, int offset,
85    int nb, Collection<E> extensions, boolean forceUnique)
86    {
87  6 ExtensionQuery query = new ExtensionQuery(pattern);
88   
89  6 query.setOffset(offset);
90  6 query.setLimit(nb);
91   
92  6 return searchInCollection(query, extensions, forceUnique);
93    }
94   
95    /**
96    * @param query the query
97    * @param extensions the extension collection to search in
98    * @param forceUnique make sure returned elements are unique
99    * @return the search result
100    * @since 7.0M2
101    * @param <E> the type of element in the {@link Collection}
102    */
 
103  6 toggle public static <E extends Extension> CollectionIterableResult<E> searchInCollection(ExtensionQuery query,
104    Collection<E> extensions, boolean forceUnique)
105    {
106  6 List<E> result;
107   
108    // Filter
109  6 if (StringUtils.isEmpty(query.getQuery())) {
110  0 result = extensions instanceof List ? (List<E>) extensions : new ArrayList<E>(extensions);
111    } else {
112  6 result = filter(query.getQuery(), query.getFilters(), extensions, forceUnique);
113    }
114   
115    // Sort
116  6 sort(result, query.getSortClauses());
117   
118    // Create result
119  6 return RepositoryUtils.getIterableResult(query.getOffset(), query.getLimit(), result);
120    }
121   
122    /**
123    * @param offset the offset where to start returning elements
124    * @param nb the number of maximum element to return
125    * @param elements the element collection to search in
126    * @return the result to limit
127    * @param <E> the type of element in the {@link Collection}
128    */
 
129  61 toggle public static <E> CollectionIterableResult<E> getIterableResult(int offset, int nb, Collection<E> elements)
130    {
131  61 if (nb == 0 || offset >= elements.size()) {
132  8 return new CollectionIterableResult<E>(elements.size(), offset, Collections.<E>emptyList());
133    }
134   
135  53 List<E> list;
136  53 if (elements instanceof List) {
137  44 list = (List<E>) elements;
138    } else {
139  9 list = new ArrayList<E>(elements);
140    }
141   
142  53 return getIterableResultFromList(offset, nb, list);
143    }
144   
145    /**
146    * @param offset the offset where to start returning elements
147    * @param nb the number of maximum element to return
148    * @param elements the element collection to search in
149    * @return the result to limit
150    * @param <E> the type of element in the {@link List}
151    */
 
152  53 toggle private static <E> CollectionIterableResult<E> getIterableResultFromList(int offset, int nb, List<E> elements)
153    {
154  53 int fromIndex = offset;
155  53 if (fromIndex < 0) {
156  4 fromIndex = 0;
157    }
158   
159  53 int toIndex;
160  53 if (nb > 0) {
161  24 toIndex = nb + fromIndex;
162  24 if (toIndex > elements.size()) {
163  10 toIndex = elements.size();
164    }
165    } else {
166  29 toIndex = elements.size();
167    }
168   
169  53 return new CollectionIterableResult<E>(elements.size(), offset, elements.subList(fromIndex, toIndex));
170    }
171   
172    /**
173    * @param pattern the pattern to match
174    * @param filters the filters
175    * @param extensions the extension collection to search in
176    * @param forceUnique make sure returned elements are unique
177    * @return the filtered list of extensions
178    * @since 7.0M2
179    * @param <E> the type of element in the {@link Collection}
180    */
 
181  6 toggle private static <E extends Extension> List<E> filter(String pattern, Collection<Filter> filters,
182    Collection<E> extensions, boolean forceUnique)
183    {
184  6 List<E> result = new ArrayList<E>(extensions.size());
185   
186  6 Pattern patternMatcher =
187    Pattern.compile(SEARCH_PATTERN_SUFFIXNPREFIX + pattern.toLowerCase() + SEARCH_PATTERN_SUFFIXNPREFIX);
188   
189  6 for (E extension : extensions) {
190  2446 if (matches(patternMatcher, filters, extension)) {
191  61 result.add(extension);
192    }
193    }
194   
195    // Make sure all the elements of the list are unique
196  6 if (forceUnique && result.size() > 1) {
197  5 result = new ArrayList<>(new LinkedHashSet<>(result));
198    }
199   
200  6 return result;
201    }
202   
203    /**
204    * Matches an extension in a case insensitive way.
205    *
206    * @param patternMatcher the pattern to match
207    * @param filters the filters
208    * @param extension the extension to match
209    * @return false if one of the filter is not matching the extension
210    * @since 7.0M2
211    */
 
212  2944 toggle public static boolean matches(Pattern patternMatcher, Collection<Filter> filters, Extension extension)
213    {
214  2944 if (matches(patternMatcher, extension.getId().getId(), extension.getDescription(), extension.getSummary(),
215    extension.getName(), ExtensionIdConverter.toStringList(extension.getExtensionFeatures()))) {
216  508 for (Filter filter : filters) {
217  72 if (!matches(filter, extension)) {
218  65 return false;
219    }
220    }
221   
222  443 return true;
223    }
224   
225  2436 return false;
226    }
227   
228    /**
229    * Make sure the passed extension matches all filters.
230    *
231    * @param filters the filters
232    * @param extension the extension to match
233    * @return false if one of the filter is not matching the extension
234    * @since 8.3RC1
235    */
 
236  0 toggle public static boolean matches(Collection<Filter> filters, Extension extension)
237    {
238  0 if (filters != null) {
239  0 for (Filter filter : filters) {
240  0 if (!matches(filter, extension)) {
241  0 return false;
242    }
243    }
244    }
245   
246  0 return true;
247    }
248   
249    /**
250    * @param filter the filter
251    * @param extension the extension to match
252    * @return true if the extension is matched by the filer
253    * @since 7.0M2
254    */
 
255  72 toggle public static boolean matches(Filter filter, Extension extension)
256    {
257  72 return matches(filter, extension.<Object>get(filter.getField()));
258    }
259   
260    /**
261    * @param filter the filter
262    * @param element the element to match
263    * @return true if the element is matched by the filer
264    * @since 7.0M2
265    */
 
266  72 toggle public static boolean matches(Filter filter, Object element)
267    {
268  72 if (element == null) {
269  15 return filter.getValue() == null;
270  57 } else if (filter.getValue() == null) {
271  0 return false;
272    }
273   
274    // TODO: add support for more than String
275  57 String filterValue = String.valueOf(filter.getValue());
276  57 String elementValue = String.valueOf(element);
277   
278  57 if (filter.getComparison() == COMPARISON.MATCH) {
279  15 Pattern patternMatcher = createPatternMatcher(filterValue);
280   
281  15 if (matches(patternMatcher, elementValue)) {
282  3 return true;
283    }
284  42 } else if (filter.getComparison() == COMPARISON.EQUAL) {
285  42 if (filterValue.equals(elementValue)) {
286  4 return true;
287    }
288    }
289   
290  50 return false;
291    }
292   
293    /**
294    * Matches a set of elements in a case insensitive way.
295    *
296    * @param patternMatcher the pattern to match
297    * @param elements the elements to match
298    * @return true if one of the element is matched
299    */
 
300  2944 toggle public static boolean matches(Pattern patternMatcher, Object... elements)
301    {
302  2944 if (patternMatcher == null) {
303  402 return true;
304    }
305   
306  2542 for (Object element : elements) {
307  12394 if (matches(patternMatcher, element)) {
308  106 return true;
309    }
310    }
311   
312  2436 return false;
313    }
314   
315    /**
316    * @param patternMatcher the pattern to match
317    * @param element the element to match with the pattern
318    * @return true of the element is matched by the pattern
319    */
 
320  12409 toggle public static boolean matches(Pattern patternMatcher, Object element)
321    {
322  12409 if (element != null) {
323  9567 if (patternMatcher.matcher(element.toString().toLowerCase()).matches()) {
324  109 return true;
325    }
326    }
327   
328  12300 return false;
329    }
330   
331    /**
332    * @param pattern the pattern to match
333    * @return a {@link Pattern} used to search the passed pattern inside a {@link String}
334    */
 
335  61 toggle public static Pattern createPatternMatcher(String pattern)
336    {
337  61 return StringUtils.isEmpty(pattern) ? null : Pattern.compile(RepositoryUtils.SEARCH_PATTERN_SUFFIXNPREFIX
338    + Pattern.quote(pattern.toLowerCase()) + RepositoryUtils.SEARCH_PATTERN_SUFFIXNPREFIX);
339    }
340   
341    /**
342    * Sort the passed extensions list based on the passed sort clauses.
343    *
344    * @param extensions the list of extensions to sort
345    * @param sortClauses the sort clauses
346    * @since 7.0M2
347    */
 
348  52 toggle public static void sort(List<? extends Extension> extensions, Collection<SortClause> sortClauses)
349    {
350  52 Collections.sort(extensions, new SortClauseComparator(sortClauses));
351    }
352   
353    /**
354    * Merge provided search results.
355    *
356    * @param previousSearchResult all the previous search results
357    * @param result the new search result to append
358    * @return the new aggregated search result
359    * @since 8.1M1
360    * @param <E> the type of element in the {@link Collection}
361    */
 
362  0 toggle public static <E extends Extension> IterableResult<E> appendSearchResults(IterableResult<E> previousSearchResult,
363    IterableResult<E> result)
364    {
365  0 AggregatedIterableResult<E> newResult;
366   
367  0 if (previousSearchResult instanceof AggregatedIterableResult) {
368  0 newResult = ((AggregatedIterableResult<E>) previousSearchResult);
369  0 } else if (previousSearchResult != null) {
370  0 newResult = new AggregatedIterableResult<E>(previousSearchResult.getOffset());
371  0 newResult.addSearchResult(previousSearchResult);
372    } else {
373  0 return result;
374    }
375   
376  0 newResult.addSearchResult(result);
377   
378  0 return newResult;
379    }
380    }