code: public <T> T executeWithTxUser(final OSecurityUser user, final SpecificUserAction<T> userAction) {
          final boolean userChanged = checkSpecificUserConditions(user.getName());
          final ODatabaseDocumentInternal db = (ODatabaseDocumentInternal) connectionProvider.get();
          final OSecurityUser original = db.getUser();
          if (userChanged) {
              // no need to track user change if user not changed
              specificTxUser.set(user);
              db.setUser(user);
          }
          T result = null;
          try {
              result = userAction.execute();
          } catch (Throwable th) {
              Throwables.throwIfUnchecked(th);
              throw new UserActionException(String.format("Failed to perform tx action with user '%s'",
                      user.getName()), th);
          } finally {
              if (userChanged) {
                  db.setUser(original);
                  specificTxUser.remove();
              }
          }
          return result;
      }
docs: Changes current connection user. Affects only current transaction and can't be used outside of transaction
  ({@link ODatabaseDocumentInternal#setUser(com.orientechnologies.orient.core.metadata.security.OSecurityUser)}).
  <p>
  Recursive user changes are not allowed, so attempt to change user under already changed user will
  lead to error. The only exception is change to the same user (in this case change is ignored).
  <p>
  Action approach is important to explicitly define scope of specific user and
  properly cleanup state (which may be not done in case of direct override).
  <p>
  Propagates runtime exceptions (orient exceptions).
  
  @param user       specific user
  @param userAction logic to execute with specific user
  @param <T>        type of returned result (may be Void)
  @return action result (may be null)