Search in sources :

Example 6 with Fn

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));
        }
    }
}
Also used : PropertyName(org.opencastproject.assetmanager.api.PropertyName) Fn(com.entwinemedia.fn.Fn) Random(java.util.Random) AResult(org.opencastproject.assetmanager.api.query.AResult) ASelectQuery(org.opencastproject.assetmanager.api.query.ASelectQuery) Property(org.opencastproject.assetmanager.api.Property) Parameters(junitparams.Parameters) Test(org.junit.Test)

Example 7 with Fn

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);
}
Also used : Fn(com.entwinemedia.fn.Fn) IOException(java.io.IOException) File(java.io.File) AssetStoreException(org.opencastproject.assetmanager.impl.storage.AssetStoreException)

Example 8 with Fn

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);
        }
    };
}
Also used : SnapshotDto(org.opencastproject.assetmanager.impl.persistence.SnapshotDto) Fn(com.entwinemedia.fn.Fn) Tuple(com.mysema.query.Tuple)

Example 9 with Fn

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);
}
Also used : Set(java.util.Set) HashMap(java.util.HashMap) Fn2(com.entwinemedia.fn.Fn2) BooleanExpression(com.mysema.query.types.expr.BooleanExpression) Opt(com.entwinemedia.fn.data.Opt) List(java.util.List) Property(org.opencastproject.assetmanager.api.Property) EntityPath(com.mysema.query.types.EntityPath) Fn(com.entwinemedia.fn.Fn) JPAQuery(com.mysema.query.jpa.impl.JPAQuery) Snapshot(org.opencastproject.assetmanager.api.Snapshot) BooleanExpression(com.mysema.query.types.expr.BooleanExpression) Expression(com.mysema.query.types.Expression) HashMap(java.util.HashMap) Map(java.util.Map)

Example 10 with Fn

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);
    }
}
Also used : WebApplicationException(javax.ws.rs.WebApplicationException) SeriesSearchQuery(org.opencastproject.index.service.impl.index.series.SeriesSearchQuery) Fn(com.entwinemedia.fn.Fn) SearchResultItem(org.opencastproject.matterhorn.search.SearchResultItem) Date(java.util.Date) SearchIndexException(org.opencastproject.matterhorn.search.SearchIndexException) SeriesException(org.opencastproject.series.api.SeriesException) IndexServiceException(org.opencastproject.index.service.exception.IndexServiceException) WebApplicationException(javax.ws.rs.WebApplicationException) ParseException(org.json.simple.parser.ParseException) UnauthorizedException(org.opencastproject.security.api.UnauthorizedException) NotFoundException(org.opencastproject.util.NotFoundException) Series(org.opencastproject.index.service.impl.index.series.Series) SortCriterion(org.opencastproject.matterhorn.search.SortCriterion) JValue(com.entwinemedia.fn.data.json.JValue) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) RestQuery(org.opencastproject.util.doc.rest.RestQuery)

Aggregations

Fn (com.entwinemedia.fn.Fn)16 Opt (com.entwinemedia.fn.data.Opt)5 JValue (com.entwinemedia.fn.data.json.JValue)5 JObject (com.entwinemedia.fn.data.json.JObject)4 ParseException (org.json.simple.parser.ParseException)4 ArrayList (java.util.ArrayList)3 Date (java.util.Date)3 NotFoundException (org.opencastproject.util.NotFoundException)3 IOException (java.io.IOException)2 MessageDigest (java.security.MessageDigest)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 SimpleDateFormat (java.text.SimpleDateFormat)2 HashMap (java.util.HashMap)2 List (java.util.List)2 Map (java.util.Map)2 EntityManager (javax.persistence.EntityManager)2 Path (javax.ws.rs.Path)2 Produces (javax.ws.rs.Produces)2 JSONArray (org.json.simple.JSONArray)2 Property (org.opencastproject.assetmanager.api.Property)2