OpencastGraphQLProvider.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.graphql;
import org.opencastproject.graphql.provider.GraphQLAdditionalTypeProvider;
import org.opencastproject.graphql.provider.GraphQLDynamicTypeProvider;
import org.opencastproject.graphql.provider.GraphQLExtensionProvider;
import org.opencastproject.graphql.provider.GraphQLTypeFunctionProvider;
import org.opencastproject.graphql.type.DateTimeFunction;
import org.opencastproject.graphql.type.DurationFunction;
import org.opencastproject.graphql.type.JsonFunction;
import org.opencastproject.graphql.type.MapFunction;
import org.opencastproject.graphql.type.TimeFunction;
import org.opencastproject.graphql.type.input.DublinCoreMetadataInput;
import org.opencastproject.graphql.type.input.GqlCommonEventMetadataInput;
import org.opencastproject.graphql.type.input.GqlCommonSeriesMetadataInput;
import org.opencastproject.graphql.type.output.GqlAccessControlGenericItem;
import org.opencastproject.graphql.type.output.GqlAccessControlGroupItem;
import org.opencastproject.graphql.type.output.GqlAccessControlUserItem;
import org.opencastproject.graphql.type.output.GqlCommonEventMetadata;
import org.opencastproject.graphql.type.output.GqlCommonEventMetadataV2;
import org.opencastproject.graphql.type.output.GqlCommonSeriesMetadata;
import org.opencastproject.graphql.type.output.GqlCommonSeriesMetadataV2;
import org.opencastproject.graphql.type.output.GqlDublinCoreMetadata;
import org.opencastproject.graphql.type.output.field.GqlDurationMetadataField;
import org.opencastproject.graphql.type.output.field.GqlIntMetadataField;
import org.opencastproject.graphql.type.output.field.GqlJsonMetadataField;
import org.opencastproject.graphql.type.output.field.GqlListMetadataField;
import org.opencastproject.graphql.type.output.field.GqlLongMetadataField;
import org.opencastproject.graphql.util.MetadataFieldToGraphQLConverter;
import org.opencastproject.graphql.util.MetadataFieldToGraphQLFieldMapper;
import org.opencastproject.index.service.api.IndexService;
import org.opencastproject.index.service.catalog.adapter.ConfigurableDCCatalogUIAdapter;
import org.opencastproject.index.service.catalog.adapter.events.CommonEventCatalogUIAdapter;
import org.opencastproject.index.service.catalog.adapter.series.CommonSeriesCatalogUIAdapter;
import org.opencastproject.metadata.dublincore.MetadataField;
import org.opencastproject.security.api.Organization;
import org.opencastproject.security.api.SecurityService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.propertytypes.ServiceDescription;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import graphql.annotations.processor.GraphQLAnnotations;
import graphql.annotations.processor.typeFunctions.TypeFunction;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLOutputType;
@Component
@ServiceDescription("Opencast GraphQL Provider")
public class OpencastGraphQLProvider implements GraphQLExtensionProvider, GraphQLDynamicTypeProvider,
GraphQLAdditionalTypeProvider, GraphQLTypeFunctionProvider {
private final IndexService indexService;
private final SecurityService securityService;
@Activate
public OpencastGraphQLProvider(
@Reference IndexService indexService,
@Reference SecurityService securityService
) {
this.indexService = indexService;
this.securityService = securityService;
}
@Override
public Set<Class<?>> getAdditionalOutputTypes() {
return Set.of(
GqlAccessControlUserItem.class,
GqlAccessControlGroupItem.class,
GqlAccessControlGenericItem.class,
GqlJsonMetadataField.class,
GqlLongMetadataField.class,
GqlDurationMetadataField.class,
GqlIntMetadataField.class,
GqlListMetadataField.class
);
}
@Override
public Map<String, GraphQLOutputType> getDynamicOutputTypes(Organization organization,
GraphQLAnnotations graphQLAnnotations) {
var outputTypes = new HashMap<String, GraphQLOutputType>();
var oldOrganization = securityService.getOrganization();
securityService.setOrganization(organization);
commonEpisodeMetadata(outputTypes, graphQLAnnotations);
commonEpisodeMetadataV2(outputTypes, graphQLAnnotations);
commonSeriesMetadata(outputTypes, graphQLAnnotations);
commonSeriesMetadataV2(outputTypes, graphQLAnnotations);
securityService.setOrganization(oldOrganization);
return outputTypes;
}
@Override
public Map<String, GraphQLInputType> getDynamicInputTypes(Organization organization,
GraphQLAnnotations graphQLAnnotations) {
var inputTypes = new HashMap<String, GraphQLInputType>();
var oldOrganization = securityService.getOrganization();
securityService.setOrganization(organization);
commonEpisodeMetadataInput(inputTypes, graphQLAnnotations);
commonSeriesMetadataInput(inputTypes, graphQLAnnotations);
securityService.setOrganization(oldOrganization);
return inputTypes;
}
private void commonEpisodeMetadataInput(
HashMap<String, GraphQLInputType> inputTypes,
GraphQLAnnotations graphQLAnnotations) {
CommonEventCatalogUIAdapter adapter = (CommonEventCatalogUIAdapter) indexService
.getCommonEventCatalogUIAdapter();
commonMetadataInput(inputTypes, graphQLAnnotations, adapter,
GqlCommonEventMetadataInput.TYPE_NAME,
GqlCommonEventMetadataInput.class);
}
private void commonSeriesMetadataInput(
HashMap<String, GraphQLInputType> inputTypes,
GraphQLAnnotations graphQLAnnotations) {
CommonSeriesCatalogUIAdapter adapter = (CommonSeriesCatalogUIAdapter) indexService
.getCommonSeriesCatalogUIAdapter();
commonMetadataInput(inputTypes, graphQLAnnotations, adapter,
GqlCommonSeriesMetadataInput.TYPE_NAME,
GqlCommonSeriesMetadataInput.class);
}
private void commonMetadataInput(HashMap<String, GraphQLInputType> inputTypes, GraphQLAnnotations graphQLAnnotations,
ConfigurableDCCatalogUIAdapter adapter, String graphQLTypeName, Class<? extends DublinCoreMetadataInput> clazz) {
final Set<GraphQLInputObjectField> fieldDefinitions = new HashSet<>();
adapter.getRawFields().getFields().stream().filter(f -> !f.isReadOnly()).forEach(
f -> fieldDefinitions.add(
GraphQLInputObjectField.newInputObjectField()
.name(f.getOutputID())
.type((GraphQLInputType) MetadataFieldToGraphQLConverter.convertType(f))
.description(f.getLabel())
.build()
)
);
var type = (GraphQLInputObjectType) graphQLAnnotations.getObjectHandler().getTypeRetriever()
.getGraphQLType(clazz, graphQLAnnotations.getContainer(), true);
GraphQLInputObjectType transformedObjectType = type
.transform(builder -> fieldDefinitions.forEach(builder::field));
inputTypes.put(graphQLTypeName, transformedObjectType);
}
private void commonEpisodeMetadata(
HashMap<String, GraphQLOutputType> outputTypes,
GraphQLAnnotations graphQLAnnotations) {
CommonEventCatalogUIAdapter adapter = (CommonEventCatalogUIAdapter) indexService
.getCommonEventCatalogUIAdapter();
commonMetadata(outputTypes, graphQLAnnotations, adapter,
GqlCommonEventMetadata.TYPE_NAME,
GqlCommonEventMetadata.class);
}
private void commonEpisodeMetadataV2(
HashMap<String, GraphQLOutputType> outputTypes,
GraphQLAnnotations graphQLAnnotations) {
CommonEventCatalogUIAdapter adapter = (CommonEventCatalogUIAdapter) indexService
.getCommonEventCatalogUIAdapter();
commonMetadataV2(outputTypes, graphQLAnnotations, adapter,
GqlCommonEventMetadataV2.TYPE_NAME,
GqlCommonEventMetadataV2.class);
}
private void commonSeriesMetadata(
HashMap<String, GraphQLOutputType> outputTypes,
GraphQLAnnotations graphQLAnnotations) {
CommonSeriesCatalogUIAdapter adapter = (CommonSeriesCatalogUIAdapter) indexService
.getCommonSeriesCatalogUIAdapter();
commonMetadata(outputTypes, graphQLAnnotations, adapter,
GqlCommonSeriesMetadata.TYPE_NAME,
GqlCommonSeriesMetadata.class);
}
private void commonSeriesMetadataV2(
HashMap<String, GraphQLOutputType> outputTypes,
GraphQLAnnotations graphQLAnnotations) {
CommonSeriesCatalogUIAdapter adapter = (CommonSeriesCatalogUIAdapter) indexService
.getCommonSeriesCatalogUIAdapter();
commonMetadataV2(outputTypes, graphQLAnnotations, adapter,
GqlCommonSeriesMetadataV2.TYPE_NAME,
GqlCommonSeriesMetadataV2.class);
}
private void commonMetadata(HashMap<String, GraphQLOutputType> outputTypes, GraphQLAnnotations graphQLAnnotations,
ConfigurableDCCatalogUIAdapter adapter, String graphQLTypeName, Class<? extends GqlDublinCoreMetadata> clazz) {
final Set<GraphQLFieldDefinition> fieldDefinitions = new HashSet<>();
for (MetadataField m : adapter.getRawFields().getFields()) {
GraphQLFieldDefinition.Builder builder = GraphQLFieldDefinition.newFieldDefinition();
builder.name(m.getOutputID());
builder.type((GraphQLOutputType) MetadataFieldToGraphQLConverter.convertType(m));
builder.description(m.getLabel());
fieldDefinitions.add(builder.build());
}
var type = (GraphQLObjectType) graphQLAnnotations.getObjectHandler().getTypeRetriever()
.getGraphQLType(clazz, graphQLAnnotations.getContainer(), false);
GraphQLObjectType transformedObjectType = type
.transform(builder -> fieldDefinitions.forEach(builder::field));
outputTypes.put(graphQLTypeName, transformedObjectType);
}
private void commonMetadataV2(HashMap<String, GraphQLOutputType> outputTypes, GraphQLAnnotations graphQLAnnotations,
ConfigurableDCCatalogUIAdapter adapter, String graphQLTypeName, Class<? extends GqlDublinCoreMetadata> clazz) {
final Set<GraphQLFieldDefinition> fieldDefinitions = new HashSet<>();
for (MetadataField m : adapter.getRawFields().getFields()) {
GraphQLFieldDefinition.Builder builder = GraphQLFieldDefinition.newFieldDefinition();
var outputId = m.getOutputID();
builder.name(outputId != null ? outputId : m.getInputID());
var outputType = MetadataFieldToGraphQLFieldMapper.mapToClass(m.getType());
builder.type((GraphQLOutputType) graphQLAnnotations.getObjectHandler().getTypeRetriever()
.getGraphQLType(outputType, graphQLAnnotations.getContainer(), false));
builder.description(m.getLabel());
fieldDefinitions.add(builder.build());
}
var type = (GraphQLObjectType) graphQLAnnotations.getObjectHandler().getTypeRetriever()
.getGraphQLType(clazz, graphQLAnnotations.getContainer(), false);
GraphQLObjectType transformedObjectType = type
.transform(builder -> fieldDefinitions.forEach(builder::field));
outputTypes.put(graphQLTypeName, transformedObjectType);
}
@Override
public Set<TypeFunction> getTypeFunctions() {
return Set.of(
new DateTimeFunction(),
new DurationFunction(),
new JsonFunction(),
new MapFunction(),
new TimeFunction()
);
}
}