/**
* 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 java.lang.String.format;
import static org.opencastproject.util.OsgiUtil.getCfg;
import static org.opencastproject.util.OsgiUtil.getOptCfg;
import org.opencastproject.index.service.catalog.adapter.events.CommonEventCatalogUIAdapter;
import org.opencastproject.index.service.catalog.adapter.events.ConfigurableEventDCCatalogUIAdapter;
import org.opencastproject.index.service.catalog.adapter.series.CommonSeriesCatalogUIAdapter;
import org.opencastproject.index.service.catalog.adapter.series.ConfigurableSeriesDCCatalogUIAdapter;
import org.opencastproject.index.service.resources.list.api.ListProvidersService;
import org.opencastproject.metadata.dublincore.EventCatalogUIAdapter;
import org.opencastproject.metadata.dublincore.SeriesCatalogUIAdapter;
import org.opencastproject.series.api.SeriesService;
import org.opencastproject.util.data.Option;
import org.opencastproject.workspace.api.Workspace;
import com.entwinemedia.fn.Prelude;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Dictionary;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Based on the given service configuration this service factory will create new instances of
* {@link SeriesCatalogUIAdapter} services and register them in the OSGi service registry.
*/
public class CatalogUIAdapterFactory implements ManagedServiceFactory {
/** The logging facility. */
private static final Logger logger = LoggerFactory.getLogger(CatalogUIAdapterFactory.class);
/* The collection of keys to read from the OSGI configuration file */
public static final String CONF_TYPE_KEY = "type";
public static final String CONF_ORGANIZATION_KEY = "organization";
public static final String CONF_FLAVOR_KEY = "flavor";
public static final String CONF_TITLE_KEY = "title";
public static final String CONF_COMMON_METADATA_KEY = "common-metadata";
private static final String CATALOG_TYPE_EVENTS = "events";
private static final String CATALOG_TYPE_SERIES = "series";
/** Map with service registrations of registered {@link SeriesCatalogUIAdapter} instances. */
private final Map<String, ServiceRegistration<?>> adapterServiceRegistrations = new ConcurrentHashMap<>();
/** Reference to a {@link ListProvidersService} instance. */
private ListProvidersService listProvidersService;
/** Reference to a {@link SeriesService} instance. */
private SeriesService seriesService;
/** Reference to a {@link Workspace} instance. */
private Workspace workspace;
/** The OSGi bundle context. */
private BundleContext bundleContext;
/** OSGi callback. */
void activate(ComponentContext cc) {
bundleContext = cc.getBundleContext();
}
/** OSGi callback for deactivating component. */
void deactivate() {
for (String pid : adapterServiceRegistrations.keySet()) {
deleted(pid);
}
}
@Override
public String getName() {
return "Catalog UI Adapter Factory";
}
@Override
public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
final String type = getCfg(properties, CONF_TYPE_KEY);
Option<String> optCommonMetadata = getOptCfg(properties, CONF_COMMON_METADATA_KEY);
final boolean isCommonMetadata = optCommonMetadata.isSome() ? Boolean.parseBoolean(optCommonMetadata.get()) : false;
// Check for valid configuration values
if (!(CATALOG_TYPE_EVENTS.equalsIgnoreCase(type) || CATALOG_TYPE_SERIES.equalsIgnoreCase(type))) {
throw new ConfigurationException(CONF_TYPE_KEY,
format("The type must either be '%s' or '%s'", CATALOG_TYPE_EVENTS, CATALOG_TYPE_SERIES));
}
switch (type) {
case CATALOG_TYPE_EVENTS: {
if (adapterServiceRegistrations.containsKey(pid)) {
ServiceRegistration<?> serviceRegistration = adapterServiceRegistrations.get(pid);
ConfigurableEventDCCatalogUIAdapter adapter = (ConfigurableEventDCCatalogUIAdapter) bundleContext
.getService(serviceRegistration.getReference());
adapter.updated(properties);
} else {
ConfigurableEventDCCatalogUIAdapter adapter;
String[] adapterClassesNames;
if (isCommonMetadata) {
if (bundleContext.getServiceReference(CommonEventCatalogUIAdapter.class.getName()) != null)
throw new ConfigurationException(CONF_COMMON_METADATA_KEY, format(
"Only one common metadata catalog adapter is allowed for the type '%s'", CATALOG_TYPE_EVENTS));
adapter = new CommonEventCatalogUIAdapter();
adapterClassesNames = new String[] { CommonEventCatalogUIAdapter.class.getName(),
EventCatalogUIAdapter.class.getName() };
} else {
adapter = new ConfigurableEventDCCatalogUIAdapter();
adapterClassesNames = new String[] { EventCatalogUIAdapter.class.getName() };
}
adapter.setListProvidersService(listProvidersService);
adapter.setWorkspace(workspace);
adapter.updated(properties);
ServiceRegistration<?> configurationRegistration = bundleContext.registerService(adapterClassesNames, adapter,
null);
adapterServiceRegistrations.put(pid, configurationRegistration);
}
break;
}
case CATALOG_TYPE_SERIES: {
if (adapterServiceRegistrations.containsKey(pid)) {
ServiceRegistration<?> serviceRegistration = adapterServiceRegistrations.get(pid);
ConfigurableSeriesDCCatalogUIAdapter adapter = (ConfigurableSeriesDCCatalogUIAdapter) bundleContext
.getService(serviceRegistration.getReference());
adapter.updated(properties);
} else {
ConfigurableSeriesDCCatalogUIAdapter adapter;
String[] adapterClassesNames;
if (isCommonMetadata) {
if (bundleContext.getServiceReference(CommonSeriesCatalogUIAdapter.class.getName()) != null)
throw new ConfigurationException(CONF_COMMON_METADATA_KEY, format(
"Only one common metadata catalog adapter is allowed for the type '%s'", CATALOG_TYPE_SERIES));
adapter = new CommonSeriesCatalogUIAdapter();
adapterClassesNames = new String[] { CommonSeriesCatalogUIAdapter.class.getName(),
SeriesCatalogUIAdapter.class.getName() };
} else {
adapter = new ConfigurableSeriesDCCatalogUIAdapter();
adapterClassesNames = new String[] { SeriesCatalogUIAdapter.class.getName() };
}
adapter.setListProvidersService(listProvidersService);
adapter.setSeriesService(seriesService);
adapter.updated(properties);
ServiceRegistration<?> adapterServiceRegistration = bundleContext.registerService(adapterClassesNames,
adapter, null);
adapterServiceRegistrations.put(pid, adapterServiceRegistration);
}
break;
}
default:
Prelude.unexhaustiveMatch(type);
}
}
@Override
public void deleted(String pid) {
if (adapterServiceRegistrations.containsKey(pid)) {
ServiceRegistration<?> serviceRegistration = adapterServiceRegistrations.remove(pid);
serviceRegistration.unregister();
logger.info("Service registration for PID {} removed", pid);
}
}
/** OSGi callback to bind {@link ListProvidersService} instance. */
void setListProvidersService(ListProvidersService listProvidersService) {
this.listProvidersService = listProvidersService;
}
/** OSGi callback to bind {@link SeriesService} instance. */
void setSeriesService(SeriesService seriesService) {
this.seriesService = seriesService;
}
/** OSGi callback to bind {@link Workspace} instance. */
void setWorkspace(Workspace workspace) {
this.workspace = workspace;
}
}