Parse library (beta) - simple backend solution

Erel

B4X founder
Staff member
Licensed User
Longtime User
Parse is a company that provides several services for mobile applications.
www.parse.com

This library is a simple wrapper for ParseObject and ParseQuery.
Using these objects it is simple to store and retrieve data on the cloud.

The web interface:
SS-2011-11-16_16.41.39.png


This library is considered a beta library. If there will be interest in this library and the other features provided by Parse.com then it will be further developed. Please provide your feedback.

All the operations which need to access their online service are done asynchronously and raise events when done.
Please read their guide for more information about the usage.

Installation instructions:

- In order to use this library you should sign to Parse.com and create a new application.
You will get two keys: ClientKey and ApplicationId. Both are required.

- You also need to download their SDK. You will find a jar file named Parse-0.3.8.jar.
You should rename it to ParseNative.jar and copy it to the libraries folder.

- Download the attached zip file and copy all three files to the libraries folder.

- You should add a reference to Parse and ParseNative in the libs tab.

A simple program that creates several objects and then retrieves those objects:
B4X:
Sub Process_Globals
   Dim AppId, ClientKey As String
   AppId = "YourAppId"
   ClientKey = "YoudClientKey"
   Dim Parse As Parse
End Sub
Sub Globals
   
End Sub
Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      Parse.Initialize(AppId, ClientKey)
   End If
   Activity.AddMenuItem("Add Items", "AddItems")
   Activity.AddMenuItem("List Items", "ListItems")
   Activity.AddMenuItem("Delete Items", "DeleteItems")
End Sub
Sub AddItems_Click
   Dim po As ParseObject
   po.Initialize("Color")
   po.Put("Name", "Red")
   po.Put("IntValue", Colors.Red)
   po.Save("po")
   
   Dim po As ParseObject
   po.Initialize("Color")
   po.Put("Name", "Blue")
   po.Put("IntValue", Colors.Blue)
   po.Save("po")
   ProgressDialogShow("Waiting for response.")
End Sub

Sub po_DoneSave (Success As Boolean)
   ProgressDialogHide
   Dim po As ParseObject
   po = Sender
   Dim msg As String
   msg = "Saving Color: " & po.GetString("Name") &  " Success=" & Success
   Log(msg)
   ToastMessageShow(msg, False)
   If Success = False Then
      Log(LastException.Message)
   End If
End Sub

Sub ListItems_Click
   Dim query As ParseQuery
   query.Initialize("Color")
   query.OrderBy("Name", True)
   query.Find("query", 1)
   ProgressDialogShow("Waiting for response.")
End Sub
Sub query_DoneFind (Success As Boolean, ListOfPO As List, TaskId As Int)
   ProgressDialogHide
   If Success = False Then
      Log("Error: " & LastException.Message)
      ToastMessageShow("Error: " & LastException.Message, True)
   Else
      Dim sb As StringBuilder
      sb.Initialize
      For i = 0 To ListOfPO.Size - 1
         Dim po As ParseObject
         po = ListOfPO.Get(i)
         sb.Append(po.GetString("Name")).Append("=").Append(po.GetInt("IntValue")).Append(CRLF)
      Next
      Msgbox(sb.ToString, "")
   End If
End Sub

Sub DeleteItems_Click
   Dim query As ParseQuery
   query.Initialize("Color")
   query.Find("DeleteItems", 1)
   ProgressDialogShow("Waiting for response.")   
End Sub
Sub DeleteItems_DoneFind (Success As Boolean, ListOfPO As List, TaskId As Int)
   ProgressDialogHide
   If Success = False Then
      Log("Error: " & LastException.Message)
      ToastMessageShow("Error: " & LastException.Message, True)
   Else
      
      For i = 0 To ListOfPO.Size - 1
         Dim po As ParseObject
         po = ListOfPO.Get(i)
         po.Delete("delete")
         ProgressDialogShow("Waiting for response.")
      Next
      
   End If
End Sub
Sub Delete_DoneDelete (Success As Boolean)
   ProgressDialogHide
   Dim po As ParseObject
   po = Sender
   Log(po.ObjectId & " delete, success = " & Success)
End Sub

Sub Activity_Pause(UserClosed As Boolean)
   
End Sub
Sub Activity_Resume

End Sub
 

Attachments

  • Parse.zip
    11.3 KB · Views: 511

NJDude

Expert
Licensed User
Longtime User
That's very nice but the "We're FREE during the beta!" might make it a little bit non-attractive for some.

My 2 cents.
 

bluedude

Well-Known Member
Licensed User
Longtime User
NJDude,

Not everything is for free in this world :) Their pricing seems to be very reasonable.

Cheers,
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
I really would use it, now I can't use HTTP GET and HTTP POST anymore becaus e our web developer died in a car accident. :(

Erel, Is there a way to update/replace a cell?
Like instead of parsing all objects, and then uploading everything, but than changing one thing it is way easier to just change that one object.

Thanks,
Tomas
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I really would use it, now I can't use HTTP GET and HTTP POST anymore becaus e our web developer died in a car accident.
:(

Erel, Is there a way to update/replace a cell?
Like instead of parsing all objects, and then uploading everything, but than changing one thing it is way easier to just change that one object.
You can get an object with ParseQuery, update its fields and then save it. There is no need to upload other objects.
 

XverhelstX

Well-Known Member
Licensed User
Longtime User
:(


You can get an object with ParseQuery, update its fields and then save it. There is no need to upload other objects.

Can you give me an example of how to update it?
The way I do it is by searching by IMEI (unique identifier), and parsing all into variables, delete the row with the imei, and reupload the downloaded variables and changing a variable that needed.

Tomas
 

JMB

Active Member
Licensed User
Longtime User
Problems.

Hi there Erel

The Parse thing looks VERY useful, especially if you could implement the Users side of things in B4A.

However, I've tried to use this code but without success.

I have the two IDs from Parse.com, but when I try and use your code, I get the following error:

com.parse.ParseException: bad json response: org.json.JSONException: Value Invalid of type java.lang.String cannot be converted to JSONObject

I note that in the Parse documentation, they suggest writing a piece of code with the IDs, and then sending a message to their servers to make sure everything is working. Since this was in java and I don't have the eclipse environment installed, I did not do this. Is this step required by parse.com to activate the account in some way?

Thanks for your help

JMB
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Tomas, see this code for example:
B4X:
Sub query_DoneFind (Success As Boolean, ListOfPO As List, TaskId As Int)
   ProgressDialogHide
   If Success = False Then
      Log("Error: " & LastException.Message)
      ToastMessageShow("Error: " & LastException.Message, True)
   Else
      Dim sb As StringBuilder
      sb.Initialize
      For i = 0 To ListOfPO.Size - 1
         Dim po As ParseObject
         po = ListOfPO.Get(i)
         If po.GetString("Name") = "Red" Then
            po.Put("Name", "Orange") 'change the name
            po.Save("")
         End If
         sb.Append(po.GetString("Name")).Append("=").Append(po.GetInt("IntValue")).Append(CRLF)
      Next
      Msgbox(sb.ToString, "")
   End If
End Sub

JMB, make sure that there are no extra spaces in the keys.
I can send you my keys if you want to test.
 

JMB

Active Member
Licensed User
Longtime User
Spaces! There they were, at the end of my strings!

Sorted now, and working.

Thanks Erel.

JMB
 

JMB

Active Member
Licensed User
Longtime User
Really useful

Erel, having played around with this I think it has huge potential, especially as the guys at parse have created an api to allow access to the database through other methods.

However, I was wondering if you had any plans to implement the user side of things in b4a? For me, that would make parse hugely useful from b4a.

Just my tuppence worth.

JMB
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I do plan to add other features in the future.

I will also post the source code if anyone wants to play with it:
B4X:
package anywheresoftware.b4a.objects;

import java.util.List;

import anywheresoftware.b4a.AbsObjectWrapper;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.Permissions;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;
import anywheresoftware.b4a.keywords.Common;

import com.parse.CountCallback;
import com.parse.DeleteCallback;
import com.parse.FindCallback;
import com.parse.GetCallback;
import com.parse.Parse;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import com.parse.RefreshCallback;
import com.parse.SaveCallback;

/**
 *    
 */
@Version(1.0f)
@Events(values={
      "DoneSave (Success As Boolean)",
      "DoneDelete (Success As Boolean)",
      "DoneRefresh (Success As Boolean)"
      })
@ShortName("ParseObject")
public class ParseObjectWrapper extends AbsObjectWrapper<ParseObject>{
   /**
    * Initializes the object and sets the class name.
    */
   public void Initialize(String ClassName) {
      setObject(new ParseObject(ClassName));
   }
   public boolean ContainsKey(String Key) {
      return getObject().containsKey(Key);
   }
   public void Put(String Key, Object Value) {
      getObject().put(Key, Value);
   }
   public String GetString(String Key) {
      return getObject().getString(Key);
   }
   public double GetDouble(String Key) {
      return getObject().getDouble(Key);
   }
   public long GetLong(String Key) {
      return getObject().getLong(Key);
   }
   public boolean GetBoolean(String Key) {
      return getObject().getBoolean(Key);
   }
   public int GetInt(String Key) {
      return getObject().getInt(Key);
   }
   public long getCreatedAt() {
      return getObject().getCreatedAt().getTime();
   }
   public long getUpdatedAt() {
      return getObject().getUpdatedAt().getTime();
   }
   public String getObjectId() {
      return getObject().getObjectId();
   }
   /**
    * Saves the object on the server.
    *DoneSave event will be raised when saving completes.
    */
   public void Save(final BA ba, final String EventName) {
      if (EventName.length() == 0) {
         getObject().saveInBackground();
      }
      else {
         getObject().saveInBackground(new SaveCallback() {
   
            @Override
            public void done(ParseException e) {
               setLastException(ba, e);
               ba.raiseEventFromDifferentThread(getObject(), null, 0, EventName.toLowerCase(BA.cul) + "_donesave", 
                  true,
                  new Object[] {e == null});
            }
            
         });
      }
   }
   /**
    * Deletes the object from the server.
    *DoneDelete event will be raised when saving completes.
    */
   public void Delete(final BA ba, final String EventName) {
      if (EventName.length() == 0) {
         getObject().deleteInBackground();
      }
      else {
         getObject().deleteInBackground(new DeleteCallback() {

            @Override
            public void done(ParseException e) {
               setLastException(ba, e);
               ba.raiseEventFromDifferentThread(getObject(), null, 0, EventName.toLowerCase(BA.cul) + "_donedelete", 
                  true,
                  new Object[] {e == null});
            }
            
         });
      }
   }
   /**
    * Refreshes the object by reading it from the server.
    *DoneRefresh event will be raised when the operation completes.
    */
   public void Refresh(final BA ba, final String EventName) {
      getObject().refreshInBackground(new RefreshCallback() {

         @Override
         public void done(ParseObject object, ParseException e) {
            setLastException(ba, e);
            ba.raiseEventFromDifferentThread(getObject(), null, 0, EventName.toLowerCase(BA.cul) + "_donerefresh", 
               true,
               new Object[] {e == null});
         }
         
      });
   }
   static void setLastException(BA ba, Exception e) {
      if (e != null) {
         BA b = ba;
         if (ba.processBA != null)
            b = ba.processBA;
         b.setLastException(e);
         e.printStackTrace();
      }
   }
   
   @ShortName("Parse")
   @Permissions(values = {"android.permission.INTERNET"})
   public static class ParseWrapper {
      /**
       * Initializes the Parse library.
       */
      public static void Initialize(String ApplicationId, String ClientId) {
         Parse.initialize(BA.applicationContext, ApplicationId, ClientId);
      }
   }
   
   @ShortName("ParseQuery")
   @Events(values={
         "DoneGet (Success As Boolean, PO As ParseObject, TaskId As Int)",
         "DoneFind (Success As Boolean, ListOfPO As List, TaskId As Int)",
         "DoneCount (Success As Boolean, Count As Int, TaskId As Int)"})
   public static class ParseQueryWrapper extends AbsObjectWrapper<ParseQuery> {
      /**
       * Initializes the object and sets the class name.
       */
      public void Initialize(String ClassName) {
         setObject(new ParseQuery(ClassName));
      }
      /**
       * Gets an object based on its ObjectId.
       *DoneGet event will be raised when the operation completes.
       */
      public void GetById(final BA ba, final String EventName, final String ObjectId, final int TaskId) {
         getObject().getInBackground(ObjectId, new GetCallback() {

            @Override
            public void done(ParseObject object, ParseException e) {
               setLastException(ba, e);
               ba.raiseEventFromDifferentThread(getObject(), null, 0, EventName.toLowerCase(BA.cul) + "_doneget",
                     true,
                     new Object[] {e == null, object, TaskId});
            }
            
         });
      }
      /**
       * Finds all objects matching the query.
       *DoneFind event will be raised when the operation completes.
       */
      public void Find(final BA ba, final String EventName, final int TaskId) {
         getObject().findInBackground( new FindCallback() {
            @Override
            public void done(List<ParseObject> objects, ParseException e) {
               setLastException(ba, e);
               anywheresoftware.b4a.objects.collections.List l = new anywheresoftware.b4a.objects.collections.List();
               if (objects != null) {
                  l.Initialize();
                  l.getObject().addAll(objects);
               }
               ba.raiseEventFromDifferentThread(getObject(), null, 0, EventName.toLowerCase(BA.cul) + "_donefind", 
                     true,
                     new Object[] {e == null, l, TaskId});
            }
         });
      }
      /**
       * Counts the number of objects matching the query.
       *DoneCount event will be raised when the operation completes.
       */
      public void Count(final BA ba, final String EventName, final int TaskId) {
         getObject().countInBackground(new CountCallback() {
            @Override
            public void done(int count, ParseException e) {
               setLastException(ba, e);
               ba.raiseEventFromDifferentThread(getObject(), null, 0, EventName.toLowerCase(BA.cul) + "_donecount", 
                     true,
                     new Object[] {e == null, count, TaskId});
            }
         });
      }
      /**
       * Sets the query order by.
       */
      public void OrderBy (String Key, boolean Ascending) {
         if (Ascending)
            getObject().orderByAscending(Key);
         else
            getObject().orderByDescending(Key);
      }
      /**
       * Adds a condition to the query.
       */
      public ParseQueryWrapper WhereEqualTo(String Key, Object Value) {
         getObject().whereEqualTo(Key, Value);
         return this;
      }
      /**
       * Adds a condition to the query.
       */
      public ParseQueryWrapper WhereGreaterThan(String Key, Object Value) {
         getObject().whereGreaterThan(Key, Value);
         return this;
      }
      /**
       * Adds a condition to the query.
       */
      public ParseQueryWrapper WhereLessThan(String Key, Object Value) {
         getObject().whereLessThan(Key, Value);
         return this;
      }
      /**
       * Adds a condition to the query.
       */
      public ParseQueryWrapper WhereNotEqualTo(String Key, Object Value) {
         getObject().whereNotEqualTo(Key, Value);
         return this;
      }
      /**
       * Limits the number of results. Pass -1 to retrieve all items.
       */
      public void setLimit(int v) {
         getObject().setLimit(v);
      }
      
   }
   
}
 

bluedude

Well-Known Member
Licensed User
Longtime User
Parse push notifications

Erel,

Any chance your are going to support the Push notifications of the parse SDK?
 

vb1992

Well-Known Member
Licensed User
Longtime User
Does XmlSax and This Library play nice together?
I am getting Force Closes


could the libraries be colliding with the word "Parse?"


B4X:
   Dim Parse As Parse
   Parse.Initialize(AppId, ClientKey)
   WriteToDB("START_PROGRAM")
   


Sub HttpClient1_ResponseSuccess (Response As HttpResponse, TaskId As Int)
   

Dim Result As InputStream
   Result = Response.GetInputStream
   MySax.Parse(Result, "Yahoo")
   Result.Close
   
   
   
End Sub
 
Top