<F extends ObjectType> void processPasswordPolicy(
      LensProjectionContext projectionContext,
      LensContext<F> context,
      Task task,
      OperationResult result)
      throws SchemaException, PolicyViolationException {

    ObjectDelta accountDelta = projectionContext.getDelta();

    if (accountDelta == null) {
      LOGGER.trace("Skipping processing password policies. Shadow delta not specified.");
      return;
    }

    if (ChangeType.DELETE == accountDelta.getChangeType()) {
      return;
    }

    PrismObject<ShadowType> accountShadow = null;
    PrismProperty<PasswordType> password = null;
    if (ChangeType.ADD == accountDelta.getChangeType()) {
      accountShadow = accountDelta.getObjectToAdd();
      if (accountShadow != null) {
        password = accountShadow.findProperty(SchemaConstants.PATH_PASSWORD_VALUE);
      }
    }
    if (ChangeType.MODIFY == accountDelta.getChangeType() || password == null) {
      PropertyDelta<PasswordType> passwordValueDelta = null;
      if (accountDelta != null) {
        passwordValueDelta = accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
        // Modification sanity check
        if (accountDelta.getChangeType() == ChangeType.MODIFY
            && passwordValueDelta != null
            && (passwordValueDelta.isAdd() || passwordValueDelta.isDelete())) {
          throw new SchemaException(
              "Shadow password value cannot be added or deleted, it can only be replaced");
        }
        if (passwordValueDelta == null) {
          LOGGER.trace(
              "Skipping processing password policies. Shadow delta does not contain password change.");
          return;
        }
        password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null);
      }
    }

    //		PrismProperty<PasswordType> password = getPassword(projectionContext);
    ValuePolicyType passwordPolicy = null;
    if (isCheckOrgPolicy(context)) {
      passwordPolicy = determineValuePolicy(context.getFocusContext().getObjectAny(), task, result);
      context.getFocusContext().setOrgPasswordPolicy(passwordPolicy);
    } else {
      passwordPolicy = projectionContext.getEffectivePasswordPolicy();
    }

    processPasswordPolicy(passwordPolicy, password, result);
  }
  <F extends FocusType> void processPasswordPolicy(
      LensFocusContext<F> focusContext, LensContext<F> context, Task task, OperationResult result)
      throws PolicyViolationException, SchemaException {

    if (!UserType.class.isAssignableFrom(focusContext.getObjectTypeClass())) {
      LOGGER.trace("Skipping processing password policies because focus is not user");
      return;
    }

    //		PrismProperty<PasswordType> password = getPassword(focusContext);
    ObjectDelta userDelta = focusContext.getDelta();

    if (userDelta == null) {
      LOGGER.trace("Skipping processing password policies. User delta not specified.");
      return;
    }

    if (userDelta.isDelete()) {
      LOGGER.trace("Skipping processing password policies. User will be deleted.");
      return;
    }

    PrismProperty<PasswordType> password = null;
    PrismObject<F> user;
    if (ChangeType.ADD == userDelta.getChangeType()) {
      user = focusContext.getDelta().getObjectToAdd();
      if (user != null) {
        password = user.findProperty(SchemaConstants.PATH_PASSWORD_VALUE);
      }
      if (password == null) {
        if (wasExecuted(userDelta, focusContext)) {
          LOGGER.trace(
              "Skipping processing password policies. User addition was already executed.");
          return;
        }
      }
    } else if (ChangeType.MODIFY == userDelta.getChangeType()) {
      PropertyDelta<PasswordType> passwordValueDelta;
      if (userDelta != null) {
        passwordValueDelta = userDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
        if (passwordValueDelta == null) {
          LOGGER.trace(
              "Skipping processing password policies. User delta does not contain password change.");
          return;
        }
        if (userDelta.getChangeType() == ChangeType.MODIFY && passwordValueDelta != null) {
          if (passwordValueDelta.isAdd()) {
            password =
                (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null);
          } else if (passwordValueDelta.isDelete()) {
            password = null;
          } else {
            password =
                (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null);
          }
        } else {
          password = (PrismProperty<PasswordType>) passwordValueDelta.getItemNewMatchingPath(null);
        }
      }
    }

    ValuePolicyType passwordPolicy;
    if (focusContext.getOrgPasswordPolicy() == null) {
      passwordPolicy =
          determineValuePolicy(userDelta, focusContext.getObjectAny(), context, task, result);
      focusContext.setOrgPasswordPolicy(passwordPolicy);
    } else {
      passwordPolicy = focusContext.getOrgPasswordPolicy();
    }

    processPasswordPolicy(passwordPolicy, password, result);
  }