/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.search;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.dao.search.SearchPaginationUtil;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.PropsUtil;
import com.liferay.portal.kernel.util.SetUtil;
import com.liferay.portal.kernel.util.Time;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author Tina Tian
*/
public abstract class BaseSearchResultPermissionFilter
implements SearchResultPermissionFilter {
@Override
public Hits search(SearchContext searchContext) throws SearchException {
QueryConfig queryConfig = searchContext.getQueryConfig();
if (!queryConfig.isAllFieldsSelected()) {
Set<String> selectedFieldNameSet = SetUtil.fromArray(
queryConfig.getSelectedFieldNames());
Collections.addAll(
selectedFieldNameSet, _PERMISSION_SELECTED_FIELD_NAMES);
queryConfig.setSelectedFieldNames(
selectedFieldNameSet.toArray(
new String[selectedFieldNameSet.size()]));
}
int end = searchContext.getEnd();
int start = searchContext.getStart();
if ((end == QueryUtil.ALL_POS) && (start == QueryUtil.ALL_POS)) {
Hits hits = getHits(searchContext);
if (!isGroupAdmin(searchContext)) {
filterHits(hits, searchContext);
}
return hits;
}
if ((start < 0) || (start > end)) {
return new HitsImpl();
}
if (isGroupAdmin(searchContext)) {
return getHits(searchContext);
}
double amplificationFactor = 1.0;
int excludedDocsSize = 0;
int hitsSize = 0;
int offset = 0;
long startTime = 0;
List<Document> documents = new ArrayList<>();
List<Float> scores = new ArrayList<>();
while (true) {
int count = end - documents.size();
int amplifiedCount = (int)Math.ceil(count * amplificationFactor);
int amplifiedEnd = offset + amplifiedCount;
searchContext.setEnd(amplifiedEnd);
searchContext.setStart(offset);
Hits hits = getHits(searchContext);
if (startTime == 0) {
hitsSize = hits.getLength();
startTime = hits.getStart();
}
Document[] oldDocs = hits.getDocs();
filterHits(hits, searchContext);
Document[] newDocs = hits.getDocs();
excludedDocsSize += oldDocs.length - newDocs.length;
collectHits(hits, documents, scores, count);
if ((newDocs.length >= count) ||
(oldDocs.length < amplifiedCount) ||
(amplifiedEnd >= hitsSize)) {
updateHits(
hits, documents, scores, start, end,
hitsSize - excludedDocsSize, startTime);
return hits;
}
offset = amplifiedEnd;
amplificationFactor = _getAmplificationFactor(
documents.size(), offset);
}
}
protected void collectHits(
Hits hits, List<Document> documents, List<Float> scores, int count) {
Document[] docs = hits.getDocs();
if (docs.length < count) {
count = docs.length;
}
for (int i = 0; i < count; i++) {
documents.add(docs[i]);
scores.add(hits.score(i));
}
}
protected abstract void filterHits(Hits hits, SearchContext searchContext);
protected abstract Hits getHits(SearchContext searchContext)
throws SearchException;
protected abstract boolean isGroupAdmin(SearchContext searchContext);
protected void updateHits(
Hits hits, List<Document> documents, List<Float> scores, int start,
int end, int size, long startTime) {
int[] startAndEnd = SearchPaginationUtil.calculateStartAndEnd(
start, end, documents.size());
start = startAndEnd[0];
end = startAndEnd[1];
documents = documents.subList(start, end);
scores = scores.subList(start, end);
hits.setDocs(documents.toArray(new Document[documents.size()]));
hits.setScores(ArrayUtil.toFloatArray(scores));
hits.setLength(size);
hits.setSearchTime(
(float)(System.currentTimeMillis() - startTime) / Time.SECOND);
}
private double _getAmplificationFactor(double totalViewable, double total) {
if (totalViewable == 0) {
return _INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR;
}
return Math.min(
1.0 / (totalViewable / total),
_INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR);
}
private static final double
_INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR =
GetterUtil.getDouble(
PropsUtil.get(
PropsKeys.
INDEX_PERMISSION_FILTER_SEARCH_AMPLIFICATION_FACTOR));
private static final String[] _PERMISSION_SELECTED_FIELD_NAMES =
{Field.COMPANY_ID, Field.ENTRY_CLASS_NAME, Field.ENTRY_CLASS_PK};
}