use of com.entwinemedia.fn.data.Opt in project opencast by opencast.
the class MetadataField method createIterableStringMetadataField.
/**
* Create a metadata field of type iterable String
*
* @param inputID
* The identifier of the new metadata field
* @param label
* The label of the new metadata field
* @param readOnly
* Define if the new metadata field can be or not edited
* @param required
* Define if the new metadata field is or not required
* @param isTranslatable
* If the field value is not human readable and should be translated before
* @param collection
* If the field has a limited list of possible value, the option should contain this one. Otherwise it should
* be none.
* @param order
* The ui order for the new field, 0 at the top and progressively down from there.
* @return the new metadata field
*/
public static MetadataField<Iterable<String>> createIterableStringMetadataField(String inputID, Opt<String> outputID, String label, boolean readOnly, boolean required, Opt<Boolean> isTranslatable, Opt<Map<String, String>> collection, Opt<String> collectionId, Opt<Integer> order, Opt<String> namespace) {
Fn<Opt<Iterable<String>>, JValue> iterableToJSON = new Fn<Opt<Iterable<String>>, JValue>() {
@Override
public JValue apply(Opt<Iterable<String>> value) {
if (value.isNone())
return arr();
Object val = value.get();
List<JValue> list = new ArrayList<>();
if (val instanceof String) {
// The value is a string so we need to split it.
String stringVal = (String) val;
for (String entry : stringVal.split(",")) {
list.add(v(entry, Jsons.BLANK));
}
} else {
// The current value is just an iterable string.
for (Object v : value.get()) {
list.add(v(v, Jsons.BLANK));
}
}
return arr(list);
}
};
Fn<Object, Iterable<String>> jsonToIterable = new Fn<Object, Iterable<String>>() {
@Override
public Iterable<String> apply(Object arrayIn) {
JSONArray array = (JSONArray) arrayIn;
if (array == null)
return null;
String[] arrayOut = new String[array.size()];
for (int i = 0; i < array.size(); i++) {
arrayOut[i] = (String) array.get(i);
}
return Arrays.asList(arrayOut);
}
};
return new MetadataField<>(inputID, outputID, label, readOnly, required, new ArrayList<String>(), isTranslatable, Type.ITERABLE_TEXT, JsonType.TEXT, collection, collectionId, iterableToJSON, jsonToIterable, order, namespace);
}
use of com.entwinemedia.fn.data.Opt in project opencast by opencast.
the class MetadataField method createMixedIterableStringMetadataField.
/**
* Create a metadata field of type mixed iterable String
*
* @param inputID
* The identifier of the new metadata field
* @param label
* The label of the new metadata field
* @param readOnly
* Define if the new metadata field can be or not edited
* @param required
* Define if the new metadata field is or not required
* @param isTranslatable
* If the field value is not human readable and should be translated before
* @param collection
* If the field has a limited list of possible value, the option should contain this one. Otherwise it should
* be none.
* @param order
* The ui order for the new field, 0 at the top and progressively down from there.
* @return the new metadata field
*/
public static MetadataField<Iterable<String>> createMixedIterableStringMetadataField(String inputID, Opt<String> outputID, String label, boolean readOnly, boolean required, Opt<Boolean> isTranslatable, Opt<Map<String, String>> collection, Opt<String> collectionId, Opt<Integer> order, Opt<String> namespace) {
Fn<Opt<Iterable<String>>, JValue> iterableToJSON = new Fn<Opt<Iterable<String>>, JValue>() {
@Override
public JValue apply(Opt<Iterable<String>> value) {
if (value.isNone())
return arr();
Object val = value.get();
List<JValue> list = new ArrayList<>();
if (val instanceof String) {
// The value is a string so we need to split it.
String stringVal = (String) val;
for (String entry : stringVal.split(",")) {
if (StringUtils.isNotBlank(entry))
list.add(v(entry, Jsons.BLANK));
}
} else {
// The current value is just an iterable string.
for (Object v : value.get()) {
list.add(v(v, Jsons.BLANK));
}
}
return arr(list);
}
};
Fn<Object, Iterable<String>> jsonToIterable = new Fn<Object, Iterable<String>>() {
@Override
public Iterable<String> apply(Object arrayIn) {
JSONParser parser = new JSONParser();
JSONArray array;
if (arrayIn instanceof String) {
try {
array = (JSONArray) parser.parse((String) arrayIn);
} catch (ParseException e) {
throw new IllegalArgumentException("Unable to parse Mixed Iterable value into a JSONArray:", e);
}
} else {
array = (JSONArray) arrayIn;
}
if (array == null)
return new ArrayList<>();
String[] arrayOut = new String[array.size()];
for (int i = 0; i < array.size(); i++) {
arrayOut[i] = (String) array.get(i);
}
return Arrays.asList(arrayOut);
}
};
return new MetadataField<>(inputID, outputID, label, readOnly, required, new ArrayList<String>(), isTranslatable, Type.MIXED_TEXT, JsonType.MIXED_TEXT, collection, collectionId, iterableToJSON, jsonToIterable, order, namespace);
}
use of com.entwinemedia.fn.data.Opt 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);
}
use of com.entwinemedia.fn.data.Opt in project opencast by opencast.
the class SchedulerServiceImpl method repopulate.
@Override
public void repopulate(final String indexName) {
notEmpty(indexName, "indexName");
final String destinationId = SchedulerItem.SCHEDULER_QUEUE_PREFIX + WordUtils.capitalize(indexName);
Organization organization = new DefaultOrganization();
SecurityUtil.runAs(securityService, organization, SecurityUtil.createSystemUser(systemUserName, organization), new Effect0() {
@Override
protected void run() {
int current = 1;
AQueryBuilder query = assetManager.createQuery();
Props p = new Props(query);
AResult result = query.select(query.snapshot(), p.agent().target(), p.start().target(), p.end().target(), p.optOut().target(), p.presenters().target(), p.reviewDate().target(), p.reviewStatus().target(), p.recordingStatus().target(), p.recordingLastHeard().target(), query.propertiesOf(CA_NAMESPACE)).where(withOrganization(query).and(query.hasPropertiesOf(p.namespace())).and(withVersion(query))).run();
final int total = (int) Math.min(result.getSize(), Integer.MAX_VALUE);
logger.info("Re-populating '{}' index with scheduled events. There are {} scheduled events to add to the index.", indexName, total);
final int responseInterval = (total < 100) ? 1 : (total / 100);
try {
for (ARecord record : result.getRecords()) {
String agentId = record.getProperties().apply(Properties.getString(AGENT_CONFIG));
boolean optOut = record.getProperties().apply(Properties.getBoolean(OPTOUT_CONFIG));
Date start = record.getProperties().apply(Properties.getDate(START_DATE_CONFIG));
Date end = record.getProperties().apply(Properties.getDate(END_DATE_CONFIG));
Set<String> presenters = getPresenters(record.getProperties().apply(getStringOpt(PRESENTERS_CONFIG)).getOr(""));
boolean blacklisted = isBlacklisted(record.getMediaPackageId(), start, end, agentId, presenters);
Map<String, String> caMetadata = record.getProperties().filter(filterByNamespace._2(CA_NAMESPACE)).group(toKey, toValue);
ReviewStatus reviewStatus = record.getProperties().apply(getStringOpt(REVIEW_STATUS_CONFIG)).map(toReviewStatus).getOr(UNSENT);
Date reviewDate = record.getProperties().apply(Properties.getDateOpt(REVIEW_DATE_CONFIG)).orNull();
Opt<String> recordingStatus = record.getProperties().apply(Properties.getStringOpt(RECORDING_STATE_CONFIG));
Opt<Long> lastHeard = record.getProperties().apply(Properties.getLongOpt(RECORDING_LAST_HEARD_CONFIG));
Opt<AccessControlList> acl = loadEpisodeAclFromAsset(record.getSnapshot().get());
Opt<DublinCoreCatalog> dublinCore = loadEpisodeDublinCoreFromAsset(record.getSnapshot().get());
sendUpdateAddEvent(record.getMediaPackageId(), acl, dublinCore, Opt.some(start), Opt.some(end), Opt.some(presenters), Opt.some(agentId), Opt.some(caMetadata), Opt.some(optOut));
messageSender.sendObjectMessage(destinationId, MessageSender.DestinationType.Queue, SchedulerItem.updateBlacklist(record.getMediaPackageId(), blacklisted));
messageSender.sendObjectMessage(destinationId, MessageSender.DestinationType.Queue, SchedulerItem.updateReviewStatus(record.getMediaPackageId(), reviewStatus, reviewDate));
if (((current % responseInterval) == 0) || (current == total)) {
messageSender.sendObjectMessage(IndexProducer.RESPONSE_QUEUE, MessageSender.DestinationType.Queue, IndexRecreateObject.update(indexName, IndexRecreateObject.Service.Scheduler, total, current));
}
if (recordingStatus.isSome() && lastHeard.isSome())
sendRecordingUpdate(new RecordingImpl(record.getMediaPackageId(), recordingStatus.get(), lastHeard.get()));
current++;
}
} catch (Exception e) {
logger.warn("Unable to index scheduled instances:", e);
throw new ServiceException(e.getMessage());
}
}
});
SecurityUtil.runAs(securityService, organization, SecurityUtil.createSystemUser(systemUserName, organization), new Effect0() {
@Override
protected void run() {
messageSender.sendObjectMessage(IndexProducer.RESPONSE_QUEUE, MessageSender.DestinationType.Queue, IndexRecreateObject.end(indexName, IndexRecreateObject.Service.Scheduler));
}
});
}
use of com.entwinemedia.fn.data.Opt in project opencast by opencast.
the class SchedulerServiceRemoteImpl method getTechnicalMetadata.
@Override
public TechnicalMetadata getTechnicalMetadata(String eventId) throws NotFoundException, UnauthorizedException, SchedulerException {
HttpGet get = new HttpGet(eventId.concat("/technical.json"));
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
try {
if (response != null) {
if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
throw new NotFoundException("Event with id '" + eventId + "' not found on remote scheduler service!");
} else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
logger.info("Unauthorized to get the technical metadata of the event {}.", eventId);
throw new UnauthorizedException("Unauthorized to get the technical metadata of the event " + eventId);
} else {
String technicalMetadataJson = EntityUtils.toString(response.getEntity(), UTF_8);
JSONObject json = (JSONObject) parser.parse(technicalMetadataJson);
final String recordingId = (String) json.get("id");
final Date start = new Date(DateTimeSupport.fromUTC((String) json.get("start")));
final Date end = new Date(DateTimeSupport.fromUTC((String) json.get("end")));
final boolean optOut = (Boolean) json.get("optOut");
final String location = (String) json.get("location");
final Set<String> presenters = new HashSet<>();
JSONArray presentersArr = (JSONArray) json.get("presenters");
for (int i = 0; i < presentersArr.size(); i++) {
presenters.add((String) presentersArr.get(i));
}
final Map<String, String> wfProperties = new HashMap<>();
JSONObject wfPropertiesObj = (JSONObject) json.get("wfProperties");
Set<Entry<String, String>> entrySet = wfPropertiesObj.entrySet();
for (Entry<String, String> entry : entrySet) {
wfProperties.put(entry.getKey(), entry.getValue());
}
final Map<String, String> agentConfig = new HashMap<>();
JSONObject agentConfigObj = (JSONObject) json.get("agentConfig");
entrySet = agentConfigObj.entrySet();
for (Entry<String, String> entry : entrySet) {
agentConfig.put(entry.getKey(), entry.getValue());
}
String status = (String) json.get("state");
String lastHeard = (String) json.get("lastHeardFrom");
Recording recording = null;
if (StringUtils.isNotBlank(status) && StringUtils.isNotBlank(lastHeard)) {
recording = new RecordingImpl(recordingId, status, DateTimeSupport.fromUTC(lastHeard));
}
final Opt<Recording> recordingOpt = Opt.nul(recording);
logger.info("Successfully get the technical metadata of event '{}' from the remote scheduler service", eventId);
return new TechnicalMetadataImpl(recordingId, location, start, end, optOut, presenters, wfProperties, agentConfig, recordingOpt);
}
}
} catch (NotFoundException e) {
throw e;
} catch (UnauthorizedException e) {
throw e;
} catch (Exception e) {
throw new SchedulerException("Unable to parse the technical metadata from remote scheduler service: " + e);
} finally {
closeConnection(response);
}
throw new SchedulerException("Unable to get the technical metadata from remote scheduler service");
}
Aggregations