001
014
015 package com.liferay.portal.kernel.search;
016
017 import com.liferay.portal.kernel.dao.orm.QueryUtil;
018 import com.liferay.portal.kernel.dao.search.SearchPaginationUtil;
019 import com.liferay.portal.kernel.util.ArrayUtil;
020 import com.liferay.portal.kernel.util.GetterUtil;
021 import com.liferay.portal.kernel.util.PropsKeys;
022 import com.liferay.portal.kernel.util.PropsUtil;
023 import com.liferay.portal.kernel.util.SetUtil;
024 import com.liferay.portal.kernel.util.Time;
025
026 import java.util.ArrayList;
027 import java.util.Collections;
028 import java.util.List;
029 import java.util.Set;
030
031
034 public abstract class BaseSearchResultPermissionFilter
035 implements SearchResultPermissionFilter {
036
037 @Override
038 public Hits search(SearchContext searchContext) throws SearchException {
039 QueryConfig queryConfig = searchContext.getQueryConfig();
040
041 if (!queryConfig.isAllFieldsSelected()) {
042 Set<String> selectedFieldNameSet = SetUtil.fromArray(
043 queryConfig.getSelectedFieldNames());
044
045 Collections.addAll(
046 selectedFieldNameSet, _PERMISSION_SELECTED_FIELD_NAMES);
047
048 queryConfig.setSelectedFieldNames(
049 selectedFieldNameSet.toArray(
050 new String[selectedFieldNameSet.size()]));
051 }
052
053 int end = searchContext.getEnd();
054 int start = searchContext.getStart();
055
056 if ((end == QueryUtil.ALL_POS) && (start == QueryUtil.ALL_POS)) {
057 Hits hits = getHits(searchContext);
058
059 if (!isGroupAdmin(searchContext)) {
060 filterHits(hits, searchContext);
061 }
062
063 return hits;
064 }
065
066 if ((start < 0) || (start > end)) {
067 return new HitsImpl();
068 }
069
070 if (isGroupAdmin(searchContext)) {
071 return getHits(searchContext);
072 }
073
074 double amplificationFactor = 1.0;
075 int excludedDocsSize = 0;
076 int hitsSize = 0;
077 int offset = 0;
078 long startTime = 0;
079
080 List<Document> documents = new ArrayList<>();
081 List<Float> scores = new ArrayList<>();
082
083 while (true) {
084 int count = end - documents.size();
085
086 int amplifiedCount = (int)Math.ceil(count * amplificationFactor);
087
088 int amplifiedEnd = offset + amplifiedCount;
089
090 searchContext.setEnd(amplifiedEnd);
091 searchContext.setStart(offset);
092
093 Hits hits = getHits(searchContext);
094
095 if (startTime == 0) {
096 hitsSize = hits.getLength();
097 startTime = hits.getStart();
098 }
099
100 Document[] oldDocs = hits.getDocs();
101
102 filterHits(hits, searchContext);
103
104 Document[] newDocs = hits.getDocs();
105
106 excludedDocsSize += oldDocs.length - newDocs.length;
107
108 collectHits(hits, documents, scores, count);
109
110 if ((newDocs.length >= count) ||
111 (oldDocs.length < amplifiedCount) ||
112 (amplifiedEnd >= hitsSize)) {
113
114 updateHits(
115 hits, documents, scores, start, end,
116 hitsSize - excludedDocsSize, startTime);
117
118 return hits;
119 }
120
121 offset = amplifiedEnd;
122
123 amplificationFactor = _getAmplificationFactor(
124 documents.size(), offset);
125 }
126 }
127
128 protected void collectHits(
129 Hits hits, List<Document> documents, List<Float> scores, int count) {
130
131 Document[] docs = hits.getDocs();
132
133 if (docs.length < count) {
134 count = docs.length;
135 }
136
137 for (int i = 0; i < count; i++) {
138 documents.add(docs[i]);
139
140 scores.add(hits.score(i));
141 }
142 }
143
144 protected abstract void filterHits(Hits hits, SearchContext searchContext);
145
146 protected abstract Hits getHits(SearchContext searchContext)
147 throws SearchException;
148
149 protected abstract boolean isGroupAdmin(SearchContext searchContext);
150
151 protected void updateHits(
152 Hits hits, List<Document> documents, List<Float> scores, int start,
153 int end, int size, long startTime) {
154
155 int[] startAndEnd = SearchPaginationUtil.calculateStartAndEnd(
156 start, end, documents.size());
157
158 start = startAndEnd[0];
159 end = startAndEnd[1];
160
161 documents = documents.subList(start, end);
162 scores = scores.subList(start, end);
163
164 hits.setDocs(documents.toArray(new Document[documents.size()]));
165 hits.setScores(ArrayUtil.toFloatArray(scores));
166 hits.setLength(size);
167 hits.setSearchTime(
168 (float)(System.currentTimeMillis() - startTime) / Time.SECOND);
169 }
170
171 private double _getAmplificationFactor(double totalViewable, double total) {
172 if (totalViewable == 0) {
173 return _INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR;
174 }
175
176 return Math.min(
177 1.0 / (totalViewable / total),
178 _INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR);
179 }
180
181 private static final double
182 _INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR =
183 GetterUtil.getDouble(
184 PropsUtil.get(
185 PropsKeys.
186 INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR));
187
188 private static final String[] _PERMISSION_SELECTED_FIELD_NAMES =
189 {Field.ENTRY_CLASS_NAME, Field.ENTRY_CLASS_PK};
190
191 }