class UmaPolicyServiceImpl implements UmaPolicyService {

    @Override
    public Promise<UmaPolicy, ResourceException> updatePolicy(final Context context, final String resourceSetId, //TODO need to check if need to delete backend policies
            JsonValue policy) {
        final UmaPolicy updatedUmaPolicy;
        final ResourceSetDescription resourceSet;
        try {
            resourceSet = getResourceSet(getRealm(context), resourceSetId);
            updatedUmaPolicy = UmaPolicy.valueOf(resourceSet, resolveUsernameToUID(context, policy));
            boolean canShare = canUserShareResourceSet(resourceSet.getResourceOwnerId(),
                    contextHelper.getUserId(context), resourceSet.getClientId(), getRealm(context), resourceSet.getId(),
                    updatedUmaPolicy.getScopes());
            if (!canShare) {
                return new ForbiddenException().asPromise();
            }
            validateScopes(resourceSet, updatedUmaPolicy.getScopes());
        } catch (ResourceException e) {
            return e.asPromise();
        }
        return internalReadPolicy(context, resourceSetId)
                .thenAsync(beforeResourceSharedModified(updatedUmaPolicy))
                .thenOnResult(new ResultHandler<UmaPolicy>() {
                    @Override
                    public void handleResult(UmaPolicy currentUmaPolicy) {
                        Set<String> modifiedScopes = new HashSet<>(updatedUmaPolicy.getScopes());
                        modifiedScopes.retainAll(currentUmaPolicy.getScopes());
                        Set<String> removedScopes = new HashSet<>(currentUmaPolicy.getScopes());
                        removedScopes.removeAll(modifiedScopes);
                        for (JsonValue policy : currentUmaPolicy.asUnderlyingPolicies(contextHelper.getUserId(context))) {
                            for (String scope : removedScopes) {
                                if (policy.get("actionValues").isDefined(scope)) {
                                    policyResourceDelegate.queryPolicies(context, Requests.newQueryRequest("")
                                            .setQueryFilter(QueryFilter.and(
                                                    QueryFilter.equalTo(new JsonPointer("createdBy"), contextHelper.getUserUid(context)),
                                                    QueryFilter.equalTo(new JsonPointer("name"), policy.get("name").asString()))))
                                            .thenAsync(new DeleteOldPolicyFunction(context));
                                }
                            }
                        }
                    }
                }).thenOnResult(new ResultHandler<UmaPolicy>() {
                    @Override
                    public void handleResult(UmaPolicy currentUmaPolicy) {
                        Set<String> modifiedScopes = new HashSet<>(currentUmaPolicy.getScopes());
                        modifiedScopes.retainAll(updatedUmaPolicy.getScopes());
                        Set<String> deletedScopes = new HashSet<>(updatedUmaPolicy.getScopes());
                        deletedScopes.removeAll(modifiedScopes);
                        for (JsonValue policy : updatedUmaPolicy.asUnderlyingPolicies(contextHelper.getUserId(context))) {
                            for (String scope : deletedScopes) {
                                if (policy.get("actionValues").isDefined(scope)) {
                                    policyResourceDelegate.createPolicies(context, singleton(policy));
                                }
                            }
                        }
                    }
                }).thenOnResult(new ResultHandler<UmaPolicy>() {
                    @Override
                    public void handleResult(UmaPolicy currentUmaPolicy) {
                        String uid = contextHelper.getUserId(context);
                        Set<String> underlyingPolicyIds = new HashSet<>(currentUmaPolicy.getUnderlyingPolicyIds());
                        Set<JsonValue> newUnderlyingPolicies = updatedUmaPolicy.asUnderlyingPolicies(uid);
                        for (JsonValue value : newUnderlyingPolicies) {
                            underlyingPolicyIds.remove(value.get("name").asString());
                        }
                        policyResourceDelegate.deletePolicies(context, underlyingPolicyIds);
                    }
                })
                .thenAsync(new UpdatePolicyGraphStatesFunction<UmaPolicy>(resourceSet, context))
                .thenAsync(new UpdateUmaPolicyFunction(context, updatedUmaPolicy, resourceSetId, resourceSet));
    }

    @Inject public  UmaPolicyServiceImpl(PolicyResourceDelegate policyResourceDelegate,
            ResourceSetStoreFactory resourceSetStoreFactory, Config<UmaAuditLogger> auditLogger,
            ContextHelper contextHelper, UmaPolicyEvaluatorFactory policyEvaluatorFactory,
            CoreServicesWrapper coreServicesWrapper, @Named("frRest") Debug debug,
            UmaSettingsFactory umaSettingsFactory, ExtensionFilterManager extensionFilterManager);

}