private SyndicateFSFileStatus getFileStatus(SyndicateFSPath abspath) throws IOException {
    if (abspath == null) {
      LOG.error("Can not get FileStatus from null abspath");
      throw new IllegalArgumentException("Can not get FileStatus from null abspath");
    }

    // check memory cache
    SyndicateFSFileStatus cached_status = this.filestatusCache.get(abspath);

    if (cached_status != null && !cached_status.isDirty()) {
      return cached_status;
    }

    // not in memory cache
    StatRaw statRaw = null;
    try {
      Future<ClientResponse> statFuture = this.client.getStat(abspath.getPath());
      if (statFuture != null) {
        statRaw = this.client.processGetStat(statFuture);
      } else {
        throw new IOException("Can not create a REST client");
      }
    } catch (FileNotFoundException ex) {
      // silent
      return null;
    } catch (Exception ex) {
      LOG.error("exception occurred", ex);
      throw new IOException(ex);
    }

    SyndicateFSFileStatus status = new SyndicateFSFileStatus(this, abspath, statRaw);
    this.filestatusCache.put(abspath, status);

    return status;
  }
  private SyndicateFSFileHandle getFileHandle(SyndicateFSFileStatus status, boolean readonly)
      throws IOException {
    if (status == null) {
      LOG.error("Can not get FileHandle from null status");
      throw new IllegalArgumentException("Can not get FileHandle from null status");
    }
    if (status.isDirty()) {
      LOG.error("Can not get FileHandle from dirty status");
      throw new IllegalArgumentException("Can not get FileHandle from dirty status");
    }

    LOG.info("opening a file - " + status.getPath().getPath());

    FileDescriptor fi = null;
    Future<ClientResponse> openFuture = null;
    if (readonly) {
      openFuture = this.client.open(status.getPath().getPath(), "r");
    } else {
      openFuture = this.client.open(status.getPath().getPath(), "w");
    }

    if (openFuture != null) {
      try {
        fi = this.client.processOpen(openFuture);
        return new SyndicateFSFileHandle(this, status, fi, readonly);
      } catch (Exception ex) {
        LOG.error("exception occurred", ex);
        throw new IOException(ex);
      }
    } else {
      throw new IOException("Can not create a REST client");
    }
  }
  @Override
  public synchronized boolean delete(SyndicateFSPath path)
      throws FileNotFoundException, IOException {
    if (path == null) {
      LOG.error("path is null");
      throw new IllegalArgumentException("path is null");
    }

    SyndicateFSPath absPath = getAbsolutePath(path);
    SyndicateFSFileStatus status = getFileStatus(absPath);
    if (status == null) {
      LOG.error("file not exist");
      throw new FileNotFoundException("file not exist : " + path.getPath());
    }

    if (status.isFile()) {
      Future<ClientResponse> unlinkFuture = this.client.unlink(absPath.getPath());
      if (unlinkFuture != null) {
        try {
          this.client.processUnlink(unlinkFuture);
        } catch (RestfulException ex) {
          LOG.error("exception occurred", ex);
          throw new IOException(ex);
        }
      } else {
        throw new IOException("Can not create a REST client");
      }
    } else if (status.isDirectory()) {
      Future<ClientResponse> removeDirFuture = this.client.removeDir(absPath.getPath());
      if (removeDirFuture != null) {
        try {
          this.client.processRemoveDir(removeDirFuture);
        } catch (RestfulException ex) {
          LOG.error("exception occurred", ex);
          throw new IOException(ex);
        }
      } else {
        throw new IOException("Can not create a REST client");
      }
    } else {
      LOG.error("Can not delete from unknown status");
      throw new IOException("Can not delete from unknown status");
    }

    this.filestatusCache.remove(absPath);
    return true;
  }
  @Override
  public synchronized long getLastAccessTime(SyndicateFSPath path) {
    if (path == null) {
      LOG.error("path is null");
      throw new IllegalArgumentException("path is null");
    }

    SyndicateFSPath absPath = getAbsolutePath(path);
    SyndicateFSFileStatus status = null;
    try {
      status = getFileStatus(absPath);
    } catch (IOException ex) {
      LOG.error("exception occurred", ex);
    }

    if (status != null) {
      return status.getLastAccess();
    }
    return 0;
  }
  @Override
  public synchronized boolean isDirectory(SyndicateFSPath path) {
    if (path == null) {
      LOG.error("path is null");
      throw new IllegalArgumentException("path is null");
    }

    SyndicateFSPath absPath = getAbsolutePath(path);
    SyndicateFSFileStatus status = null;
    try {
      status = getFileStatus(absPath);
    } catch (IOException ex) {
      LOG.error("exception occurred", ex);
    }

    if (status != null) {
      return status.isDirectory();
    }
    return false;
  }
  @Override
  public SyndicateFSOutputStream getFileOutputStream(SyndicateFSPath path) throws IOException {
    if (path == null) {
      LOG.error("path is null");
      throw new IllegalArgumentException("path is null");
    }

    SyndicateFSPath absPath = getAbsolutePath(path);
    SyndicateFSFileStatus status = getFileStatus(absPath);

    if (status != null) {
      if (!status.isFile()) {
        LOG.error("Can not open the file to write (is directory) : " + absPath.getPath());
        throw new IOException(
            "Can not open the file to write (is directory) : " + absPath.getPath());
      }

      SyndicateFSFileHandle handle = getFileHandle(status, false);
      if (handle == null) {
        LOG.error("Can not open the file to write : " + absPath.getPath());
        throw new IOException("Can not open the file to write : " + absPath.getPath());
      }

      SyndicateFSOutputStream os = new SyndicateFSOutputStream(handle);
      this.openOutputStream.add(os);
      return os;
    } else {
      // create new file
      SyndicateFSFileHandle handle = createNewFile(absPath);
      if (handle == null) {
        LOG.error("Can not create a file to write : " + absPath.getPath());
        throw new IOException("Can not create a file to write : " + absPath.getPath());
      }

      SyndicateFSOutputStream os = new SyndicateFSOutputStream(handle);
      this.openOutputStream.add(os);
      return os;
    }
  }
  @Override
  public synchronized FsPermission getPermission(SyndicateFSPath path) {
    if (path == null) {
      LOG.error("path is null");
      throw new IllegalArgumentException("path is null");
    }

    SyndicateFSPath absPath = getAbsolutePath(path);
    SyndicateFSFileStatus status = null;
    try {
      status = getFileStatus(absPath);
    } catch (IOException ex) {
      LOG.error("exception occurred", ex);
    }

    if (status != null) {
      int userMode = status.getUserMode();
      int groupMode = status.getGroupMode();
      int othersMode = status.getOthersMode();

      return new FsPermission(parseMode(userMode), parseMode(groupMode), parseMode(othersMode));
    }
    return new FsPermission(FsAction.NONE, FsAction.NONE, FsAction.NONE);
  }
  private synchronized SyndicateFSFileHandle createNewFile(SyndicateFSPath abspath)
      throws IOException {
    if (abspath == null) {
      LOG.error("abspath is null");
      throw new IllegalArgumentException("abspath is null");
    }

    if (abspath.getParent() != null) {
      SyndicateFSFileStatus parent = getFileStatus(abspath.getParent());
      if (parent == null) {
        LOG.error("Parent directory does not exist");
        throw new IOException("Parent directory does not exist");
      }

      if (!parent.isDirectory()) {
        LOG.error("Parent directory does not exist");
        throw new IOException("Parent directory does not exist");
      }
    }

    LOG.info("creating a file - " + abspath.getPath());

    Future<ClientResponse> openFuture = this.client.open(abspath.getPath(), "w");
    if (openFuture != null) {
      try {
        FileDescriptor fi = this.client.processOpen(openFuture);
        SyndicateFSFileStatus status = new SyndicateFSFileStatus(this, abspath);
        return new SyndicateFSFileHandle(this, status, fi, false);
      } catch (Exception ex) {
        LOG.error("exception occurred", ex);
        throw new IOException(ex);
      }
    } else {
      throw new IOException("Can not create a REST client");
    }
  }