B4J Question Help with Parse

derez

Expert
Licensed User
Longtime User
I made a Family Tree app which updates the DB at several users using PARSE.
It works nice and I made an equivalent app with B4j but the PARSE lib is not compatible.
Agraham showed me their REST API https://parse.com/docs/rest#users-login
It looks like something that can be done using HTTP and HTTPUTILS but I have no experience. The examples are in PYTHON or CURL.
For example : login process
B4X:
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"username":"cooldude6","password":"p_n7!-e8"})
connection.connect()
connection.request('GET', '/1/login?%s' % params, '', {
"X-Parse-Application-Id": "${APPLICATION_ID}",
"X-Parse-REST-API-Key": "${REST_API_KEY}"
})
result = json.loads(connection.getresponse().read())
print result

I made a successful connection :
B4X:
skt.Initialize("skt")
skt.Connect("api.parse.com", 443,0)

But got lost afterwards. I guess it should be job1.download2() with the username & password (which I have).
After login I need to get objects and send objects.
If someone could help – I’ll appreciate.
 

derez

Expert
Licensed User
Longtime User
I installed the new files and now the init of Httpjob initialize("log-in",Me) doesn't work:
Program started.
Error occurred on line: 19 (main).
java.lang.NoSuchMethodException: org.apache.http.conn.ssl.SSLSocketFactory.<init>(javax.net.ssl.SSLSocketFactory)
at java.lang.Class.getConstructor0(Class.java:2810)
at java.lang.Class.getConstructor(Class.java:1718)
at anywheresoftware.b4a.http.HttpClientWrapper.InitializeAcceptAll(HttpClientWrapper.java:125)
at b4j.example.httputils2service._initialize(httputils2service.java:78)
at b4j.example.httpjob._initialize(httpjob.java:177)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:503)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:215)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:153)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:93)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:69)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:84)
at b4j.example.main.start(main.java:33)
at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:216)
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179)
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:76)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:17)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:67)
at java.lang.Thread.run(Thread.java:744)
 
Upvote 0

derez

Expert
Licensed User
Longtime User
I managed to upload a file to the /1/files storage area, and got back its name.
B4X:
Sub file_Action
  Dim j As HttpJob
  j.Initialize("file", Me)
  j.PostFile("https://api.parse.com/1/files/3000.txt", "D:\parse","3000.txt")
    j.GetRequest.SetHeader("X-Parse-REST-API-Key", "opBMoH2Qqguvx3eDhcwEAZ0Jdl4nuLUP5BgRZWZb")
  j.GetRequest.SetHeader("X-Parse-Application-Id", "vWcbP5PvajXyGcF123E0Z9F4tSCIwvS9AtIZmwCz")
  j.GetRequest.SetContentType("text/plain")
End Sub


Then I did "Association with object" :
B4X:
Sub save_file(st)
Dim m, m1 As Map
m.Initialize
m1.Initialize
m1.Put("name",filename)
m1.Put("__type","File")
m.Put("html",m1)
Dim gen As JSONGenerator
gen.Initialize(m)
Dim j As HttpJob
j.Initialize("Associate",Me)
j.PostString("https://api.parse.com/1/classes/Family", gen.ToString)
j.GetRequest.SetHeader("X-Parse-REST-API-Key", "opBMoH2Qqguvx3eDhcwEAZ0Jdl4nuLUP5BgRZWZb")
  j.GetRequest.SetHeader("X-Parse-Application-Id", "vWcbP5PvajXyGcF123E0Z9F4tSCIwvS9AtIZmwCz")
  j.GetRequest.SetContentType("application/json")
End Sub

The file now appears in field "html" in a new line since I don't know how to update an object...o_O
It is late, I'll think tomorrow...

And one more problem: the API shows how to delete an object or a file with "DELETE" command. How to implement it ?
 
Last edited:
Upvote 0

derez

Expert
Licensed User
Longtime User
Thanks. I checked and succeeded to update and delete and object and associating a file to an existing object.
I am still trying to delete a file from its storage. I tried to do it with delete() by adding the filename to the path like here:
connection.request('DELETE', '/1/files/...profile.png', '', {
"X-Parse-Application-Id": "ZGNsrGgSDVZaYmXpnAc5aX4d0Ivc2yASOr8qe1xX",
"X-Parse-Master-Key": "MAIpiN7H5vgnryiSDJ4X9iOQPqKrvUQ2alHCYHAT"
})
But it does not find it.
I tried to put the filename as parameter in delete2() but it fails also. I also tried delete() with the file's url but failed.
 
Upvote 0

derez

Expert
Licensed User
Longtime User
This doesn't work :
B4X:
Dim ApiKey As String = "opBMoH2Qqguvx3eDhcwEAZ0Jdl4nuLUP5BgRZWZb"
Dim master As String = "BB69dVtdhXyAG9aSPLhIcqkIoOYnrDjQRBiFYMrQ"
Dim AppId As String  = "vWcbP5PvajXyGcF123E0Z9F4tSCIwvS9AtIZmwCz"
dim filename as string = "94388913-bf9a-4e70-b0ea-e6768088986f-3000.txt"
Dim j As HttpJob
j.Initialize("del", Me)
' This
j.Delete("https://api.parse.com/1/files/" & filename )

'or this
j.Delete2("https://api.parse.com/1/files",Array As String(filename ))

j.GetRequest.SetHeader("X-Parse-Application-Id", AppId)
j.GetRequest.SetHeader( "X-Parse-Master-Key", master)

Compare to "Deletiing Files" in the API.

This works:
B4X:
'del object
Dim j As HttpJob
j.Initialize("del", Me)
j.Delete("https://api.parse.com/1/classes/Family/9YInGuVMA5")
j.GetRequest.SetHeader("X-Parse-REST-API-Key", ApiKey)
j.GetRequest.SetHeader("X-Parse-Application-Id", AppId)
 
Last edited:
Upvote 0

derez

Expert
Licensed User
Longtime User
Yes, and I can get it also from the field where it shows in the object line. In my DB it is in "html" field:
B4X:
...
Dim k As Int = m.Get("No")
m2 = m.Get("html")
If m2.IsInitialized Then
    Dim j As HttpJob
    j.Initialize("txt"&k,Me) 'k is a way to get the number later in jobDone.
    Log("name = " & m2.Get("name"))  ' if you want to delete the file you need this name
    '    Log(m2.get("url"))  ' or this ????
    j.Download(m2.Get("url"))  ' to get the file itself, then save it in the jobDone sub
End If

I tried it again with Delete() and it works :) (in the object it still shows but when pressed it doesn't find it because it had been deleted !

Thanks Erel.
I'll try to put everything in a convenient way as a class and publish it (unless you are doing it ?)
Next step will be to add notifications.
 
Last edited:
Upvote 0

derez

Expert
Licensed User
Longtime User
One last thing (in the meantime...) :
Getting an object can be done with constraints, like this
B4X:
 j.Download2("https://api.parse.com/1/classes/Family", Array As String("where", "{""No"":110}"))
Is it possible to get the object like this for updating or deleting ? Delete2 has an array but put will be useful to have (will save a cycle of getting the objectId).
Delete2() without the objectId and with parameter doesn't work.
 
Last edited:
Upvote 0

derez

Expert
Licensed User
Longtime User
You do not need to escape it.
I don't understand.
how do I combine this
B4X:
Array As String("where", "{""No"":110}"))
with the map of data to be updated, all to be one json string gen.ToString ?
 
Last edited:
Upvote 0

derez

Expert
Licensed User
Longtime User
Just write: "where={""No"":110}"
Erel
This is to define the object to be updated, but I need to put somehow in the command the map of data that is the update. How ?
 
Upvote 0

derez

Expert
Licensed User
Longtime User
Please try to understand the problem.
I can get an object with "where={""No"":110}" and I can also make it a map in Json.
To update an object I use a map of all key-value pairs of the object (those to be updated), = Data.
I don't know how to put both maps into the json string. I tried to add the "where={""No"":110}" as another map to the data map but it failed. I think there should be a higher level map which will look like this:

m1.put("No",110)
map1.put("where",m1)
map1.put("?????",Data)
gen.initialize(map1)
j. putstring([address] ,gen.tostring)

but I can't find the answer in the api.
 
Upvote 0
Top