Update metadata of object in Google Cloud Storare with Java/Kotlin gives NullPoinerException - kotlin

I have created a function to update metadata of an object in Google Cloud Storage.
fun updateUserMetadata(objectName: String, userMetadata: Map<String, String>) {
val blobId = BlobId.of(bucketName, basePath + objectName)
val blobInfo: BlobInfo = BlobInfo.newBuilder(blobId)
.setMetadata(userMetadata)
.build()
storage.update(blobInfo)
}
Somehow this function always gives me the following exception:
java.lang.NullPointerException
at com.google.cloud.storage.BlobId.fromPb(BlobId.java:119)
at com.google.cloud.storage.BlobInfo.fromPb(BlobInfo.java:1029)
at com.google.cloud.storage.Blob.fromPb(Blob.java:918)
at com.google.cloud.storage.StorageImpl.update(StorageImpl.java:428)
at com.google.cloud.storage.StorageImpl.update(StorageImpl.java:447)
at com.peerke.outdoorpuzzlegame.backend.common.gcp.cloudstorage.CloudStorageBase.updateUserMetadata(CloudStorageBase.kt:88)
at com.peerke.outdoorpuzzlegame.backend.common.gcp.cloudstorage.CloudStorageBaseTest.testUpdateUserMetadata(CloudStorageBaseTest.kt:71)
In the function above non of the variables are null.
Is this a bug or am I doing something wrong?

I've been looking into how you are passing things and I first did not see anything directly wrong. What I found though makes total sense and I hope helps you in finding a solution is this:
gsObjectName - the object name of this Blob, if it is stored on Google Cloud Storage, null otherwise.
I'm inclining towards it being a pathing issue on how you are pointing to the GCS object. It not being able to reach where you are pointing would explain why a nullpointer is raised.
I would recommend revising the way you are pointing to the path of the GCS object.
Hope this helps.
EDIT:
I've found another thing that might help you solve the issue. This is a similar way of doing what you are attempting to do and the different perspective might help you out.
Have a look here

Related

How to make a post request using the gogearbox framework

I am currently stuck because I do not know how to complete my Post request for a project I am doing. I am using a framework called gearbox (I wanted to try something new). The main problem is I don't know how to bind the json to the new variable. So can anyone help me with this issue. For the info I can post the GitHub package. It's "github.com/gogearbox/gearbox" , Please help me.
I did try to look up the documentation,and I did try a few different functions but it didn't work so if anyone can help me please.
You should provide some code even if it doesn't work. It's usually a good starting point. This way we can avoid trying things you already tested out. I've briefly read the doc and didn't test the code below but you may try to look at the ParseBody function:
type Payload struct{
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
requestHandler := func(ctx *fasthttp.RequestCtx) {
var payload *Payload
err := ctx.ParseBody(&payload)
if err!= nil {
ctx.Status(gearbox.StatusInternalServerError).SendString("Something went wrong when parsing your payload!")
}
// do something with your payload
}
reference here

Apache OAK Direct Binary Access with S3DataStore

I'm trying to figure out how the direct binary access feature works with Apache Oak.
My understanding so far is, I can set binary properties to nodes, and later, I should be able to get a direct download link (from S3).
First, I created a node and added a binary property with the contents of some file.
val ntFile = session.getRootNode.addNode(path, "nt:file")
val ntResource = ntFile.addNode("jcr:content", "nt:resource")
ntResource.setProperty("jcr:mimeType", "application/octet-stream")
ntResource.setProperty("jcr:lastModified", Calendar.getInstance())
val fStream = new FileInputStream("/home/evren/cast.webm")
val bin = session.getValueFactory.asInstanceOf[JackrabbitValueFactory].createBinary(fStream)
ntResource.setProperty("jcr:data", bin)
And I can see on the AWS Console, my binary is uploaded.
But, still, I cannot generate direct download URI, even following the documentation on the OAK website. (So the code continues)
session.save()
session.refresh(false)
val binary = session.getRootNode.getNode(path)
.getNode("jcr:content").getProperty("jcr:data").getValue.getBinary
val uri = binary.asInstanceOf[BinaryDownload].getURI(BinaryDownloadOptions.DEFAULT)
It's always returning null.
Someone please could point me to what I am doing wrong or is my understanding.
Thanks in advance.
I figured it out. In case, anyone else is facing the same issue, the trick is to register your BlobStore using a WhiteBoard.
This explains a lot about the issue that, I could upload files directly using BlobStorage but OAK itself could not use the BlobStore functionality to get a direct download link.
val wb = new DefaultWhiteboard()
// register s3/azure as BlobAccessProvider
wb.register(
classOf[BlobAccessProvider],
blobStore.asInstanceOf[BlobAccessProvider],
Collections.emptyMap()
)
val jcrRepo = new Jcr(nodeStore).`with`(wb).createRepository()
And once you create your JCR Repo like this, direct binary download/upload works as expected.

Using Leigh version of S3Wrapper.cfc Can't get past Init

I am new to S3 and need to use it for image storage. I found a half dozen versions of an s2wrapper for cf but it appears that the only one set of for v4 is one modified by Leigh
https://gist.github.com/Leigh-/26993ed79c956c9309a9dfe40f1fce29
Dropped in the com directory and created a "test" page that contains the following code:
s3 = createObject('component','com.S3Wrapper').init(application.s3.AccessKeyId,application.s3.SecretAccessKey);
but got the following error :
So I changed the line 37 from
variables.Sv4Util = createObject('component', 'Sv4').init(arguments.S3AccessKey, arguments.S3SecretAccessKey);
to
variables.Sv4Util = createObject('component', 'Sv4Util').init(arguments.S3AccessKey, arguments.S3SecretAccessKey);
Now I am getting:
I feel like going through Leigh code and start changing things is a bad idea since I have lurked here for year an know Leigh's code is solid.
Does any know if there are any examples on how to use this anywhere? If not what I am doing wrong. If it makes a difference I am using Lucee 5 and not Adobe's CF engine.
UPDATE :
I followed Leigh's directions and the error is now gone. I am addedsome more code to my test page which now looks like this :
<cfscript>
s3 = createObject('component','com.S3v4').init(application.s3.AccessKeyId,application.s3.SecretAccessKey);
bucket = "imgbkt.domain.com";
obj = "fake.ping";
region = "s3-us-west-1"
test = s3.getObject(bucket,obj,region);
writeDump(test);
test2 = s3.getObjectLink(bucket,obj,region);
writeDump(test2);
writeDump(s3);
</cfscript>
Regardless of what I put in for bucket, obj or region I get :
JIC I did go to AWS and get new keys:
Leigh if you are still around or anyone how has used one of the s3Wrappers any suggestions or guidance?
UPDATE #2:
Even after Alex's help I am not able to get this to work. The Link I receive from getObjectLink is not valid and getObject never does download an object. I thought I would try the putObject method
test3 = s3.putObject(bucketName=bucket,regionName=region,keyName="favicon.ico");
writeDump(test3);
to see if there is any additional information, I received this :
I did find this article https://shlomoswidler.com/2009/08/amazon-s3-gotcha-using-virtual-host.html but it is pretty old and since S3 specifically suggests using dots in bucketnames I don't that it is relevant any longer. There is obviously something I am doing wrong but I have spent hours trying to resolve this and I can't seem to figure out what it might be.
I will give you a rundown of what the code does:
getObjectLink returns a HTTP URL for the file fake.ping that is found looking in the bucket imgbkt.domain.com of region s3-us-west-1. This link is temporary and expires after 60 seconds by default.
getObject invokes getObjectLink and immediately requests the URL using HTTP GET. The response is then saved to the directory of the S3v4.cfc with the filename fake.ping by default. Finally the function returns the full path of the downloaded file: E:\wwwDevRoot\taa\fake.ping
To save the file in a different location, you would invoke:
downloadPath = 'E:\';
test = s3.getObject(bucket,obj,region,downloadPath);
writeDump(test);
The HTTP request is synchronous, meaning the file will be downloaded completely when the functions returns the filepath.
If you want to access the actual content of the file, you can do this:
test = s3.getObject(bucket,obj,region);
contentAsString = fileRead(test); // returns the file content as string
// or
contentAsBinary = fileReadBinary(test); // returns the content as binary (byte array)
writeDump(contentAsString);
writeDump(contentAsBinary);
(You might want to stream the content if the file is large since fileRead/fileReadBinary reads the whole file into buffer. Use fileOpen to stream the content.
Does that help you?

How can you use SessionAsSigner in a Java Bean called from an XPage?

According to Phillip Riand (see: discussion on openNTF) this is not possible... They need to know the design element to find out who signed it. Therefore, it is only available in SSJS.
There are 2 ways that I know of to use the sessionAsSigner object in Java beans:
1 By resolving the sessionAsSigner object:
FacesContext context = FacesContext.getCurrentInstance();
Session sessionAsSigner = context.getApplication().getVariableResolver().
resolveVariable(context, "sessionAsSigner");
2 By using the getCurrentSessionAsSigner() function from the com.ibm.xsp.extlib.util.ExtLibUtil class in the Extension Library.
To be able to use it (in Java as wel as SSJS) you'll want to make sure that all design elements were signed by the same user ID. If that's not the case, the sessionAsSigner object will not be available ('undefined').
I found that the solution is right at hand :-)
I changed my XPage (in this example an XAgent) to:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
This is an xAgent returning json data...
<xp:this.afterRenderResponse><![CDATA[#{javascript:Controller.verify(sessionAsSigner)}]]></xp:this.afterRenderResponse>
and in the bean I simply used the session in the argument when I needed to open a database/document as signer. Sometimes the solution is so simple :-)
/John
This is quite an old post that I just stumbled upon. Tried some of the solutions mentioned above:
resolveVariable did not work for me, at least not for sessionAsSigner as this throws a runtime error (I can resolve plain old session, though...)
to be honest I didn't quite understand the Controller.verify(sessionAsSigner) method; is Controller something specific to XAgents? If so, I don't have an XAgent here, so can't use it
didn't feel like importing extra ExtLib classes here...
So I came up with another solution that appears to be very simple:
created a method in my javaBean that takes a session object as argument; since sessionAsSigner belongs to the same class as session I don't have to import something new.
Javacode is:
public void testSession(Session s) throws Exception{
System.out.println(" > test effective user for this session = "
+ s.getEffectiveUserName());
}
This is called from SSJS as either
mybean.testSession(session);
or
myBean.testSession(sessionAsSigner);
Maybe helps others, too

How do I utilize a named instance within the ObjectFactory.Initialize call for StructureMap?

I am trying to do the following bootstrapping:
x.For(Of IErrorLogger).Use(Of ErrorLogger.SQLErrorLogger)().
Ctor(Of IErrorLogger)("backupErrorLogger").Is(ObjectFactory.GetNamedInstance(Of IErrorLogger)("Disk"))
x.For(Of IErrorLogger).Add(
Function()
Return New ErrorLogger.DiskErrorLogger(
CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))
End Function).Named("Disk")
But it shows this error:
StructureMap Exception Code: 200
Could not find an Instance named "Disk" for PluginType Logging.IErrorLogger
I sort of understand why this is happening.. the question is, how do I utilize a named instance within the registry? Maybe something like lazy initialization for the ctor argument for the SQLErrorLogger? I am not sure how to make it happen.
Thanks in advance for any help you can provide.
I found the correct way to do it in the latest version (2.6.1) of StructureMap:
x.For(Of IErrorLogger).Use(Of ErrorLogger.SQLErrorLogger)().
Ctor(Of IErrorLogger)("backupErrorLogger").Is(
Function(c) c.ConstructedBy(Function() ObjectFactory.GetNamedInstance(Of IErrorLogger)("Disk"))
)
x.For(Of IErrorLogger).Add(Function() _
New ErrorLogger.DiskErrorLogger(
CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))
).Named("Disk")
Notice for the Is method of Ctor, we need to provide a func(IContext), and use the IContext.ConstructedBy(Func()) to call ObjectFactory.Get... to successfully register the IErrorLogger in this case.
This is the only way to do it as far as I know. The other Icontext methods such as IsThis and Instance will only work with already registered type.
Your problem is that you are trying to access the Container before it's configured. In order to make structuremap evaluate the object resolution after the configuration you need to provide a lambda to the Is function. The lambda will be evaluated when trying to resolve the type registered.
x.[For](Of ILogger)().Add(Of SqlLogger)().Ctor(Of ILogger)("backupErrorLogger")_
.[Is](Function(context) context.GetInstance(Of ILogger)("Disk"))
x.[For](Of ILogger)().Add(Of DiskLogger)().Ctor(Of String)("errorFileName")_
.[Is](CreateErrorFileName(ServerMapPath(GetAppSetting("ErrorLogFolder"))))_
.Named("Disk")
Disclaimer: I'm not completely up-to-date with the lambda syntax in VB.NET, but I hope I got it right.
Edit:
The working C# version of this I tried myself before posting was this:
ObjectFactory.Initialize(i =>
{
i.For<ILogger>().Add<SqlLogger>()
.Ctor<ILogger>("backup").Is(
c => c.GetInstance<ILogger>("disk"))
.Named("sql");
i.For<ILogger>().Add<DiskLogger>().Named("disk");
});
var logger = ObjectFactory.GetNamedInstance<ILogger>("sql");