use of com.entwinemedia.fn.Fn in project opencast by opencast.
the class AbstractAssetManagerPropertyRetrievalTest method testPropertyRetrieval.
/**
* Create some media packages and associate some random properties to each of them.
* Then iterate all created properties and create a query for each of them.
*/
@Test
@Parameters
public void testPropertyRetrieval(final Params params) {
// create a set of media packages and add them to the asset manager
final String[] mps = createAndAddMediaPackagesSimple(params.mpCount, 1, 1);
final Random random = new Random(System.nanoTime());
// create a set of random property names
final PropertyName[] propertyNames = createRandomPropertyNames(params.propertyNameSetSize);
// create a random amount of random properties for each media package
final Stream<Property> props = $(mps).bind(new Fn<String, Stream<Property>>() {
@Override
public Stream<Property> apply(final String mp) {
// create a random amount of random properties
return Stream.cont(inc()).take(random.nextInt(params.maxProps - params.minProps + 1) + params.minProps).map(new Fn<Integer, Property>() {
@Override
public Property apply(Integer ignore) {
// try to pick a free property a 100 times
for (int i = 0; i < 100; i++) {
// randomly select a property name
final PropertyName pName = propertyNames[random.nextInt(propertyNames.length)];
// check if the selected property is already associated with the current media package
final ASelectQuery doesPropertyExist = q.select(q.properties(pName)).where(q.mediaPackageId(mp));
if (sizeOf(doesPropertyExist.run().getRecords().bind(ARecords.getProperties)) == 0) {
// create a property with a randomly picked value
final Property p = Property.mk(PropertyId.mk(mp, pName), params.values[random.nextInt(params.values.length)]);
if (am.setProperty(p))
return p;
}
}
fail("Cannot pick another random property that has not been inserted yet");
return null;
}
});
}
}).eval();
assertThat("Number of generated properties", sizeOf(props), allOf(greaterThanOrEqualTo(params.mpCount * params.minProps), lessThanOrEqualTo(params.mpCount * params.maxProps)));
// iterate all properties and try to retrieve them from the AssetManager
for (final Property prop : props) {
final AResult r = q.select(params.mkTarget.apply(prop)).where(params.mkWhere.apply(prop)).run();
// get all properties of the result records
assertThat("Number of records", r.getSize(), params.expectRecords);
final Stream<Property> allProps = r.getRecords().bind(ARecords.getProperties);
assertThat("Total number of properties: " + allProps.mkString(", "), sizeOf(allProps), params.expectPropertiesTotal);
assertThat("Total number of snapshots", sizeOf(r.getRecords().bind(ARecords.getSnapshot)), params.expectSnapshotsTotal);
final Stream<Property> findSavedProperty = r.getRecords().bind(ARecords.getProperties).filter(Booleans.eq(prop));
if (params.expectContainsSavedProperty) {
assertThat("Contains saved property", findSavedProperty, hasItem(prop));
}
}
}
use of com.entwinemedia.fn.Fn in project opencast by opencast.
the class AbstractFileSystemAssetStore method copy.
@Override
public boolean copy(final StoragePath from, final StoragePath to) throws AssetStoreException {
return findStoragePathFile(from).map(new Fn<File, Boolean>() {
@Override
public Boolean apply(File f) {
final File t = createFile(to, f);
mkParent(t);
logger.debug("Copying {} to {}", f.getAbsolutePath(), t.getAbsolutePath());
try {
link(f, t, true);
} catch (IOException e) {
logger.error("Error copying archive file {} to {}", f, t);
throw new AssetStoreException(e);
}
return true;
}
}).getOr(false);
}
use of com.entwinemedia.fn.Fn in project opencast by opencast.
the class AbstractASelectQuery method toARecord.
/**
* Transform a Querydsl result {@link Tuple} into an {@link ARecord}.
* To do the transformation I need to know what targets have been selected.
*/
private Fn<Tuple, ARecordImpl> toARecord(final SelectQueryContribution c) {
return new Fn<Tuple, ARecordImpl>() {
@Override
public ARecordImpl apply(Tuple tuple) {
final String mediaPackageId;
SnapshotDto snapshotDto = null;
final long id;
// Only fetch the snapshot if it is in the fetch list.
if (c.fetch.exists(Booleans.<Expression<?>>eq(Q_SNAPSHOT))) {
snapshotDto = RequireUtil.notNull(tuple.get(Q_SNAPSHOT), "[BUG] snapshot table data");
id = snapshotDto.getId();
mediaPackageId = snapshotDto.getMediaPackageId();
} else {
// The media package ID and the snapshot's database ID must always be fetched.
id = RequireUtil.notNull(tuple.get(Q_SNAPSHOT.id), "[BUG] snapshot table id");
mediaPackageId = RequireUtil.notNull(tuple.get(Q_SNAPSHOT.mediaPackageId), "[BUG] snapshot table media package id");
}
return new ARecordImpl(id, mediaPackageId, Stream.<Property>empty(), snapshotDto);
}
};
}
use of com.entwinemedia.fn.Fn in project opencast by opencast.
the class AbstractASelectQuery method run.
private AResult run(JPAQueryFactory f) {
// run query and map the result to records
final long startTime = System.nanoTime();
// resolve AST
final SelectQueryContribution r = contributeSelect(f);
final boolean toFetchProperties = r.fetch.exists(Booleans.<Expression<?>>eq(QPropertyDto.propertyDto));
// # create Querydsl query
final JPAQuery q = f.query();
// # from
{
// Make sure that the snapshotDto is always contained in the from clause because the media package ID and
// the ID are always selected.
// Use a mutable hash set to be able to use the removeAll operation.
final Set<EntityPath<?>> from = Stream.<EntityPath<?>>mk(Q_SNAPSHOT).append(// all collected from clauses
r.from).append(// all from clauses from the joins
r.join.map(Join.getFrom)).toSet(SetB.MH);
// Now remove everything that will be joined. Adding them in both the from and a join
// clause is not allowed.
from.removeAll(r.join.map(Join.getJoin).toSet());
q.from(JpaFns.toEntityPathArray(from));
}
// # join
if (!r.join.isEmpty()) {
// Group joins by entity and combine all "on" clauses with "or" expressions.
// This way there is only one join clause per distinct entity which eliminates the need to alias entities
// like this `new QPropertyDto("alias")`.
// Entity aliasing produces many issues which seem to cause a huge rewrite of the query building mechanism
// so it should be prevented at all costs.
final Map<EntityPath<?>, BooleanExpression> joins = r.join.foldl(new HashMap<EntityPath<?>, BooleanExpression>(), new Fn2<Map<EntityPath<?>, BooleanExpression>, Join, Map<EntityPath<?>, BooleanExpression>>() {
@Override
public Map<EntityPath<?>, BooleanExpression> apply(Map<EntityPath<?>, BooleanExpression> sum, Join join) {
// get the on expression saved with the join, may be null
final BooleanExpression existing = sum.get(join.join);
final BooleanExpression combined;
// combine the existing and the current expression
if (existing == null) {
combined = join.on;
} else if (existing.equals(join.on)) {
// if both expressions are equal there is no need to combine them
combined = existing;
} else {
// if different combine with logical "or"
combined = existing.or(join.on);
}
sum.put(join.join, combined);
return sum;
}
});
for (final Map.Entry<EntityPath<?>, BooleanExpression> j : joins.entrySet()) {
q.leftJoin(j.getKey()).on(j.getValue());
}
}
// # where
q.where(r.where.orNull());
// # paging
for (Integer a : r.offset) {
q.offset(a);
}
for (Integer a : r.limit) {
q.limit(a);
}
// # order
for (OrderSpecifier<?> a : r.order) {
q.orderBy(a);
}
// # distinct
if (!toFetchProperties) {
// if no properties shall be fetched the result set can be distinct
q.distinct();
}
// # fetch
// create parameters for fetch clause, i.e. Querydsl's list() method
final List<Expression<?>> fetch;
{
// check if the media package ID needs to be selected separately
if (r.fetch.exists(MandatoryFetch.exists)) {
fetch = r.fetch.toList();
} else {
fetch = r.fetch.append(MandatoryFetch.fetch).toList();
}
}
// Run the query and transform the result into records
final Stream<ARecordImpl> records;
{
// run query
am.getDb().logQuery(q);
final List<Tuple> result = q.list(JpaFns.toExpressionArray(fetch));
logger.debug("Pure query ms " + (System.nanoTime() - startTime) / 1000000);
// map result based on the fact whether properties have been fetched or not
if (!toFetchProperties) {
// No properties have been fetched -> each result row (tuple) is a distinct record (snapshot).
records = $($(result).map(toARecord(r))).map(new Fn<ARecordImpl, ARecordImpl>() {
@Override
public ARecordImpl apply(ARecordImpl record) {
Opt<Snapshot> snapshotOpt = record.getSnapshot();
Snapshot snapshot = null;
if (snapshotOpt.isSome()) {
// make sure the delivered media package has valid URIs
snapshot = am.getHttpAssetProvider().prepareForDelivery(snapshotOpt.get());
}
return new ARecordImpl(record.getSnapshotId(), record.getMediaPackageId(), record.getProperties(), snapshot);
}
});
} else {
logger.trace("Fetched properties");
// Properties have been fetched -> there may be multiple rows (tuples) per snapshot because of the join with the property table.
// Extract records and properties and link them together.
// group properties after their media package ID and make sure that no duplicate properties occur
final Map<String, Set<Property>> propertiesPerMp = $(result).bind(toProperty).foldl(new HashMap<String, Set<Property>>(), new Fn2<Map<String, Set<Property>>, Property, Map<String, Set<Property>>>() {
@Override
public Map<String, Set<Property>> apply(Map<String, Set<Property>> sum, Property p) {
final String mpId = p.getId().getMediaPackageId();
final Set<Property> props = sum.get(mpId);
if (props != null) {
props.add(p);
} else {
sum.put(mpId, SetB.MH.mk(p));
}
return sum;
}
});
// group records after their media package ID
final Map<String, List<ARecordImpl>> distinctRecords = $($(result).map(toARecord(r)).toSet()).groupMulti(ARecordImpl.getMediaPackageId);
records = $(distinctRecords.values()).bind(new Fn<List<ARecordImpl>, Iterable<ARecordImpl>>() {
@Override
public Iterable<ARecordImpl> apply(List<ARecordImpl> records) {
return $(records).map(new Fn<ARecordImpl, ARecordImpl>() {
@Override
public ARecordImpl apply(ARecordImpl record) {
final Set<Property> properties = propertiesPerMp.get(record.getMediaPackageId());
final Stream<Property> p = properties != null ? $(properties) : Stream.<Property>empty();
Snapshot snapshot = null;
Opt<Snapshot> snapshotOpt = record.getSnapshot();
if (snapshotOpt.isSome()) {
// make sure the delivered media package has valid URIs
snapshot = am.getHttpAssetProvider().prepareForDelivery(snapshotOpt.get());
}
return new ARecordImpl(record.getSnapshotId(), record.getMediaPackageId(), p, snapshot);
}
});
}
});
}
}
final long searchTime = (System.nanoTime() - startTime) / 1000000;
logger.debug("Complete query ms " + searchTime);
return new AResultImpl(AbstractASelectQuery.<ARecord>vary(records), sizeOf(records), r.offset.getOr(0), r.limit.getOr(-1), searchTime);
}
use of com.entwinemedia.fn.Fn in project opencast by opencast.
the class SeriesEndpoint method getSeriesList.
@GET
@Path("")
@Produces({ "application/json", "application/v1.0.0+json" })
@RestQuery(name = "getseries", description = "Returns a list of series.", returnDescription = "", restParameters = { @RestParameter(name = "filter", isRequired = false, description = "A comma seperated list of filters to limit the results with. A filter is the filter's name followed by a colon \":\" and then the value to filter with so it is the form <Filter Name>:<Value to Filter With>.", type = STRING), @RestParameter(name = "sort", description = "Sort the results based upon a list of comma seperated sorting criteria. In the comma seperated list each type of sorting is specified as a pair such as: <Sort Name>:ASC or <Sort Name>:DESC. Adding the suffix ASC or DESC sets the order as ascending or descending order and is mandatory.", isRequired = false, type = STRING), @RestParameter(name = "limit", description = "The maximum number of results to return for a single request.", isRequired = false, type = RestParameter.Type.INTEGER), @RestParameter(name = "offset", description = "Number of results to skip based on the limit. 0 is the first set of results up to the limit, 1 is the second set of results after the first limit, 2 is third set of results after skipping the first two sets of results etc.", isRequired = false, type = RestParameter.Type.INTEGER) }, reponses = { @RestResponse(description = "A (potentially empty) list of series is returned.", responseCode = HttpServletResponse.SC_OK) })
public Response getSeriesList(@HeaderParam("Accept") String acceptHeader, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("order") String order, @QueryParam("offset") int offset, @QueryParam("limit") int limit) throws UnauthorizedException {
try {
SeriesSearchQuery query = new SeriesSearchQuery(securityService.getOrganization().getId(), securityService.getUser());
Option<String> optSort = Option.option(trimToNull(sort));
if (offset > 0) {
query.withOffset(offset);
}
// If limit is 0, we set the default limit
query.withLimit(limit < 1 ? DEFAULT_LIMIT : limit);
// Parse the filters
if (StringUtils.isNotBlank(filter)) {
for (String f : filter.split(",")) {
String[] filterTuple = f.split(":");
if (filterTuple.length != 2) {
logger.info("No value for filter {} in filters list: {}", filterTuple[0], filter);
continue;
}
String name = filterTuple[0];
String value = filterTuple[1];
if ("managedAcl".equals(name)) {
query.withAccessPolicy(value);
} else if ("contributors".equals(name)) {
query.withContributor(value);
} else if ("CreationDate".equals(name)) {
if (name.split("/").length == 2) {
try {
Tuple<Date, Date> fromAndToCreationRange = getFromAndToCreationRange(name.split("/")[0], name.split("/")[1]);
query.withCreatedFrom(fromAndToCreationRange.getA());
query.withCreatedTo(fromAndToCreationRange.getB());
} catch (IllegalArgumentException e) {
return RestUtil.R.badRequest(e.getMessage());
}
}
query.withCreator(value);
} else if ("Creator".equals(name)) {
query.withCreator(value);
} else if ("textFilter".equals(name)) {
query.withText("*" + value + "*");
} else if ("language".equals(name)) {
query.withLanguage(value);
} else if ("license".equals(name)) {
query.withLicense(value);
} else if ("organizers".equals(name)) {
query.withOrganizer(value);
} else if ("subject".equals(name)) {
query.withSubject(value);
} else if ("title".equals(name)) {
query.withTitle(value);
}
}
}
if (optSort.isSome()) {
Set<SortCriterion> sortCriteria = RestUtils.parseSortQueryParameter(optSort.get());
for (SortCriterion criterion : sortCriteria) {
switch(criterion.getFieldName()) {
case SeriesIndexSchema.TITLE:
query.sortByTitle(criterion.getOrder());
break;
case SeriesIndexSchema.CONTRIBUTORS:
query.sortByContributors(criterion.getOrder());
break;
case SeriesIndexSchema.CREATOR:
query.sortByOrganizers(criterion.getOrder());
break;
case EventIndexSchema.CREATED:
query.sortByCreatedDateTime(criterion.getOrder());
break;
default:
logger.info("Unknown filter criteria {}", criterion.getFieldName());
return Response.status(SC_BAD_REQUEST).build();
}
}
}
logger.trace("Using Query: " + query.toString());
SearchResult<Series> result = externalIndex.getByQuery(query);
return ApiResponses.Json.ok(VERSION_1_0_0, arr($(result.getItems()).map(new Fn<SearchResultItem<Series>, JValue>() {
@Override
public JValue apply(SearchResultItem<Series> a) {
final Series s = a.getSource();
JValue subjects;
if (s.getSubject() == null) {
subjects = arr();
} else {
subjects = arr(splitSubjectIntoArray(s.getSubject()));
}
Date createdDate = s.getCreatedDateTime();
return obj(f("identifier", v(s.getIdentifier())), f("title", v(s.getTitle())), f("creator", v(s.getCreator(), BLANK)), f("created", v(createdDate != null ? toUTC(createdDate.getTime()) : null, BLANK)), f("subjects", subjects), f("contributors", arr($(s.getContributors()).map(Functions.stringToJValue))), f("organizers", arr($(s.getOrganizers()).map(Functions.stringToJValue))), f("publishers", arr($(s.getPublishers()).map(Functions.stringToJValue))));
}
}).toList()));
} catch (Exception e) {
logger.warn("Could not perform search query: {}", ExceptionUtils.getStackTrace(e));
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
}
Aggregations