ContributorsListProvider.java
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.index.service.resources.list.provider;
import org.opencastproject.elasticsearch.index.ElasticsearchIndex;
import org.opencastproject.elasticsearch.index.objects.event.Event;
import org.opencastproject.elasticsearch.index.objects.event.EventIndexSchema;
import org.opencastproject.elasticsearch.index.objects.series.Series;
import org.opencastproject.elasticsearch.index.objects.series.SeriesIndexSchema;
import org.opencastproject.list.api.ResourceListProvider;
import org.opencastproject.list.api.ResourceListQuery;
import org.opencastproject.list.util.ListProviderUtil;
import org.opencastproject.security.api.User;
import org.opencastproject.security.api.UserDirectoryService;
import org.apache.commons.lang3.StringUtils;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
@Component(
service = ResourceListProvider.class,
property = {
"service.description=Contributors list provider",
"opencast.service.type=org.opencastproject.index.service.resources.list.provider.ContributorsListProvider"
}
)
public class ContributorsListProvider implements ResourceListProvider {
private static final String CONFIGURATION_KEY_EXCLUDE_USER_PROVIDER = "exclude.user.provider";
private static final String ALL_USER_PROVIDERS_VALUE = "*";
private static final String PROVIDER_PREFIX = "CONTRIBUTORS";
public static final String DEFAULT = PROVIDER_PREFIX;
public static final String NAMES_TO_USERNAMES = PROVIDER_PREFIX + ".NAMES.TO.USERNAMES";
public static final String USERNAMES = PROVIDER_PREFIX + ".USERNAMES";
protected static final String[] NAMES = { PROVIDER_PREFIX, USERNAMES, NAMES_TO_USERNAMES };
private static final Logger logger = LoggerFactory.getLogger(ContributorsListProvider.class);
private final Set<String> excludeUserProvider = new HashSet<>();
private UserDirectoryService userDirectoryService;
private ElasticsearchIndex searchIndex;
@Activate
protected void activate(Map<String, Object> properties) {
modified(properties);
logger.info("Contributors list provider activated!");
}
@Modified
public void modified(Map<String, Object> properties) {
Object excludeUserProviderValue = properties.get(CONFIGURATION_KEY_EXCLUDE_USER_PROVIDER);
excludeUserProvider.clear();
if (excludeUserProviderValue != null) {
for (String userProvider : StringUtils.split(excludeUserProviderValue.toString(), ',')) {
if (StringUtils.trimToNull(userProvider) != null) {
excludeUserProvider.add(StringUtils.trimToNull(userProvider));
}
}
}
logger.debug("Excluded user providers: {}", excludeUserProvider);
}
/** OSGi callback for users services. */
@Reference
public void setUserDirectoryService(UserDirectoryService userDirectoryService) {
this.userDirectoryService = userDirectoryService;
}
/** OSGi callback for the search index. */
@Reference
public void setIndex(ElasticsearchIndex index) {
this.searchIndex = index;
}
@Override
public String[] getListNames() {
return NAMES;
}
@Override
public Map<String, String> getList(String listName, ResourceListQuery query) {
if (listName.equalsIgnoreCase(USERNAMES)) {
return getListWithUserNames(query);
} else if (listName.equalsIgnoreCase(NAMES_TO_USERNAMES)) {
return getListWithTechnicalPresenters(query);
} else {
return getList(query);
}
}
/**
* Get all of the contributors with friendly printable names.
*
* @param query
* The query for the list including limit and offset.
* @return The {@link Map} including all of the contributors.
*/
protected Map<String, String> getList(ResourceListQuery query) {
Map<String, String> usersList = new HashMap<String, String>();
int offset = 0;
int limit = 0;
SortedSet<String> contributorsList = new TreeSet<String>(new Comparator<String>() {
@Override
public int compare(String name1, String name2) {
return name1.compareTo(name2);
}
});
if (!excludeUserProvider.contains(ALL_USER_PROVIDERS_VALUE)) {
Iterator<User> users = userDirectoryService.findUsers("%", offset, limit);
while (users.hasNext()) {
User u = users.next();
if (!excludeUserProvider.contains(u.getProvider()) && StringUtils.isNotBlank(u.getName()))
contributorsList.add(u.getName());
}
}
contributorsList.addAll(searchIndex.getTermsForField(EventIndexSchema.CONTRIBUTOR,
Event.DOCUMENT_TYPE));
contributorsList.addAll(searchIndex.getTermsForField(EventIndexSchema.PRESENTER,
Event.DOCUMENT_TYPE));
contributorsList.addAll(searchIndex.getTermsForField(EventIndexSchema.PUBLISHER,
Event.DOCUMENT_TYPE));
contributorsList.addAll(searchIndex.getTermsForField(SeriesIndexSchema.CONTRIBUTORS,
Series.DOCUMENT_TYPE));
contributorsList.addAll(searchIndex.getTermsForField(SeriesIndexSchema.ORGANIZERS,
Series.DOCUMENT_TYPE));
contributorsList.addAll(searchIndex.getTermsForField(SeriesIndexSchema.PUBLISHERS,
Series.DOCUMENT_TYPE));
// TODO: TThis is not a good idea.
// TODO: The search index can handle limit and offset.
// TODO: We should not request all data.
if (query != null) {
if (query.getLimit().isSome())
limit = query.getLimit().get();
if (query.getOffset().isSome())
offset = query.getOffset().get();
}
int i = 0;
for (String contributor : contributorsList) {
if (i >= offset && (limit == 0 || i < limit)) {
usersList.put(contributor, contributor);
}
i++;
}
return usersList;
}
/**
* Get the contributors list including usernames and organizations for the users available.
*
* @param query
* The query for the list including limit and offset.
* @return The {@link Map} including all of the contributors.
*/
protected Map<String, String> getListWithTechnicalPresenters(ResourceListQuery query) {
int offset = 0;
int limit = 0;
List<Contributor> contributorsList = new ArrayList<Contributor>();
HashSet<String> labels = new HashSet<String>();
if (!excludeUserProvider.contains(ALL_USER_PROVIDERS_VALUE)) {
Iterator<User> users = userDirectoryService.findUsers("%", offset, limit);
while (users.hasNext()) {
User u = users.next();
if (!excludeUserProvider.contains(u.getProvider())) {
if (StringUtils.isNotBlank(u.getName())) {
contributorsList.add(new Contributor(u.getUsername(), u.getName()));
labels.add(u.getName());
} else {
contributorsList.add(new Contributor(u.getUsername(), u.getUsername()));
labels.add(u.getUsername());
}
}
}
}
addIndexNamesToMap(labels, contributorsList, searchIndex
.getTermsForField(EventIndexSchema.PRESENTER, Event.DOCUMENT_TYPE));
addIndexNamesToMap(labels, contributorsList, searchIndex
.getTermsForField(EventIndexSchema.CONTRIBUTOR, Event.DOCUMENT_TYPE));
addIndexNamesToMap(labels, contributorsList, searchIndex
.getTermsForField(SeriesIndexSchema.CONTRIBUTORS, Event.DOCUMENT_TYPE));
addIndexNamesToMap(labels, contributorsList, searchIndex
.getTermsForField(SeriesIndexSchema.ORGANIZERS, Event.DOCUMENT_TYPE));
addIndexNamesToMap(labels, contributorsList, searchIndex
.getTermsForField(SeriesIndexSchema.PUBLISHERS, Event.DOCUMENT_TYPE));
Collections.sort(contributorsList, new Comparator<Contributor>() {
@Override
public int compare(Contributor contributor1, Contributor contributor2) {
return contributor1.getLabel().compareTo(contributor2.getLabel());
}
});
Map<String, String> contributorMap = new LinkedHashMap<>();
for (Contributor contributor : contributorsList) {
contributorMap.put(contributor.getKey(), contributor.getLabel());
}
return ListProviderUtil.filterMap(contributorMap, query);
}
/**
* Get the contributors list including usernames and organizations for the users available.
*
* @param query
* The query for the list including limit and offset.
* @return The {@link Map} including all of the contributors.
*/
protected Map<String, String> getListWithUserNames(ResourceListQuery query) {
int offset = 0;
int limit = 0;
List<Contributor> contributorsList = new ArrayList<Contributor>();
HashSet<String> labels = new HashSet<String>();
if (!excludeUserProvider.contains(ALL_USER_PROVIDERS_VALUE)) {
Iterator<User> users = userDirectoryService.findUsers("%", offset, limit);
while (users.hasNext()) {
User u = users.next();
if (!excludeUserProvider.contains(u.getProvider())) {
if (StringUtils.isNotBlank(u.getName())) {
contributorsList.add(new Contributor(u.getUsername(), u.getName()));
labels.add(u.getName());
} else {
contributorsList.add(new Contributor(u.getUsername(), u.getUsername()));
labels.add(u.getUsername());
}
}
}
}
Collections.sort(contributorsList, new Comparator<Contributor>() {
@Override
public int compare(Contributor contributor1, Contributor contributor2) {
return contributor1.getLabel().compareTo(contributor2.getLabel());
}
});
Map<String, String> contributorMap = new LinkedHashMap<>();
for (Contributor contributor : contributorsList) {
contributorMap.put(contributor.getKey(), contributor.getLabel());
}
return ListProviderUtil.filterMap(contributorMap, query);
}
/**
* Add all names in the index to the map if they aren't already present as a user.
*
* @param userLabels
* The collection of user labels, the full names of the users.
* @param contributors
* The collection of all contributors including the index names that will be added.
* @param indexNames
* The list of new names from the index.
*/
protected void addIndexNamesToMap(Set<String> userLabels, Collection<Contributor> contributors,
List<String> indexNames) {
for (String indexName : indexNames) {
if (!userLabels.contains(indexName)) {
contributors.add(new Contributor(indexName, indexName));
}
}
}
@Override
public boolean isTranslatable(String listName) {
return false;
}
@Override
public String getDefault() {
return null;
}
private class Contributor {
public String getKey() {
return key;
}
public String getLabel() {
return label;
}
private String key;
private String label;
Contributor(String key, String label) {
this.key = key;
this.label = label;
}
@Override
public String toString() {
return key + ":" + label;
}
}
}