/**
   * Method called locally to the repository during {@link #rawAccess()}. Only the remoteable fields
   * should be accessed during this method call since this will be a copy of the object originally
   * called.
   *
   * @param abstractRepositoryI
   * @param servant
   * @param __current
   */
  public void local(
      AbstractRepositoryI abstractRepositoryI, PublicRepositoryI servant, Current __current)
      throws Exception {

    if ("touch".equals(command)) {
      for (String arg : args) {
        final CheckedPath checked = servant.checkPath(parse(arg), null, __current);
        if (!checked.exists()) {
          final CheckedPath parent = checked.parent();
          if (!(parent.isDirectory() || checked.parent().mkdirs())) {
            throw new RepositoryException(null, null, "cannot create directory: " + parent);
          }
          final FileBuffer buffer = checked.getFileBuffer("rw");
          buffer.write(ByteBuffer.allocate(0));
          buffer.close();
        } else if (!checked.markModified()) {
          throw new RepositoryException(null, null, "cannot touch file: " + checked);
        }
      }
    } else if ("mkdir".equals(command)) {
      boolean parents = false;
      for (String arg : args) {
        if ("-p".equals(arg)) {
          parents = true;
          continue;
        }
        final CheckedPath checked = servant.checkPath(parse(arg), null, __current);
        if (parents) {
          checked.mkdirs();
        } else {
          checked.mkdir();
        }
      }
    } else if ("rm".equals(command)) {
      if (args.size() == 1) {
        final CheckedPath checked = servant.checkPath(parse(args.get(0)), null, __current);
        if (!checked.delete()) {
          throw new omero.grid.FileDeleteException(
              null, null, "Delete file failed: " + args.get(0));
        }
      } else {
        throw new omero.ApiUsageException(
            null, null, "Command: " + command + " takes just one argument");
      }
    } else if ("checksum".equals(command)) {
      if (args.size() == 3) {
        final String checksumType = args.get(0);
        final ChecksumAlgorithm algo = ChecksumAlgorithmMapper.getChecksumAlgorithm(checksumType);
        final String expectedHash = args.get(1);
        final CheckedPath checked = servant.checkPath(parse(args.get(2)), algo, __current);
        final String currentHash = checked.hash();
        if (!currentHash.equals(expectedHash)) {
          // TODO: ADD ANNOTATION TO DATABASE HERE!
          throw new omero.ResourceError(
              null,
              null,
              String.format(
                  "Checksum mismatch (%s): expected=%s found=%s",
                  checksumType, expectedHash, currentHash));
        }
      } else {
        throw new omero.ApiUsageException(
            null, null, "'checksum' requires HASHER HASH FILEPATH, not: " + args.toString());
      }
    } else {
      throw new omero.ApiUsageException(null, null, "Unknown command: " + command);
    }
  }
  /**
   * Internal method to be used by subclasses to perform any extra checks on the listed of {@link
   * CheckedPath} instances before allowing the creation of directories.
   *
   * @param paths Not null, not empty. (Will be emptied by this method.)
   * @param parents "mkdir -p" like flag.
   * @param __current
   */
  protected void makeCheckedDirs(
      final LinkedList<CheckedPath> paths,
      boolean parents,
      Session s,
      ServiceFactory sf,
      SqlAction sql,
      ome.system.EventContext effectiveEventContext)
      throws ServerError {

    CheckedPath checked;

    // Since we now have some number of elements, we start at the most
    // parent element and work our way down through all the parents.
    // If the file exists, then we check its permissions. If it doesn't
    // exist, it gets created.
    while (paths.size() > 1) { // Only possible if `parents`
      checked = paths.removeFirst();

      if (checked.exists()) {
        if (!checked.isDirectory()) {
          throw new omero.ResourceError(null, null, "Path is not a directory.");
        } else if (!checked.canRead()) {
          throw new omero.ResourceError(null, null, "Directory is not readable");
        }
        assertFindDir(checked, s, sf, sql);

      } else {
        // This will fail if the directory already exists
        try {
          repositoryDao.register(repoUuid, checked, DIRECTORY_MIMETYPE, sf, sql);
        } catch (ValidationException ve) {
          if (ve.getCause() instanceof PSQLException) {
            // Could have collided with another thread also creating the directory.
            // See Trac #11096 regarding originalfile table uniqueness of columns repo, path, name.
            // So, give the other thread time to complete registration.
            SleepTimer.sleepFor(1000);
            if (checked.exists()) {
              // The path now exists! It did not a moment ago.
              // We are not going to rethrow the validation exception,
              // so we otherwise note that something unexpected did occur.
              log.warn(
                  "retrying after exception in registering directory "
                      + checked
                      + ": "
                      + ve.getCause());
              // Another thread may have succeeded where this one failed,
              // so try this directory again.
              paths.add(0, checked);
              continue;
            }
          }
          // We cannot recover from the validation exception.
          throw ve;
        }
      }
    }

    // Now we are ready to work on the actual intended path.
    checked = paths.removeFirst(); // Size is now empty
    if (checked.exists()) {
      if (parents) {
        assertFindDir(checked, s, sf, sql);
      } else {
        throw new omero.ResourceError(null, null, "Path exists on disk: " + checked.fsFile);
      }
    }
    repositoryDao.register(repoUuid, checked, DIRECTORY_MIMETYPE, sf, sql);
  }