CollectionRelationshipProvider.java revision c4d029d82df44c016eb7a1d4cf6e8b441aa3d4bc
/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2015 ForgeRock AS.
*/
/**
* A {@link RelationshipProvider} representing a collection (array) of relationships for the given field.
*/
class CollectionRelationshipProvider extends RelationshipProvider implements CollectionResourceProvider {
/**
* Setup logging for the {@link CollectionRelationshipProvider}.
*/
final static QueryFilterVisitor<QueryFilter<JsonPointer>, Boolean, JsonPointer> VISITOR = new RelationshipQueryFilterVisitor();
private final RequestHandler requestHandler;
/**
* Create a new relationship set for the given managed resource
* @param connectionFactory Connection factory used to access the repository
* @param propertyName Name of property on first object represents the relationship
*/
public CollectionRelationshipProvider(final ConnectionFactory connectionFactory, final ResourcePath resourcePath,
super(connectionFactory, resourcePath, propertyName, isReverse, activityLogger,managedObjectSyncService);
router.addRoute(RoutingMode.STARTS_WITH, uriTemplate("{firstId}/" + propertyName.leaf()), Resources.newCollection(this));
this.requestHandler = router;
}
/** {@inheritDoc} */
public RequestHandler asRequestHandler() {
return requestHandler;
}
/** {@inheritDoc} */
public Promise<JsonValue, ResourceException> getRelationshipValueForResource(final Context context, final String resourceId) {
try {
return true;
}
}).getOrThrowUninterruptibly(); // call get() so we block until we have all items
}
return newResultPromise(buf);
} catch (ResourceException e) {
return e.asPromise();
}
}
/** {@inheritDoc} */
// delete all relationships not in this array
public Promise<JsonValue, ResourceException> setRelationshipValueForResource(Context context, String resourceId, JsonValue value) {
// Set of relation ids for updating (don't delete)
// Set of relationships to perform an update on (have an _id)
// Set of relationships to create (no _id field)
// JsonValue array to contain persisted relations
try {
// Split relationships in to to-be-updated (_id present) and to-be-created
} else { // no id. create
}
}
// Call get() so we block until they are deleted.
} else {
// We didn't get any relations to persist. Clear and return empty array.
return newResultPromise(results);
}
/*
* Create or update relationships
*/
// List of promises returned by update and create to when() on later
}
}
}
return value;
}
});
} catch (ResourceException e) {
return e.asPromise();
}
}
/**
* Clear all relationships not present in {@code relationshipsToKeep}.
*
* @param context The current context.
* @param resourceId The resource whose relationships we wish to clear
* @param relationshipsToKeep Set of relationship ids that should not be deleted
* @return A promised JsonValue array of delete responses
*/
private Promise<JsonValue, ResourceException> clearNotIn(final Context context, final String resourceId,
return getRelationshipValueForResource(context, resourceId).thenAsync(new AsyncFunction<JsonValue, JsonValue, ResourceException>() {
public Promise<JsonValue, ResourceException> apply(JsonValue existingRelationships) throws ResourceException {
// Delete if we're not told to keep this id
}
}
}
return result;
}
});
}
});
}
/** {@inheritDoc} */
public Promise<JsonValue, ResourceException> clear(final Context context, final String resourceId) {
/*
* FIXME - Performance here is terrible. We read every relationship just to get the id to delete.
* Need a deleteByQueryFilter() to remove all relationships for a given firstId
*/
return getRelationshipValueForResource(context, resourceId).thenAsync(new AsyncFunction<JsonValue, JsonValue, ResourceException>() {
}
}
return deleted;
}
});
}
});
}
/** {@inheritDoc} */
public Promise<ResourceResponse, ResourceException> createInstance(final Context context, final CreateRequest request) {
}
/** {@inheritDoc} */
public Promise<ResourceResponse, ResourceException> readInstance(Context context, String resourceId, ReadRequest request) {
}
/** {@inheritDoc} */
public Promise<ResourceResponse, ResourceException> updateInstance(Context context, String resourceId, UpdateRequest request) {
}
/** {@inheritDoc} */
public Promise<ResourceResponse, ResourceException> deleteInstance(final Context context, final String resourceId, final DeleteRequest request) {
}
/** {@inheritDoc} */
public Promise<ResourceResponse, ResourceException> patchInstance(Context context, String resourceId, PatchRequest request) {
}
/** {@inheritDoc} */
public Promise<ActionResponse, ResourceException> actionCollection(Context context, ActionRequest request) {
}
/** {@inheritDoc} */
public Promise<ActionResponse, ResourceException> actionInstance(Context context, String resourceId, ActionRequest request) {
}
/** {@inheritDoc} */
public Promise<QueryResponse, ResourceException> queryCollection(final Context context, final QueryRequest request, final QueryResourceHandler handler) {
try {
}
/*
* Create new request copying all attributes but fields.
* This must be done so field filtering can be handled by CREST externally on
* the transformed resource response.
*/
// This should be the only field ever set on queryRequest
return new BadRequestException("Invalid " + HttpUtils.PARAM_QUERY_ID + ": only query-all and query-all-ids supported").asPromise();
}
}
}
QueryFilter.equalTo(new JsonPointer(isReverse ? REPO_FIELD_SECOND_ID : REPO_FIELD_FIRST_ID), firstResourcePath(context, request)),
}
final Promise<QueryResponse, ResourceException> response = getConnection().queryAsync(context, queryRequest,
new QueryResourceHandler() {
if (queryAllIds) {
// Special case, return just the ids, no expansion
}
try {
} catch (Exception e) {
}
}
});
return response;
}
// Get the value of the managed object
// Do activity logging.
activityLogger.log(context, request, "query", getManagedObjectPath(context), null, value.getContent(),
return newResultPromise(result);
} catch (ResourceException e) {
return e.asPromise();
} catch (Exception e) {
}
}
}
/**
* A {@link QueryFilterVisitor} implementation which modifies the {@link JsonPointer} fields by prepending them
* with the appropriate key where the full config object is located.
*/
private static class RelationshipQueryFilterVisitor implements QueryFilterVisitor<QueryFilter<JsonPointer>, Boolean, JsonPointer> {
public QueryFilter<JsonPointer> visitAndFilter(Boolean parameter, List<QueryFilter<JsonPointer>> subFilters) {
}
}
public QueryFilter<JsonPointer> visitContainsFilter(Boolean parameter, JsonPointer field, Object valueAssertion) {
}
public QueryFilter<JsonPointer> visitEqualsFilter(Boolean parameter, JsonPointer field, Object valueAssertion) {
}
public QueryFilter<JsonPointer> visitExtendedMatchFilter(Boolean parameter, JsonPointer field, String operator, Object valueAssertion) {
return QueryFilter.comparisonFilter(getRelationshipPointer(parameter, field), operator, valueAssertion);
}
public QueryFilter<JsonPointer> visitGreaterThanFilter(Boolean parameter, JsonPointer field, Object valueAssertion) {
}
public QueryFilter<JsonPointer> visitGreaterThanOrEqualToFilter(Boolean parameter, JsonPointer field, Object valueAssertion) {
}
public QueryFilter<JsonPointer> visitLessThanFilter(Boolean parameter, JsonPointer field, Object valueAssertion) {
}
public QueryFilter<JsonPointer> visitLessThanOrEqualToFilter(Boolean parameter, JsonPointer field, Object valueAssertion) {
}
public QueryFilter<JsonPointer> visitNotFilter(Boolean parameter, QueryFilter<JsonPointer> subFilter) {
}
public QueryFilter<JsonPointer> visitOrFilter(Boolean parameter, List<QueryFilter<JsonPointer>> subFilters) {
}
}
public QueryFilter<JsonPointer> visitStartsWithFilter(Boolean parameter, JsonPointer field, Object valueAssertion) {
}
/**
* Visits each {@link QueryFilter} in a list of filters and returns a list of the
* visited filters.
*
* @param subFilters a list of the filters to visit
* @return a list of visited filters
*/
private List<QueryFilter<JsonPointer>> visitQueryFilters(List<QueryFilter<JsonPointer>> subFilters) {
}
return visitedFilters;
}
/**
* Converts relationship client object pointers to repo format.
*
* Converts /_refProperties/_id to /_id
* Converts /_refProperties/_rev to /_rev
* Converts /_ref to /secondId
* Converts /_refProperties/... to /properties/...
*
* @param field a {@link JsonPointer} representing the field to modify.
* @return a {@link JsonPointer} representing the modified field
*/
// /_revProperties/_id to /_id
return new JsonPointer(FIELD_CONTENT_ID);
}
// /_refProperties/_rev to /_rev
return new JsonPointer(FIELD_CONTENT_REVISION);
}
if (isReverse) {
// /_ref to /firstId
return new JsonPointer(REPO_FIELD_FIRST_ID);
}
} else {
// /_ref to /secondId
return new JsonPointer(REPO_FIELD_SECOND_ID);
}
}
// /_ref to /secondId
// /_refProperties/... to /properties/...
}
return ptr;
}
// TODO: OPENIDM-4153 don't expose direct repo properties
return field;
}
}
}