@Override
 public void respondPartialContent(
     GetableResource resource,
     Response response,
     Request request,
     Map<String, String> params,
     Range range)
     throws NotAuthorizedException, BadRequestException, NotFoundException {
   log.debug("respondPartialContent: " + range.getStart() + " - " + range.getFinish());
   response.setStatus(Response.Status.SC_PARTIAL_CONTENT);
   long st = range.getStart() == null ? 0 : range.getStart();
   long fn;
   Long cl = resource.getContentLength();
   if (range.getFinish() == null) {
     if (cl != null) {
       fn = cl.longValue() - 1; // position is one less then length
     } else {
       log.warn(
           "Couldnt calculate range end position because the resource is not reporting a content length, and no end position was requested by the client: "
               + resource.getName()
               + " - "
               + resource.getClass());
       fn = -1;
     }
   } else {
     fn = range.getFinish();
   }
   response.setContentRangeHeader(st, fn, cl);
   long contentLength = fn - st + 1;
   response.setContentLengthHeader(contentLength);
   response.setDateHeader(new Date());
   String etag = eTagGenerator.generateEtag(resource);
   if (etag != null) {
     response.setEtag(etag);
   }
   String acc = request.getAcceptHeader();
   String ct = resource.getContentType(acc);
   if (ct != null) {
     response.setContentTypeHeader(ct);
   }
   response.setEntity(new GetableResourceEntity(resource, range, params, ct));
 }
  public void execute(
      AnnoResource resource,
      OutputStream out,
      Range range,
      Map<String, String> params,
      String contentType)
      throws IOException, NotAuthorizedException, BadRequestException, NotFoundException {
    Object source = resource.getSource();
    ControllerMethod cm = getBestMethod(source.getClass(), contentType, params, null);
    if (cm == null) {
      throw new RuntimeException("Method not found: " + getClass() + " - " + source.getClass());
    }
    log.trace("execute GET method: " + cm.method.getName());
    try {
      // Object[] args = annoResourceFactory.buildInvokeArgs(resource, cm.method, range, params,
      // contentType, out);
      // Object result = cm.method.invoke(cm.controller, args);
      Object result = invoke(cm, resource, range, params, contentType, out);
      if (result != null) {
        log.trace("method returned a value, so write it to output");
        if (result instanceof String) {
          ModelAndView modelAndView = new ModelAndView("resource", source, result.toString());
          processTemplate(modelAndView, resource, out);
        } else if (result instanceof JsonResult) {
          JsonResult jsonr = (JsonResult) result;
          JsonWriter jsonWriter = new JsonWriter();
          jsonWriter.write(jsonr, out);

        } else if (result instanceof InputStream) {
          InputStream contentIn = (InputStream) result;
          if (range != null) {
            StreamUtils.readTo(contentIn, out, true, false, range.getStart(), range.getFinish());
          } else {
            try {
              IOUtils.copy(contentIn, out);
            } finally {
              IOUtils.closeQuietly(contentIn);
            }
          }
        } else if (result instanceof byte[]) {
          byte[] bytes = (byte[]) result;
          out.write(bytes);
        } else if (result instanceof ModelAndView) {
          processTemplate((ModelAndView) result, resource, out);
        } else {
          throw new RuntimeException(
              "Unsupported return type from method: "
                  + cm.method.getName()
                  + " in "
                  + cm.controller.getClass()
                  + " should return String or byte[]");
        }
      }
      out.flush();
    } catch (IOException e) {
      throw e;
    } catch (NotAuthorizedException e) {
      throw e;
    } catch (BadRequestException e) {
      throw e;
    } catch (NotFoundException e) {
      throw e;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }