ConfigurableDCCatalogUIAdapter.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.catalog.adapter;
import static org.opencastproject.index.service.catalog.adapter.CatalogUIAdapterFactory.CONF_FLAVOR_KEY;
import static org.opencastproject.index.service.catalog.adapter.CatalogUIAdapterFactory.CONF_ORGANIZATION_KEY;
import static org.opencastproject.index.service.catalog.adapter.CatalogUIAdapterFactory.CONF_TITLE_KEY;
import static org.opencastproject.util.OsgiUtil.getCfg;
import org.opencastproject.list.api.ListProviderException;
import org.opencastproject.list.api.ListProvidersService;
import org.opencastproject.list.api.ResourceListQuery;
import org.opencastproject.mediapackage.EName;
import org.opencastproject.mediapackage.MediaPackageElementFlavor;
import org.opencastproject.metadata.dublincore.CatalogUIAdapter;
import org.opencastproject.metadata.dublincore.DublinCore;
import org.opencastproject.metadata.dublincore.DublinCoreCatalog;
import org.opencastproject.metadata.dublincore.DublinCoreMetadataCollection;
import org.opencastproject.metadata.dublincore.DublinCoreValue;
import org.opencastproject.metadata.dublincore.MetadataField;
import org.opencastproject.metadata.dublincore.SeriesCatalogUIAdapter;
import org.osgi.service.cm.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
public abstract class ConfigurableDCCatalogUIAdapter implements CatalogUIAdapter {
private static final Logger logger = LoggerFactory.getLogger(ConfigurableDCCatalogUIAdapter.class);
/** The catalog UI adapter configuration */
protected CatalogUIAdapterConfiguration config;
/** The organization name */
protected String organization;
/** The flavor of this catalog */
protected MediaPackageElementFlavor flavor;
/** The title of this catalog */
protected String title;
/** The metadata fields for all properties of the underlying DublinCore */
protected Map<String, MetadataField> dublinCoreProperties;
/** Reference to the list providers service */
protected ListProvidersService listProvidersService;
/**
* Reconfigures the {@link SeriesCatalogUIAdapter} instance with an updated set of configuration properties;
*
* @param properties
* the configuration properties
* @throws ConfigurationException
* if there is a configuration error
*/
public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
config = CatalogUIAdapterConfiguration.loadFromDictionary(properties);
organization = getCfg(properties, CONF_ORGANIZATION_KEY);
flavor = MediaPackageElementFlavor.parseFlavor(getCfg(properties, CONF_FLAVOR_KEY));
title = getCfg(properties, CONF_TITLE_KEY);
dublinCoreProperties = DublinCoreMetadataUtil.getDublinCoreProperties(properties);
}
/**
* Get default value for collection from list providers service
* @param metadataField
* @param listProvidersService
* @return default value
*/
private String getCollectionDefault(MetadataField metadataField,
ListProvidersService listProvidersService) {
if (listProvidersService != null && metadataField.getListprovider() != null) {
try {
return listProvidersService.getDefault(metadataField.getListprovider());
} catch (ListProviderException ex) {
// failed to get default property on list-provider-service
// as this field is optional, it is fine to pass here
}
}
return null;
}
@Override
public DublinCoreMetadataCollection getRawFields() {
return getRawFields(Collections.emptyMap());
}
@Override
public DublinCoreMetadataCollection getRawFields(Map<String, ResourceListQuery> collectionQueryOverrides) {
DublinCoreMetadataCollection rawFields = new DublinCoreMetadataCollection();
for (MetadataField metadataField : dublinCoreProperties.values()) {
try {
String defaultKey = getCollectionDefault(metadataField, listProvidersService);
ResourceListQuery collectionQueryOverride = collectionQueryOverrides.get(metadataField.getOutputID());
rawFields.addField(new MetadataField(metadataField), Optional.ofNullable(defaultKey),
Optional.ofNullable(collectionQueryOverride), listProvidersService);
} catch (IllegalArgumentException e) {
logger.error("Skipping metadata field '{}' because of error", metadataField, e);
}
}
return rawFields;
}
@Override
public DublinCoreMetadataCollection getRawFields(ResourceListQuery collectionQueryOverride) {
DublinCoreMetadataCollection rawFields = new DublinCoreMetadataCollection();
for (MetadataField metadataField : dublinCoreProperties.values()) {
try {
String defaultKey = getCollectionDefault(metadataField, listProvidersService);
rawFields.addField(new MetadataField(metadataField), Optional.ofNullable(defaultKey),
Optional.ofNullable(collectionQueryOverride), listProvidersService);
} catch (IllegalArgumentException e) {
logger.error("Skipping metadata field '{}' because of error", metadataField, e);
}
}
return rawFields;
}
protected DublinCoreMetadataCollection getFieldsFromCatalogs(List<DublinCoreCatalog> dcCatalogs) {
Map<String,List<MetadataField>> metadataFields = new HashMap<>();
List<MetadataField> emptyFields = new ArrayList<>(dublinCoreProperties.values());
for (MetadataField metadataField: dublinCoreProperties.values()) {
String namespace = DublinCore.TERMS_NS_URI;
if (metadataField.getNamespace() != null) {
namespace = metadataField.getNamespace();
}
String metadataFieldKey = namespace.toLowerCase() + ":" + metadataField.getInputID().toLowerCase();
List<MetadataField> metadataFieldList = metadataFields.computeIfAbsent(metadataFieldKey,
key -> new ArrayList<>());
metadataFieldList.add(metadataField);
}
DublinCoreMetadataCollection dublinCoreMetadata = new DublinCoreMetadataCollection();
for (DublinCoreCatalog dc : dcCatalogs) {
getFieldsFromCatalog(metadataFields, emptyFields, dublinCoreMetadata, dc);
}
// Add all of the rest of the fields that didn't have values as empty.
for (MetadataField metadataField: emptyFields) {
try {
dublinCoreMetadata.addEmptyField(new MetadataField(metadataField), getListProvidersService());
} catch (IllegalArgumentException e) {
logger.error("Skipping metadata field '{}' because of error", metadataField, e);
}
}
return dublinCoreMetadata;
}
private void getFieldsFromCatalog(
Map<String, List<MetadataField>> metadataFields,
List<MetadataField> emptyFields,
DublinCoreMetadataCollection dublinCoreMetadata,
DublinCoreCatalog dc) {
for (EName propertyKey : dc.getValues().keySet()) {
// namespace and input id need to match
final String metadataFieldKey = propertyKey.getNamespaceURI().toLowerCase() + ":"
+ propertyKey.getLocalName().toLowerCase();
if (metadataFields.containsKey(metadataFieldKey)) {
// multiple metadata fields can match
for (MetadataField metadataField : metadataFields.get(metadataFieldKey)) {
List<DublinCoreValue> values = dc.get(propertyKey);
if (!values.isEmpty()) {
try {
dublinCoreMetadata.addField(
new MetadataField(metadataField),
values.stream().map(DublinCoreValue::getValue).collect(Collectors.toList()),
getListProvidersService());
emptyFields.remove(metadataField);
} catch (IllegalArgumentException e) {
logger.error("Skipping metadata field '{}' because of error:", metadataField.getInputID(), e);
}
}
}
}
}
}
@Override
public String getOrganization() {
return organization;
}
@Override
public boolean handlesOrganization(String organization) {
return ORGANIZATION_WILDCARD.equals(this.organization) || organization.equals(this.organization);
}
@Override
public MediaPackageElementFlavor getFlavor() {
return flavor;
}
@Override
public String getUITitle() {
return title;
}
public void setListProvidersService(ListProvidersService listProvidersService) {
this.listProvidersService = listProvidersService;
}
protected ListProvidersService getListProvidersService() {
return listProvidersService;
}
}