com.google.cloud.storage.StorageException 404 in blob.getContent() - java

I'm running a service that either creates or updates objects in a GCP bucket. I.e my code checks if the object exists, and if it does my code reads it, updates it and writes it back.
Occasionally I'm getting an exception when trying to read the object.
My code:
Storage storage = googleStorage.get();
BlobId blobId = BlobId.of(STORAGE_BUCKET, "path/to.obj"));
Blob blob = storage.get(blobId);
if (blob == null) return null;
byte[] blobContent = blob.getContent();
...
The stacktrace:
...
at com.google.cloud.storage.Blob.getContent(Blob.java:455)
at com.google.cloud.storage.StorageImpl.readAllBytes(StorageImpl.java:461)
at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:51)
at com.google.cloud.RetryHelper.run(RetryHelper.java:74)
at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:89)
at com.google.cloud.storage.StorageImpl$16.call(StorageImpl.java:461)
at com.google.cloud.storage.StorageImpl$16.call(StorageImpl.java:464)
at com.google.cloud.storage.spi.v1.HttpStorageRpc.load(HttpStorageRpc.java:588)
at com.google.cloud.storage.spi.v1.HttpStorageRpc.translate(HttpStorageRpc.java:220)
No such object: bucket/path/to.obj
com.google.cloud.storage.StorageException: 404 Not Found
I would expect to get null in blob if the object does not exist, or to be able to read if blob isn't null.
This behavior results in the object being updated several times (not sure if this is because my code retries the call or because of something the storage library is doing).
I'm using google-cloud-storage 1.27.0, it happens about once per ~10K objects.

I’ve tested the code you provided and it appears to work in the desired way - the Blob object is assigned null if the Cloud Storage Object can’t be located or if the path is not correct.
The incidence of failure is quite insubstantial. Perhaps if you configure exponential backoff using the RetryParams class, then you can eliminate or reduce the impact of these failures.

You don't need the BlobId. You can use this method:
Blob blob = storage.get(bucketName).get(pathToObject);
This method will return null if the blob does not exist at the specified path.

Related

Retrieving only metadata information from object stored in s3 without reading the object payload

I am storing object which consists of stream and metadata in s3 using aws java sdk v2.
Metadata is a map of values extracted from object received from UI.
My code looks this
response=s3Client.putObject(PutObjectRequest.builder().bucket(bucket).key(key).metadata(metadata(media)).build(),
RequestBody.fromBytes(readAsBytesFromStream(media)));
I want to retrieve only the meta information from the object saved and not read the object's payload.
The use case is i have to read only the meta info to render on UI preventing s3 to read object's content.
Is there any way where i can read only the meta info and not the content of saved object.As reading multiple object's content(payload+metadata) and then rendering would make it slow.
Some other way to store meta and payload separately so that reading meta becomes efficient .
You should be able to use the headObject method.
Something like:
response = s3Client.headObject(PutObjectRequest.builder().bucket(bucket).key(key).build();
metadata = response.metadata();
SDK documentation:
https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#headObject-java.util.function.Consumer-
https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/HeadObjectResponse.html

How to generate a single Account SAS for both container.listBlobs() and blob.exists()

I'm developing a Java application which executes the following methods with Account SAS (Shared Access Signature) URI:
CLoudBlockBlob blob = container.getBlockBlobReference("tmp/test.json");
blob.exists();
blob.openInputStream();
blob.delete();
container.exists();
container.listBlobs().iterator().next();
container.getDirectoryReference("tmp/").listBlobs().iterator().next()
But, I could not find a way to generate a single Account SAS to support all methods listed above.
Account SAS generated with SharedAccessAccountResourceType.OBJECT:
Executes successfully:
CLoudBlockBlob blob = container.getBlockBlobReference("tmp/test.json");
blob.exists();
blob.openInputStream();
blob.delete();
Fails with an error code: AuthorizationResourceTypeMismatch
container.exists();
container.listBlobs().iterator().next();
container.getDirectoryReference("tmp/").listBlobs().iterator().next()
Account SAS generated with SharedAccessAccountResourceType.CONTAINER:
Executes successfully:
container.exists();
container.listBlobs().iterator().next();
container.getDirectoryReference("tmp/").listBlobs().iterator().next()
Fails with an error code: AuthorizationResourceTypeMismatch
CLoudBlockBlob blob = container.getBlockBlobReference("tmp/test.json");
blob.exists();
blob.openInputStream();
blob.delete();
Account SAS generated with SharedAccessAccountResourceType.SERVICE
fails with an error code: AuthorizationResourceTypeMismatch for all methods above.
Is there any way to generate a single Account SAS which work for all following methods?
CLoudBlockBlob blob = container.getBlockBlobReference("tmp/test.json");
blob.exists();
blob.openInputStream();
blob.delete();
container.exists();
container.listBlobs().iterator().next();
container.getDirectoryReference("tmp/").listBlobs().iterator().next()
Yea just add the right permissions on the blob and container resources. Note that list is different from the create.
You can find it here
And then add permissions
For listing blobs in a blob container, you would need to set resource type as Container. The permission you would need would be List.
For checking if blob exists, you would need to set resource type as Object. The permission you would need would be Read.
For deleting blob, you would need to set the permission as Delete. The resource type would still be Object.
Since you're working with just Blob Storage, the service type would be just Blob.
To summarize:
Service Type: Blob
Resource Types: Container (for listing blobs), and Object (for checking blob's existence and deleting blob)
Permissions: List, Read, and Delete
With this you should be able to accomplish your goal.
Setting both resource types resolved the issue:
sasAccountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER));
(The application which I'm developing also has to generate SAS URI.)
Thanks.

How to upload encoded metadata to sharepoint using ValidateUpdateListItem method?

I am trying to upload metadata to SharePoint server using ValidateUpdateListItem method. In this method, value of bNewDocumentUpdate is true to avoid creating a new version for the uploaded file. The name of metadata which has to be updated, is 'cc1'. When i fetch metadata information, the name of metadata is converted from 'cc1' to 'OData__x0063_c1'. Now, i have used both the names (encoded and decoded) to upload the metadata, but below error is generated -
{"error":{"code":"-2147024809, System.ArgumentException","message":{"lang":"en-US","value":"Column 'cc1' does not exist. It may have been deleted by another user. /Shared Documents"}}}
Earlier, i was not using ValidateUpdateListItem method, and was able to upload metadata using encoded name.
Is there any way to upload the encoded metadata while using ValidateUpdateListItem method?
Update -
This problem has been resolved by using 'InternalName' of metadata. Earlier i was using 'EntityPropertyName' of metadata to set metadata value.

Ensure file insertion finished with GridFS - MongoDB Java API

I have a REST service to upload images and this is the main code in charge of the registration in mongodb:
public String writeFiles(InputStream inputStream, String fileName, String contentType) throws IOException {
// save the file
GridFS gridFS = new GridFS(getDB(), Collections.PICTURES_FILES.name());
GridFSInputFile gridFSInputFile = gridFS.createFile(inputStream, fileName);
gridFSInputFile.setContentType(contentType);
gridFSInputFile.setMetaData(new BasicDBObject(ORIGINAL_PICT_COL, true));
gridFSInputFile.save();
return gridFSInputFile.getId();
}
The service then return the file ID to the client so that this one can ask for and display the uploaded image.
The problem is for very large images: sometime while requesting an image by its ID right after the upload gives a HTTP 404 error (due to unknown image ID on server side, this is a correct behavior).
I suppose it happens because registration time on the server side is greater than time used to get the ID back and request the new image on the client side - i.e the '.save()' operation is async, right ?
My question: How to be sure that the save operation has been completed before returning the ID in the given code ?
Or how to obtain a result object as for .insert operation ?
Does a
gridFSInputFile.validate();
would be enought ?
Or
getDB().getLastError()
?
I cannot reproduce easily this "bug" so i ask the question in case someone with experience already know how to solve this. Thanks in advance for your help.
If you are using a recent version of the Java driver (2.10 or later), try creating an instance of MongoClient instead of an instance of Mongo. The default write concern is WriteConcern.ACKNOWLEDGED for instances of MongoClient, so the save method will not complete until the write operation has completed.
Otherwise, in your getDB method (not shown), call the method DB.setWriteConcern(WriteConcern.SAFE) to change the default write concern.
The other possibility is that you are reading from a secondary member of your replica set. The default is to read from the primary, but if you are overriding that, then your reads will be eventually consistent, and you could see this problem in that case as well.

Oracle Workflow API: adding and accessing file Attachments to a Human Task

I am using the Workflow Services Java API (11.1.1) for SOA Suite to access and manipulate human tasks. I would like to be able to access and add file attachments to existing human tasks. I am using the methods provided in the AttachmentType interface.
When adding an attachment, the problem I am running into is that an attachment does get created and associated with the task, however it is empty and has no content. I have attempted both setting the input stream of the attachment, as well as the content string and in each case have had no success (and setting the content string results in an exception when trying to update the corresponding task).
I have successfully added and accessed an attachment using the worklist application, however when trying to access the content of this attachment through code I receive an object with mostly null/0 values throughout, apart from the attachment name.
The code I am using to access attachments resembles:
List attachments = taskWithAttachments.getAttachment();
for(Object o : attachments){
AttachmentType a = (AttachmentType) o;
String content = a.getContent(); // NULL
InputStream str = a.getInputStream(); // NULL
String name = a.getName(); // Has the attachment name
String mime = a.getMimeType(); // Has the mime type
long size = a.getSize(); // 0
...
}
As the API's are not overly rich in documentation I may well be using them incorrectly. I would really appreciate any help/suggestions/alternatives in dealing with BPEL task attachments.
Thanks
After contacting Oracle for support, it turns out that the attachments portion of the Workflow API is broken in the current release. The fix will be included in a future release.

Categories