use of org.opencastproject.metadata.dublincore.EventCatalogUIAdapter in project opencast by opencast.
the class IndexServiceImpl method updateMediaPackageMetadata.
private void updateMediaPackageMetadata(MediaPackage mp, MetadataList metadataList) {
String oldSeriesId = mp.getSeries();
for (EventCatalogUIAdapter catalogUIAdapter : getEventCatalogUIAdapters()) {
Opt<MetadataCollection> metadata = metadataList.getMetadataByAdapter(catalogUIAdapter);
if (metadata.isSome() && metadata.get().isUpdated()) {
catalogUIAdapter.storeFields(mp, metadata.get());
}
}
// update series catalogs
if (!StringUtils.equals(oldSeriesId, mp.getSeries())) {
List<String> seriesDcTags = new ArrayList<>();
List<String> seriesAclTags = new ArrayList<>();
Map<String, List<String>> seriesExtDcTags = new HashMap<>();
if (StringUtils.isNotBlank(oldSeriesId)) {
// remove series dublincore from the media package
for (MediaPackageElement mpe : mp.getElementsByFlavor(MediaPackageElements.SERIES)) {
mp.remove(mpe);
for (String tag : mpe.getTags()) {
seriesDcTags.add(tag);
}
}
// remove series ACL from the media package
for (MediaPackageElement mpe : mp.getElementsByFlavor(MediaPackageElements.XACML_POLICY_SERIES)) {
mp.remove(mpe);
for (String tag : mpe.getTags()) {
seriesAclTags.add(tag);
}
}
// remove series extended metadata from the media package
try {
Opt<Map<String, byte[]>> oldSeriesElementsOpt = seriesService.getSeriesElements(oldSeriesId);
for (Map<String, byte[]> oldSeriesElements : oldSeriesElementsOpt) {
for (String oldSeriesElementType : oldSeriesElements.keySet()) {
for (MediaPackageElement mpe : mp.getElementsByFlavor(MediaPackageElementFlavor.flavor(oldSeriesElementType, "series"))) {
mp.remove(mpe);
String elementType = mpe.getFlavor().getType();
if (StringUtils.isNotBlank(elementType)) {
// remember the tags for this type of element
if (!seriesExtDcTags.containsKey(elementType)) {
// initialize the tags list on the first occurrence of this element type
seriesExtDcTags.put(elementType, new ArrayList<>());
}
for (String tag : mpe.getTags()) {
seriesExtDcTags.get(elementType).add(tag);
}
}
}
}
}
} catch (SeriesException e) {
logger.info("Unable to retrieve series element types from series service for the series {}", oldSeriesId, e);
}
}
if (StringUtils.isNotBlank(mp.getSeries())) {
// add updated series dublincore to the media package
try {
DublinCoreCatalog seriesDC = seriesService.getSeries(mp.getSeries());
if (seriesDC != null) {
mp.setSeriesTitle(seriesDC.getFirst(DublinCore.PROPERTY_TITLE));
try (InputStream in = IOUtils.toInputStream(seriesDC.toXmlString(), "UTF-8")) {
String elementId = UUID.randomUUID().toString();
URI catalogUrl = workspace.put(mp.getIdentifier().compact(), elementId, "dublincore.xml", in);
MediaPackageElement mpe = mp.add(catalogUrl, MediaPackageElement.Type.Catalog, MediaPackageElements.SERIES);
mpe.setIdentifier(elementId);
mpe.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, workspace.read(catalogUrl)));
if (StringUtils.isNotBlank(oldSeriesId)) {
for (String tag : seriesDcTags) {
mpe.addTag(tag);
}
} else {
// add archive tag to the element if the media package had no series set before
mpe.addTag("archive");
}
} catch (IOException e) {
throw new IllegalStateException("Unable to add the series dublincore to the media package " + mp.getIdentifier(), e);
}
}
} catch (SeriesException e) {
throw new IllegalStateException("Unable to retrieve series dublincore catalog for the series " + mp.getSeries(), e);
} catch (NotFoundException | UnauthorizedException e) {
throw new IllegalArgumentException("Unable to retrieve series dublincore catalog for the series " + mp.getSeries(), e);
}
// add updated series ACL to the media package
try {
AccessControlList seriesAccessControl = seriesService.getSeriesAccessControl(mp.getSeries());
if (seriesAccessControl != null) {
mp = authorizationService.setAcl(mp, AclScope.Series, seriesAccessControl).getA();
for (MediaPackageElement seriesAclMpe : mp.getElementsByFlavor(MediaPackageElements.XACML_POLICY_SERIES)) {
if (StringUtils.isNotBlank(oldSeriesId)) {
for (String tag : seriesAclTags) {
seriesAclMpe.addTag(tag);
}
} else {
// add archive tag to the element if the media package had no series set before
seriesAclMpe.addTag("archive");
}
}
}
} catch (SeriesException e) {
throw new IllegalStateException("Unable to retrieve series ACL for series " + oldSeriesId, e);
} catch (NotFoundException e) {
logger.debug("There is no ACL set for the series {}", mp.getSeries());
}
// add updated series extended metadata to the media package
try {
Opt<Map<String, byte[]>> seriesElementsOpt = seriesService.getSeriesElements(mp.getSeries());
for (Map<String, byte[]> seriesElements : seriesElementsOpt) {
for (String seriesElementType : seriesElements.keySet()) {
try (InputStream in = new ByteArrayInputStream(seriesElements.get(seriesElementType))) {
String elementId = UUID.randomUUID().toString();
URI catalogUrl = workspace.put(mp.getIdentifier().compact(), elementId, "dublincore.xml", in);
MediaPackageElement mpe = mp.add(catalogUrl, MediaPackageElement.Type.Catalog, MediaPackageElementFlavor.flavor(seriesElementType, "series"));
mpe.setIdentifier(elementId);
mpe.setChecksum(Checksum.create(ChecksumType.DEFAULT_TYPE, workspace.read(catalogUrl)));
if (StringUtils.isNotBlank(oldSeriesId)) {
if (seriesExtDcTags.containsKey(seriesElementType)) {
for (String tag : seriesExtDcTags.get(seriesElementType)) {
mpe.addTag(tag);
}
}
} else {
// add archive tag to the element if the media package had no series set before
mpe.addTag("archive");
}
} catch (IOException e) {
throw new IllegalStateException(String.format("Unable to serialize series element %s for the series %s", seriesElementType, mp.getSeries()), e);
} catch (NotFoundException e) {
throw new IllegalArgumentException("Unable to retrieve series element dublincore catalog for the series " + mp.getSeries(), e);
}
}
}
} catch (SeriesException e) {
throw new IllegalStateException("Unable to retrieve series elements for the series " + mp.getSeries(), e);
}
}
}
}
use of org.opencastproject.metadata.dublincore.EventCatalogUIAdapter in project opencast by opencast.
the class EventHttpServletRequest method deserializeMetadataList.
/**
* Change the simplified fields of key values provided to the external api into a {@link MetadataList}.
*
* @param json
* The json string that contains an array of metadata field lists for the different catalogs.
* @param startDatePattern
* The pattern to use to parse the start date from the json payload.
* @param startTimePattern
* The pattern to use to parse the start time from the json payload.
* @return A {@link MetadataList} with the fields populated with the values provided.
* @throws ParseException
* Thrown if unable to parse the json string.
* @throws NotFoundException
* Thrown if unable to find the catalog or field that the json refers to.
*/
protected static MetadataList deserializeMetadataList(String json, List<EventCatalogUIAdapter> catalogAdapters, Opt<String> startDatePattern, Opt<String> startTimePattern) throws ParseException, NotFoundException, java.text.ParseException {
MetadataList metadataList = new MetadataList();
JSONParser parser = new JSONParser();
JSONArray jsonCatalogs = (JSONArray) parser.parse(json);
for (int i = 0; i < jsonCatalogs.size(); i++) {
JSONObject catalog = (JSONObject) jsonCatalogs.get(i);
if (catalog.get("flavor") == null || StringUtils.isBlank(catalog.get("flavor").toString())) {
throw new IllegalArgumentException("Unable to create new event as no flavor was given for one of the metadata collections");
}
String flavorString = catalog.get("flavor").toString();
MediaPackageElementFlavor flavor = MediaPackageElementFlavor.parseFlavor(flavorString);
MetadataCollection collection = null;
EventCatalogUIAdapter adapter = null;
for (EventCatalogUIAdapter eventCatalogUIAdapter : catalogAdapters) {
if (eventCatalogUIAdapter.getFlavor().equals(flavor)) {
adapter = eventCatalogUIAdapter;
collection = eventCatalogUIAdapter.getRawFields();
}
}
if (collection == null) {
throw new IllegalArgumentException(String.format("Unable to find an EventCatalogUIAdapter with Flavor '%s'", flavorString));
}
String fieldsJson = catalog.get("fields").toString();
if (StringUtils.trimToNull(fieldsJson) != null) {
Map<String, String> fields = RequestUtils.getKeyValueMap(fieldsJson);
for (String key : fields.keySet()) {
if ("subjects".equals(key)) {
// Handle the special case of allowing subjects to be an array.
MetadataField<?> field = collection.getOutputFields().get(DublinCore.PROPERTY_SUBJECT.getLocalName());
if (field == null) {
throw new NotFoundException(String.format("Cannot find a metadata field with id 'subject' from Catalog with Flavor '%s'.", flavorString));
}
collection.removeField(field);
try {
JSONArray subjects = (JSONArray) parser.parse(fields.get(key));
collection.addField(MetadataField.copyMetadataFieldWithValue(field, StringUtils.join(subjects.iterator(), ",")));
} catch (ParseException e) {
throw new IllegalArgumentException(String.format("Unable to parse the 'subjects' metadata array field because: %s", e.toString()));
}
} else if ("startDate".equals(key)) {
// Special handling for start date since in API v1 we expect start date and start time to be separate fields.
MetadataField<String> field = (MetadataField<String>) collection.getOutputFields().get(key);
if (field == null) {
throw new NotFoundException(String.format("Cannot find a metadata field with id '%s' from Catalog with Flavor '%s'.", key, flavorString));
}
SimpleDateFormat apiSdf = MetadataField.getSimpleDateFormatter(startDatePattern.getOr(field.getPattern().get()));
SimpleDateFormat sdf = MetadataField.getSimpleDateFormatter(field.getPattern().get());
DateTime newStartDate = new DateTime(apiSdf.parse(fields.get(key)), DateTimeZone.UTC);
if (field.getValue().isSome()) {
DateTime oldStartDate = new DateTime(sdf.parse(field.getValue().get()), DateTimeZone.UTC);
newStartDate = oldStartDate.withDate(newStartDate.year().get(), newStartDate.monthOfYear().get(), newStartDate.dayOfMonth().get());
}
collection.removeField(field);
collection.addField(MetadataField.copyMetadataFieldWithValue(field, sdf.format(newStartDate.toDate())));
} else if ("startTime".equals(key)) {
// Special handling for start time since in API v1 we expect start date and start time to be separate fields.
MetadataField<String> field = (MetadataField<String>) collection.getOutputFields().get("startDate");
if (field == null) {
throw new NotFoundException(String.format("Cannot find a metadata field with id '%s' from Catalog with Flavor '%s'.", "startDate", flavorString));
}
SimpleDateFormat apiSdf = MetadataField.getSimpleDateFormatter(startTimePattern.getOr("HH:mm"));
SimpleDateFormat sdf = MetadataField.getSimpleDateFormatter(field.getPattern().get());
DateTime newStartDate = new DateTime(apiSdf.parse(fields.get(key)), DateTimeZone.UTC);
if (field.getValue().isSome()) {
DateTime oldStartDate = new DateTime(sdf.parse(field.getValue().get()), DateTimeZone.UTC);
newStartDate = oldStartDate.withTime(newStartDate.hourOfDay().get(), newStartDate.minuteOfHour().get(), newStartDate.secondOfMinute().get(), newStartDate.millisOfSecond().get());
}
collection.removeField(field);
collection.addField(MetadataField.copyMetadataFieldWithValue(field, sdf.format(newStartDate.toDate())));
} else {
MetadataField<?> field = collection.getOutputFields().get(key);
if (field == null) {
throw new NotFoundException(String.format("Cannot find a metadata field with id '%s' from Catalog with Flavor '%s'.", key, flavorString));
}
collection.removeField(field);
collection.addField(MetadataField.copyMetadataFieldWithValue(field, fields.get(key)));
}
}
}
metadataList.add(adapter, collection);
}
setStartDateAndTimeIfUnset(metadataList);
return metadataList;
}
use of org.opencastproject.metadata.dublincore.EventCatalogUIAdapter in project opencast by opencast.
the class AbstractEventEndpoint method getEventMetadata.
@GET
@Path("{eventId}/metadata.json")
@Produces(MediaType.APPLICATION_JSON)
@RestQuery(name = "geteventmetadata", description = "Returns all the data related to the metadata tab in the event details modal as JSON", returnDescription = "All the data related to the event metadata tab as JSON", pathParameters = { @RestParameter(name = "eventId", description = "The event id", isRequired = true, type = RestParameter.Type.STRING) }, reponses = { @RestResponse(description = "Returns all the data related to the event metadata tab as JSON", responseCode = HttpServletResponse.SC_OK), @RestResponse(description = "No event with this identifier was found.", responseCode = HttpServletResponse.SC_NOT_FOUND) })
public Response getEventMetadata(@PathParam("eventId") String eventId) throws Exception {
Opt<Event> optEvent = getIndexService().getEvent(eventId, getIndex());
if (optEvent.isNone())
return notFound("Cannot find an event with id '%s'.", eventId);
MetadataList metadataList = new MetadataList();
List<EventCatalogUIAdapter> catalogUIAdapters = getIndexService().getEventCatalogUIAdapters();
catalogUIAdapters.remove(getIndexService().getCommonEventCatalogUIAdapter());
MediaPackage mediaPackage = getIndexService().getEventMediapackage(optEvent.get());
for (EventCatalogUIAdapter catalogUIAdapter : catalogUIAdapters) {
metadataList.add(catalogUIAdapter, catalogUIAdapter.getFields(mediaPackage));
}
metadataList.add(getIndexService().getCommonEventCatalogUIAdapter(), EventUtils.getEventMetadata(optEvent.get(), getIndexService().getCommonEventCatalogUIAdapter()));
final String wfState = optEvent.get().getWorkflowState();
if (wfState != null && WorkflowUtil.isActive(WorkflowInstance.WorkflowState.valueOf(wfState)))
metadataList.setLocked(Locked.WORKFLOW_RUNNING);
return okJson(metadataList.toJSON());
}
use of org.opencastproject.metadata.dublincore.EventCatalogUIAdapter in project opencast by opencast.
the class AbstractEventEndpoint method getCatalogAdapters.
@GET
@Path("catalogAdapters")
@Produces(MediaType.APPLICATION_JSON)
@RestQuery(name = "getcataloguiadapters", description = "Returns the available catalog UI adapters as JSON", returnDescription = "The catalog UI adapters as JSON", reponses = { @RestResponse(description = "Returns the available catalog UI adapters as JSON", responseCode = HttpServletResponse.SC_OK) })
public Response getCatalogAdapters() {
List<JValue> adapters = new ArrayList<>();
for (EventCatalogUIAdapter adapter : getIndexService().getEventCatalogUIAdapters()) {
List<Field> fields = new ArrayList<>();
fields.add(f("flavor", v(adapter.getFlavor().toString())));
fields.add(f("title", v(adapter.getUITitle())));
adapters.add(obj(fields));
}
return okJson(arr(adapters));
}
use of org.opencastproject.metadata.dublincore.EventCatalogUIAdapter in project opencast by opencast.
the class EventsEndpoint method updateEventMetadataByType.
@PUT
@Path("{eventId}/metadata")
@Produces({ "application/json", "application/v1.0.0+json" })
@RestQuery(name = "updateeventmetadata", description = "Update the metadata with the matching type of the specified event. For a metadata catalog there is the flavor such as 'dublincore/episode' and this is the unique type.", returnDescription = "", pathParameters = { @RestParameter(name = "eventId", description = "The event id", isRequired = true, type = STRING) }, restParameters = { @RestParameter(name = "type", isRequired = true, description = "The type of metadata to update", type = STRING), @RestParameter(name = "metadata", description = "Metadata catalog in JSON format", isRequired = true, type = STRING) }, reponses = { @RestResponse(description = "The metadata of the given namespace has been updated.", responseCode = HttpServletResponse.SC_OK), @RestResponse(description = "The request is invalid or inconsistent.", responseCode = HttpServletResponse.SC_BAD_REQUEST), @RestResponse(description = "The specified event does not exist.", responseCode = HttpServletResponse.SC_NOT_FOUND) })
public Response updateEventMetadataByType(@HeaderParam("Accept") String acceptHeader, @PathParam("eventId") String id, @QueryParam("type") String type, @FormParam("metadata") String metadataJSON) throws Exception {
Map<String, String> updatedFields;
JSONParser parser = new JSONParser();
try {
updatedFields = RequestUtils.getKeyValueMap(metadataJSON);
} catch (ParseException e) {
logger.debug("Unable to update event '{}' with metadata type '{}' and content '{}' because: {}", id, type, metadataJSON, ExceptionUtils.getStackTrace(e));
return RestUtil.R.badRequest(String.format("Unable to parse metadata fields as json from '%s' because '%s'", metadataJSON, ExceptionUtils.getStackTrace(e)));
} catch (IllegalArgumentException e) {
logger.debug("Unable to update event '{}' with metadata type '{}' and content '{}' because: {}", id, type, metadataJSON, ExceptionUtils.getStackTrace(e));
return RestUtil.R.badRequest(e.getMessage());
}
if (updatedFields == null || updatedFields.size() == 0) {
return RestUtil.R.badRequest(String.format("Unable to parse metadata fields as json from '%s' because there were no fields to update.", metadataJSON));
}
Opt<MediaPackageElementFlavor> flavor = getFlavor(type);
if (flavor.isNone()) {
return R.badRequest(String.format("Unable to parse type '%s' as a flavor so unable to find the matching catalog.", type));
}
MetadataCollection collection = null;
EventCatalogUIAdapter adapter = null;
for (final Event event : indexService.getEvent(id, externalIndex)) {
MetadataList metadataList = new MetadataList();
// Try the main catalog first as we load it from the index.
if (flavor.get().equals(eventCatalogUIAdapter.getFlavor())) {
collection = EventUtils.getEventMetadata(event, eventCatalogUIAdapter);
adapter = eventCatalogUIAdapter;
} else {
metadataList.add(eventCatalogUIAdapter, EventUtils.getEventMetadata(event, eventCatalogUIAdapter));
}
// Try the other catalogs
List<EventCatalogUIAdapter> catalogUIAdapters = getEventCatalogUIAdapters();
catalogUIAdapters.remove(eventCatalogUIAdapter);
MediaPackage mediaPackage = indexService.getEventMediapackage(event);
if (catalogUIAdapters.size() > 0) {
for (EventCatalogUIAdapter catalogUIAdapter : catalogUIAdapters) {
if (flavor.get().equals(catalogUIAdapter.getFlavor())) {
collection = catalogUIAdapter.getFields(mediaPackage);
adapter = eventCatalogUIAdapter;
} else {
metadataList.add(catalogUIAdapter, catalogUIAdapter.getFields(mediaPackage));
}
}
}
if (collection == null) {
return ApiResponses.notFound("Cannot find a catalog with type '%s' for event with id '%s'.", type, id);
}
for (String key : updatedFields.keySet()) {
if ("subjects".equals(key)) {
MetadataField<?> field = collection.getOutputFields().get(DublinCore.PROPERTY_SUBJECT.getLocalName());
Opt<Response> error = validateField(field, key, id, type, updatedFields);
if (error.isSome()) {
return error.get();
}
collection.removeField(field);
JSONArray subjectArray = (JSONArray) parser.parse(updatedFields.get(key));
collection.addField(MetadataField.copyMetadataFieldWithValue(field, StringUtils.join(subjectArray.iterator(), ",")));
} else if ("startDate".equals(key)) {
// Special handling for start date since in API v1 we expect start date and start time to be separate fields.
MetadataField<String> field = (MetadataField<String>) collection.getOutputFields().get(key);
Opt<Response> error = validateField(field, key, id, type, updatedFields);
if (error.isSome()) {
return error.get();
}
String apiPattern = field.getPattern().get();
if (configuredMetadataFields.containsKey("startDate")) {
apiPattern = configuredMetadataFields.get("startDate").getPattern().getOr(apiPattern);
}
SimpleDateFormat apiSdf = MetadataField.getSimpleDateFormatter(apiPattern);
SimpleDateFormat sdf = MetadataField.getSimpleDateFormatter(field.getPattern().get());
DateTime oldStartDate = new DateTime(sdf.parse(field.getValue().get()), DateTimeZone.UTC);
DateTime newStartDate = new DateTime(apiSdf.parse(updatedFields.get(key)), DateTimeZone.UTC);
DateTime updatedStartDate = oldStartDate.withDate(newStartDate.year().get(), newStartDate.monthOfYear().get(), newStartDate.dayOfMonth().get());
collection.removeField(field);
collection.addField(MetadataField.copyMetadataFieldWithValue(field, sdf.format(updatedStartDate.toDate())));
} else if ("startTime".equals(key)) {
// Special handling for start time since in API v1 we expect start date and start time to be separate fields.
MetadataField<String> field = (MetadataField<String>) collection.getOutputFields().get("startDate");
Opt<Response> error = validateField(field, "startDate", id, type, updatedFields);
if (error.isSome()) {
return error.get();
}
String apiPattern = "HH:mm";
if (configuredMetadataFields.containsKey("startTime")) {
apiPattern = configuredMetadataFields.get("startTime").getPattern().getOr(apiPattern);
}
SimpleDateFormat apiSdf = MetadataField.getSimpleDateFormatter(apiPattern);
SimpleDateFormat sdf = MetadataField.getSimpleDateFormatter(field.getPattern().get());
DateTime oldStartDate = new DateTime(sdf.parse(field.getValue().get()), DateTimeZone.UTC);
DateTime newStartDate = new DateTime(apiSdf.parse(updatedFields.get(key)), DateTimeZone.UTC);
DateTime updatedStartDate = oldStartDate.withTime(newStartDate.hourOfDay().get(), newStartDate.minuteOfHour().get(), newStartDate.secondOfMinute().get(), newStartDate.millisOfSecond().get());
collection.removeField(field);
collection.addField(MetadataField.copyMetadataFieldWithValue(field, sdf.format(updatedStartDate.toDate())));
} else {
MetadataField<?> field = collection.getOutputFields().get(key);
Opt<Response> error = validateField(field, key, id, type, updatedFields);
if (error.isSome()) {
return error.get();
}
collection.removeField(field);
collection.addField(MetadataField.copyMetadataFieldWithValue(field, updatedFields.get(key)));
}
}
metadataList.add(adapter, collection);
indexService.updateEventMetadata(id, metadataList, externalIndex);
return ApiResponses.Json.noContent(ApiVersion.VERSION_1_0_0);
}
return ApiResponses.notFound("Cannot find an event with id '%s'.", id);
}
Aggregations