@Override
  public <T extends ObjectType> SearchResultList<PrismObject<T>> searchObjects(
      Class<T> type,
      ObjectQuery query,
      Collection<SelectorOptions<GetOperationOptions>> options,
      OperationResult parentResult)
      throws SchemaException {
    if (!isCacheable(type) || !nullOrHarmlessOptions(options)) {
      log("Cache: PASS ({})", type.getSimpleName());
      return repository.searchObjects(type, query, options, parentResult);
    }
    Cache cache = getCache();
    if (cache == null) {
      log("Cache: NULL ({})", type.getSimpleName());
    } else {
      SearchResultList queryResult = cache.getQueryResult(type, query, prismContext);
      if (queryResult != null) {
        log("Cache: HIT {} ({})", query, type.getSimpleName());
        return queryResult.clone();
      }
      log("Cache: MISS {} ({})", query, type.getSimpleName());
    }

    // Cannot satisfy from cache, pass down to repository
    SearchResultList<PrismObject<T>> objects =
        repository.searchObjects(type, query, options, parentResult);
    if (cache != null && options == null) {
      for (PrismObject<T> object : objects) {
        cacheObject(cache, object);
      }
      cache.putQueryResult(type, query, objects, prismContext);
    }
    return objects;
  }
 @Override
 public <T extends ObjectType> PrismObject<T> getObject(
     Class<T> type,
     String oid,
     Collection<SelectorOptions<GetOperationOptions>> options,
     OperationResult parentResult)
     throws ObjectNotFoundException, SchemaException {
   if (!isCacheable(type) || !nullOrHarmlessOptions(options)) {
     log("Cache: PASS {} ({})", oid, type.getSimpleName());
     return repository.getObject(type, oid, options, parentResult);
   }
   Cache cache = getCache();
   if (cache == null) {
     log("Cache: NULL {} ({})", oid, type.getSimpleName());
   } else {
     PrismObject<T> object = (PrismObject) cache.getObject(oid);
     if (object != null) {
       // TODO: result?
       log("Cache: HIT {} ({})", oid, type.getSimpleName());
       return object.clone();
     }
     log("Cache: MISS {} ({})", oid, type.getSimpleName());
   }
   PrismObject<T> object = repository.getObject(type, oid, null, parentResult);
   cacheObject(cache, object);
   return object;
 }
 @Override
 public <T extends ObjectType> int countObjects(
     Class<T> type, ObjectQuery query, OperationResult parentResult) throws SchemaException {
   // TODO use cached query result if applicable
   log("Cache: PASS countObjects ({})", type.getSimpleName());
   return repository.countObjects(type, query, parentResult);
 }
  @Test(enabled = true)
  public void test010SetGetWfApprovedBy() throws Exception {

    Task task = taskManager.createTaskInstance();
    OperationResult result = new OperationResult("test010SetGetWfApprovedBy");

    task.setOwner(
        repositoryService.getObject(
            UserType.class, SystemObjectsType.USER_ADMINISTRATOR.value(), null, result));
    taskManager.switchToBackground(task, result);

    wfTaskUtil.addApprovedBy(task, SystemObjectsType.USER_ADMINISTRATOR.value());
    wfTaskUtil.addApprovedBy(task, SystemObjectsType.USER_ADMINISTRATOR.value());
    wfTaskUtil.addApprovedBy(task, AbstractWfTestLegacy.R1BOSS_OID);
    wfTaskUtil.addApprovedBy(task, AbstractWfTestLegacy.R2BOSS_OID);
    task.savePendingModifications(result);

    Task task2 = taskManager.getTask(task.getOid(), result);
    PrismReference approvers = wfTaskUtil.getApprovedBy(task2);

    assertEquals("Incorrect number of approvers", 3, approvers.getValues().size());
    assertEquals(
        "Incorrect approvers",
        new HashSet(
            Arrays.asList(
                SystemObjectsType.USER_ADMINISTRATOR.value(),
                AbstractWfTestLegacy.R1BOSS_OID,
                AbstractWfTestLegacy.R2BOSS_OID)),
        new HashSet(
            Arrays.asList(
                approvers.getValue(0).getOid(),
                approvers.getValue(1).getOid(),
                approvers.getValue(2).getOid())));
  }
 @Override
 public <T extends ShadowType> List<PrismObject<T>> listResourceObjectShadows(
     String resourceOid, Class<T> resourceObjectShadowType, OperationResult parentResult)
     throws ObjectNotFoundException, SchemaException {
   return repository.listResourceObjectShadows(
       resourceOid, resourceObjectShadowType, parentResult);
 }
 @Override
 public <T extends ObjectType> void deleteObject(
     Class<T> type, String oid, OperationResult parentResult) throws ObjectNotFoundException {
   repository.deleteObject(type, oid, parentResult);
   Cache cache = getCache();
   if (cache != null) {
     cache.removeObject(oid);
     cache.clearQueryResults(type);
   }
 }
  /* (non-Javadoc)
   * @see com.evolveum.midpoint.model.api.ModelDiagnosticService#repositorySelfTest(com.evolveum.midpoint.task.api.Task)
   */
  @Override
  public OperationResult repositorySelfTest(Task task) {
    OperationResult testResult = new OperationResult(REPOSITORY_SELF_TEST);
    // Give repository chance to run its own self-test if available
    repositoryService.repositorySelfTest(testResult);

    repositorySelfTestUser(task, testResult);

    testResult.computeStatus();
    return testResult;
  }
  // Called from the ObjectResolver.resolve
  public ObjectType resolveRef(
      ObjectReferenceType ref, String contextDescription, OperationResult result)
      throws ObjectNotFoundException, SchemaException {

    Class<? extends ObjectType> type = ObjectType.class;
    if (ref.getType() != null) {
      ObjectTypes objectTypeType = ObjectTypes.getObjectTypeFromTypeQName(ref.getType());
      type = objectTypeType.getClassDefinition();
    }

    return repositoryService.getObject(type, ref.getOid(), null, result).asObjectable();
  }
 @Override
 public <F extends FocusType> PrismObject<F> searchShadowOwner(
     String shadowOid,
     Collection<SelectorOptions<GetOperationOptions>> options,
     OperationResult parentResult)
     throws ObjectNotFoundException {
   // TODO cache the search operation?
   PrismObject<F> ownerObject = repository.searchShadowOwner(shadowOid, options, parentResult);
   if (ownerObject != null && nullOrHarmlessOptions(options)) {
     cacheObject(getCache(), ownerObject);
   }
   return ownerObject;
 }
 /* (non-Javadoc)
  * @see com.evolveum.midpoint.repo.api.RepositoryService#getVersion(java.lang.Class, java.lang.String, com.evolveum.midpoint.schema.result.OperationResult)
  */
 @Override
 public <T extends ObjectType> String getVersion(
     Class<T> type, String oid, OperationResult parentResult)
     throws ObjectNotFoundException, SchemaException {
   if (!isCacheable(type)) {
     log("Cache: PASS {} ({})", oid, type.getSimpleName());
     return repository.getVersion(type, oid, parentResult);
   }
   Cache cache = getCache();
   if (cache == null) {
     log("Cache: NULL {} ({})", oid, type.getSimpleName());
   } else {
     String version = cache.getObjectVersion(oid);
     if (version != null) {
       log("Cache: HIT {} ({})", oid, type.getSimpleName());
       return version;
     }
     log("Cache: MISS {} ({})", oid, type.getSimpleName());
   }
   String version = repository.getVersion(type, oid, parentResult);
   cacheObjectVersion(cache, oid, version);
   return version;
 }
 @Override
 public <T extends ObjectType> void modifyObject(
     Class<T> type,
     String oid,
     Collection<? extends ItemDelta> modifications,
     OperationResult parentResult)
     throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException {
   repository.modifyObject(type, oid, modifications, parentResult);
   // this changes the object. We are too lazy to apply changes ourselves, so just invalidate
   // the object in cache
   Cache cache = getCache();
   if (cache != null) {
     cache.removeObject(oid);
     cache.clearQueryResults(type);
   }
 }
 @Override
 public <T extends ObjectType> String addObject(
     PrismObject<T> object, RepoAddOptions options, OperationResult parentResult)
     throws ObjectAlreadyExistsException, SchemaException {
   String oid = repository.addObject(object, options, parentResult);
   Cache cache = getCache();
   // DON't cache the object here. The object may not have proper "JAXB" form, e.g. some pieces may
   // be
   // DOM element instead of JAXB elements. Not to cache it is safer and the performance loss
   // is acceptable.
   if (cache != null) {
     // Invalidate the cache entry if it happens to be there
     cache.removeObject(oid);
     cache.clearQueryResults(object.getCompileTimeClass());
   }
   return oid;
 }
 /* (non-Javadoc)
  * @see com.evolveum.midpoint.repo.api.RepositoryService#searchObjectsIterative(java.lang.Class, com.evolveum.midpoint.prism.query.ObjectQuery, com.evolveum.midpoint.schema.ResultHandler, com.evolveum.midpoint.schema.result.OperationResult)
  */
 @Override
 public <T extends ObjectType> SearchResultMetadata searchObjectsIterative(
     Class<T> type,
     ObjectQuery query,
     final ResultHandler<T> handler,
     Collection<SelectorOptions<GetOperationOptions>> options,
     OperationResult parentResult)
     throws SchemaException {
   // TODO use cached query result if applicable
   log("Cache: PASS searchObjectsIterative ({})", type.getSimpleName());
   final Cache cache = getCache();
   ResultHandler<T> myHandler =
       new ResultHandler<T>() {
         @Override
         public boolean handle(PrismObject<T> object, OperationResult parentResult) {
           cacheObject(cache, object);
           return handler.handle(object, parentResult);
         }
       };
   return repository.searchObjectsIterative(type, query, myHandler, options, parentResult);
 }
 @Override
 public boolean isAnySubordinate(String upperOrgOid, Collection<String> lowerObjectOids)
     throws SchemaException {
   return repository.isAnySubordinate(upperOrgOid, lowerObjectOids);
 }
 @Override
 public void testOrgClosureConsistency(boolean repairIfNecessary, OperationResult testResult) {
   repository.testOrgClosureConsistency(repairIfNecessary, testResult);
 }
 /* (non-Javadoc)
  * @see com.evolveum.midpoint.repo.api.RepositoryService#repositorySelfTest(com.evolveum.midpoint.schema.result.OperationResult)
  */
 @Override
 public void repositorySelfTest(OperationResult parentResult) {
   repository.repositorySelfTest(parentResult);
 }
 /* (non-Javadoc)
  * @see com.evolveum.midpoint.repo.api.RepositoryService#getRepositoryDiag()
  */
 @Override
 public RepositoryDiag getRepositoryDiag() {
   return repository.getRepositoryDiag();
 }
  private void repositorySelfTestUser(Task task, OperationResult testResult) {
    OperationResult result = testResult.createSubresult(REPOSITORY_SELF_TEST_USER);

    PrismObject<UserType> user = getObjectDefinition(UserType.class).instantiate();
    UserType userType = user.asObjectable();

    String name = generateRandomName();
    PolyStringType namePolyStringType = toPolyStringType(name);
    userType.setName(namePolyStringType);
    result.addContext("name", name);
    userType.setDescription(SelfTestData.POLICIJA);
    userType.setFullName(toPolyStringType(USER_FULL_NAME));
    userType.setGivenName(toPolyStringType(USER_GIVEN_NAME));
    userType.setFamilyName(toPolyStringType(USER_FAMILY_NAME));
    userType.setTitle(toPolyStringType(INSANE_NATIONAL_STRING));
    userType.getEmployeeType().add(USER_EMPLOYEE_TYPE[0]);
    userType.getEmployeeType().add(USER_EMPLOYEE_TYPE[1]);
    userType.getOrganization().add(toPolyStringType(USER_ORGANIZATION[0]));
    userType.getOrganization().add(toPolyStringType(USER_ORGANIZATION[1]));

    String oid;
    try {
      oid = repositoryService.addObject(user, null, result);
    } catch (ObjectAlreadyExistsException e) {
      result.recordFatalError(e);
      return;
    } catch (SchemaException e) {
      result.recordFatalError(e);
      return;
    } catch (RuntimeException e) {
      result.recordFatalError(e);
      return;
    }

    try {

      {
        OperationResult subresult = result.createSubresult(result.getOperation() + ".getObject");

        PrismObject<UserType> userRetrieved;
        try {
          userRetrieved = repositoryService.getObject(UserType.class, oid, null, subresult);
        } catch (ObjectNotFoundException e) {
          result.recordFatalError(e);
          return;
        } catch (SchemaException e) {
          result.recordFatalError(e);
          return;
        } catch (RuntimeException e) {
          result.recordFatalError(e);
          return;
        }

        if (LOGGER.isTraceEnabled()) {
          LOGGER.trace("Self-test:user getObject:\n{}", userRetrieved.debugDump());
        }

        checkUser(userRetrieved, name, subresult);

        subresult.recordSuccessIfUnknown();
      }

      {
        OperationResult subresult =
            result.createSubresult(result.getOperation() + ".searchObjects.fullName");
        try {

          ObjectQuery query = new ObjectQuery();
          ObjectFilter filter =
              EqualFilter.createEqual(
                  UserType.F_FULL_NAME,
                  UserType.class,
                  prismContext,
                  null,
                  toPolyString(USER_FULL_NAME));
          query.setFilter(filter);
          subresult.addParam("query", query);
          List<PrismObject<UserType>> foundObjects =
              repositoryService.searchObjects(UserType.class, query, null, subresult);
          if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Self-test:user searchObjects:\n{}", DebugUtil.debugDump(foundObjects));
          }
          assertSingleSearchResult("user", foundObjects, subresult);

          PrismObject<UserType> userRetrieved = foundObjects.iterator().next();
          checkUser(userRetrieved, name, subresult);

          subresult.recordSuccessIfUnknown();
        } catch (SchemaException e) {
          subresult.recordFatalError(e);
          return;
        } catch (RuntimeException e) {
          subresult.recordFatalError(e);
          return;
        }
      }

      // MID-1116
      {
        OperationResult subresult =
            result.createSubresult(result.getOperation() + ".searchObjects.employeeType");
        try {

          ObjectQuery query = new ObjectQuery();
          ObjectFilter filter =
              EqualFilter.createEqual(
                  UserType.F_EMPLOYEE_TYPE,
                  UserType.class,
                  prismContext,
                  null,
                  USER_EMPLOYEE_TYPE[0]);
          query.setFilter(filter);
          subresult.addParam("query", query);
          List<PrismObject<UserType>> foundObjects =
              repositoryService.searchObjects(UserType.class, query, null, subresult);
          if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Self-test:user searchObjects:\n{}", DebugUtil.debugDump(foundObjects));
          }
          assertSingleSearchResult("user", foundObjects, subresult);

          PrismObject<UserType> userRetrieved = foundObjects.iterator().next();
          checkUser(userRetrieved, name, subresult);

          subresult.recordSuccessIfUnknown();
        } catch (SchemaException e) {
          subresult.recordFatalError(e);
          return;
        } catch (RuntimeException e) {
          subresult.recordFatalError(e);
          return;
        }
      }

      // MID-1116
      {
        OperationResult subresult =
            result.createSubresult(result.getOperation() + ".searchObjects.organization");
        try {

          ObjectQuery query = new ObjectQuery();
          ObjectFilter filter =
              EqualFilter.createEqual(
                  UserType.F_ORGANIZATION,
                  UserType.class,
                  prismContext,
                  null,
                  toPolyString(USER_ORGANIZATION[1]));
          query.setFilter(filter);
          subresult.addParam("query", query);
          List<PrismObject<UserType>> foundObjects =
              repositoryService.searchObjects(UserType.class, query, null, subresult);
          if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Self-test:user searchObjects:\n{}", DebugUtil.debugDump(foundObjects));
          }
          assertSingleSearchResult("user", foundObjects, subresult);

          PrismObject<UserType> userRetrieved = foundObjects.iterator().next();
          checkUser(userRetrieved, name, subresult);

          subresult.recordSuccessIfUnknown();
        } catch (SchemaException e) {
          subresult.recordFatalError(e);
          return;
        } catch (RuntimeException e) {
          subresult.recordFatalError(e);
          return;
        }
      }

    } finally {

      try {
        repositoryService.deleteObject(UserType.class, oid, testResult);
      } catch (ObjectNotFoundException e) {
        result.recordFatalError(e);
        return;
      } catch (RuntimeException e) {
        result.recordFatalError(e);
        return;
      }

      result.computeStatus();
    }
  }
 /* (non-Javadoc)
  * @see com.evolveum.midpoint.model.api.ModelDiagnosticService#getRepositoryDiag(com.evolveum.midpoint.task.api.Task, com.evolveum.midpoint.schema.result.OperationResult)
  */
 @Override
 public RepositoryDiag getRepositoryDiag(Task task, OperationResult parentResult) {
   return repositoryService.getRepositoryDiag();
 }
 @Override
 @Deprecated
 public PrismObject<UserType> listAccountShadowOwner(
     String accountOid, OperationResult parentResult) throws ObjectNotFoundException {
   return repository.listAccountShadowOwner(accountOid, parentResult);
 }