class GoogleStorageReadFeature implements Read {

    @Override
    public InputStream read(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
        try {
            if(0L == status.getLength()) {
                return new NullInputStream(0L);
            }
            final StringBuilder uri = new StringBuilder(String.format("%sstorage/v1/b/%s/o/%s?alt=media",
                session.getClient().getRootUrl(), containerService.getContainer(file).getName(),
                GoogleStorageUriEncoder.encode(containerService.getKey(file))));
            if(StringUtils.isNotBlank(file.attributes().getVersionId())) {
                uri.append(String.format("?generation=%s", file.attributes().getVersionId()));
            }
            final HttpUriRequest request = new HttpGet(uri.toString());
            request.addHeader(HTTP.CONTENT_TYPE, MEDIA_TYPE);
            if(status.isAppend()) {
                final HttpRange range = HttpRange.withStatus(status);
                final String header;
                if(-1 == range.getEnd()) {
                    header = String.format("bytes=%d-", range.getStart());
                }
                else {
                    header = String.format("bytes=%d-%d", range.getStart(), range.getEnd());
                }
                if(log.isDebugEnabled()) {
                    log.debug(String.format("Add range header %s for file %s", header, file));
                }
                request.addHeader(new BasicHeader(HttpHeaders.RANGE, header));
                // Disable compression
                request.addHeader(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "identity"));
            }
            final HttpClient client = session.getHttpClient();
            final HttpResponse response = client.execute(request);
            switch(response.getStatusLine().getStatusCode()) {
                case HttpStatus.SC_OK:
                case HttpStatus.SC_PARTIAL_CONTENT:
                    return new HttpMethodReleaseInputStream(response);
                default:
                    throw new DefaultHttpResponseExceptionMappingService().map(
                        new HttpResponseException(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase()));
            }
        }
        catch(IOException e) {
            throw new GoogleStorageExceptionMappingService().map("Download {0} failed", e, file);
        }
    }

    public  GoogleStorageReadFeature(final GoogleStorageSession session);

}