I use the Parse.com Cloud service in my Android app to sync data between devices.
I use the app mainly offline and use the local data store.
There is one class called Point that has a unique number as identifier I want to display. So when working offline I want to create a Point as draft (with a draft text as number) and when synchronizing I want it to get the real number that is unique over all the devices.
How would I set the number when saving? I was thinking about adding a WebHook in the cloud when saving the Point and giving it a unique number and then in my app use
newPoint.saveEventually(new SaveCallback() {
public void done(ParseException e) {
//query for the number
}
});
to query the point from the cloud to get the number after it has been saved. But this seems kind of too complicated for such a simple requirement. And I am not sure if the SaveCallback() is always triggered when saving it.
I would recommend using an afterSave trigger on the Point class to set the unique identifier when the object is newly created. Then, as you've mentioned, you'll need to fetch the value before displaying it.
Here's what the cloud code could look like:
// Assign the Point a unique identifier on creation
Parse.Cloud.afterSave("Point", function(request) {
// Check if the Point is new
if (!(request.object.existed())) {
// Get the unique identifier
var uniqueIdentifier = ...
// Set the unique identifier
request.object.set('uniqueIdentifier', uniqueIdentifier);
}
});
One important bit of information to keep in mind about using saveEventually with SaveCallback() is:
The callback will only be called if the operation completes within the
current app lifecycle. If the app is closed, the callback can't be
called, even if the save eventually is completed.
Source: Hector Ramos
If the unique identifier should be immediately displayed in the app or if the callback needs to be handled consistently, it would probably be best to use saveInBackground rather than saveEventually.
Another option would be to dynamically change the callback depending on network availability and/or offline settings. For example, if the offline mode is used anytime when the cell signal or wifi is unavailable, then network reachability could be used to check for a network and then use saveInBackground or saveEventually as appropriate.
Update
OP ended up using this code:
Parse.Cloud.beforeSave("Point", function(request, response) {
if (!(request.object.existed())) {
var query = new Parse.Query("Point");
query.addDescending("uniqueIdentifier");
query.first({
success: function(result) {
var maxId = result.get("uniqueIdentifier");
request.object.set("uniqueIdentifier", maxId + 1);
},
error: function() {
}
});
}
response.success();
});
Related
I want to setup 2 Firebase in 1 App, but with difference persistence.
One is enable, and the second is disable.
Please inform me how to set it up.
I take code from link below,
Multiple Firebase projects in one app
but it didn't explain,
how to setup persistence for the second Firebase.
I want to enable persistence for 1st Firebase.
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
And disable persistence for 2nd Firebase.
FirebaseDatabase.getInstance().setPersistenceEnabled(false);
As we see, that getInstance is static method,
how do we know that,
the returned FirebaseDatabase instance,
will belong to 1st or 2nd Firebase.
private void initSecondFirebaseAcct()
{
FirebaseOptions options = new FirebaseOptions.Builder()
.setApplicationId("<your application id>")
.setApiKey("<your api key>")
.setDatabaseUrl("<your DB url that ends in 'firebaseio.com/' ")
.build();
try
{
FirebaseApp.initializeApp(this, options, "<database tag>");
}catch (Exception e){
Log.d("Firebase error", "App already exists");
}
mMySecondApp = FirebaseApp.getInstance("<database tag>");
mSecondDBRef = FirebaseDatabase.getInstance(mMySecondApp).getReference();
}
The way to make sure you are referencing the first or second Firebase app is to provide the specific FirebaseApp instance as a parameter to:
FireDatabase.getInstance(<app instance here>).setPersistenceEnabled().
If you use FirebaseDatabase.getInstance() you will receive the default instance, the first database app. So just provide the second instance as a parameter and you'll be good to go.
I am using Azure Cosmos DB. I have created a simple trigger in Azure Portal as follows:
var context = getContext();
var request = context.getRequest();
// item to be created in the current operation
var itemToCreate = request.getBody();
itemToCreate["address"] = "test";
// update the item that will be created
request.setBody(itemToCreate);
Unfortunately this trigger is not being triggered when I insert new documents. I have also tried to set the "Trigger Type" to "Post". Am I missing anything?
Great question! I always thought that triggers would run automatically :).
I believe the triggers are not run automatically whenever a document is inserted. What you would need to do is specify the trigger that you want to run when you're creating the document.
What you need to do is register the trigger by passing the trigger name as the request option when sending create document request.
For example, see the code here: https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-use-stored-procedures-triggers-udfs#pre-triggers (copied below as well). Notice the use of PreTriggerInclude in RequestOptions:
dynamic newItem = new
{
category = "Personal",
name = "Groceries",
description = "Pick up strawberries",
isComplete = false
};
Uri containerUri = UriFactory.CreateDocumentCollectionUri("myDatabase", "myContainer");
RequestOptions requestOptions = new RequestOptions { PreTriggerInclude = new List<string> { "trgPreValidateToDoItemTimestamp" } };
await client.CreateDocumentAsync(containerUri, newItem, requestOptions);
Firing triggers automatically in relational databases makes sense since there is schema in
the database, you kind of know what to handle in a trigger logic.
In NoSQL database, since there is no schema, you may end up with a large script to handle all kind of exceptions.
Large script in triggers means higher bills in Cloud. Making triggers automatic can make many customers bill really high specially in IOT solutions.
You can read about Azure Cosmos DB pre/post triggers in my post.
https://h-savran.blogspot.com/2020/03/create-triggers.html
The only way according to the answers from #Guarav Mantri and #Hasan Savaran is to specify the trigger while creating the item through the API. I have managed to do it in Java Azure SDK like that:
RequestOptions options = new RequestOptions();
options.setPreTriggerInclude(Arrays.asList("pre"));
documentClient.createDocument(
collectionLink(),
documentToAdd,
options,
true);
Although I am not happy with this solution because for instance the trigger will not be triggered when creating the item via Portal.
I started to learn Android few days back and so far I am done with implementing Login Activity, Main Activity which extends abstract Base Activity.
Nav Bar item when clicked opens xml from Fragments.
I have a question about the token that I receive after successful login. This token is being used with each request to get data after successful login. Should I save the token in sqlite database securely or I should make a public property in Main Activity? Main Activity will always remain in memory as this will open fragments.
I can suggest 3 options:
1) you can save the token to the file, something like this:
public static void saveToken(Context ctx, String fileName, Object token) {
if (token == null) {
ctx.deleteFile(fileName);
} else {
ObjectOutputStream out = null;
try {
FileOutputStream fout = ctx.openFileOutput(fileName, 0);
out = new ObjectOutputStream(fout);
out.writeObject(token);
fout.getFD().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Make sure object token implements java.io.Serializable interface.
Usage before API level 24:
saveToken(appContext, someFileName, someTokenObject);
Usage with API level 24 and higher:
saveToken(appContext.createDeviceProtectedStorageContext(), someFileName, someTokenObject);
2) Use SQLCipher library for encrypted database.
3) You can encrypt your token using keystore system https://developer.android.com/training/articles/keystore.html
Use SharedPreferences and make sure you are using Context.MODE_PRIVATE this way only your app can access the data. SharedPreferences is a persistent store
e.g.
SharedPreferences prefs = context.getPreferences(Context.MODE_PRIVATE);
prefs.edit().putString("token", token).apply();
token = prefs.getString("token");
Why not to use SQLite:
SQLite is a database and is targeted at tabular data, a single token does not fit this use case.
Why not store in the main activity:
The main activity will not be around for the lifetime of the application install, it can be cleaned up by the OS at any time. It is not a persistent data store.
Should I save the token in sqlite database securely or I should make a public property in Main Activity? Main Activity will always remain in memory as this will open fragments.
The Official Android documentation already answers your question in the section on called "Best practices for security and privacy". It gives the following statement:
If you have access to user data and can avoid storing or transmitting it, don't store or transmit the data
In other words, if you can avoid persisting then don't persist it.
You mentioned "public property" in your question which makes me wonder if the concept of visibility modifiers is not yet clear. The Java public and private modifiers are for controlling access to the members of your class. They have nothing to do with security as per this answer here.
If you do persist the token in memory, as a public field or otherwise, you may reduce your exposure slightly by storing the token in a char[] rather than a String. That also is detailed in this canonical answer.
Finally, if you do have to store the token, the sqlite database is not the correct place to do it. Instead, you should use the provided KeyStore which will make for more difficult extraction of the token in the case that the device is compromised. The link to the documentation above is complete with code examples. If this proves too difficult to use, there are some wrappers around it including Scytale.
1) Store the token value within the base application singleton (where your application must be an instance of BaseApplication)
public class BaseApplication extends Application {
// token
private String token = null;
public String getToken() {return this.token;}
public void setToken(String token) {this.token = token;}
}
With the implementation above you will be able to set and get the token value from any activity/fragment. However the value is not persistent and it will be lost once the application ends.
Remark: If you are using the token for REST api access then you can store the token in the background service instance using a similar solution as above.
2) Use SharedPreferences - this is recommended way in case you want to store the token's value between application's runs.
Please see the answer from #Ryan.
You can use SharedPreferences to store token.it is available over application.
You can store it in Shared Preference as this one is token.
Now coming to the part of Security You can obviously use encryption for the shared preference.
There are already lots of open items available you can use below library for example
https://github.com/ophio/secure-preferences
Regarding keys that are in your java file to encrypt, You need to be sure you are applying proguard before you upload it to playstore.
In that manner now your token is fully secure with shared preferences.
In order to save it in sqlite than by decoding or root access your db file can also be accessed same as preferences. Regarding clear data from setting I think it will delete your sqlite data as well. Not sure about this though.
I hope it will help you out.
Better to use Sqlite or Realm. And store in Application memory and not in external memory. As for data residing in application memory we don't need to worry much about security. Saving in MainActivity is not a good solution, as once application closes, this will get cleared.
Storing in Shared Preference is also an option. But if user clears the cache from setting's this value will also get cleared. Realm Android Reference Link
I am trying to implement a solution for storing reference data in the database of my app.
The data is initially stored as JSON files, which I will need to sync from a server on each launch. I have a local copy of the files baked into the app. Each launch I have to check shared preferences for a version. And if it not present, I assume it is the first launch. So i need to read in the files, write the files to the database and fire on completed when that is done. The first screen expects this data to be in the database, so I will be not showing the UI for that screen in this scenario, until the process completes.
However in the future the network call to sync these files can happen asynchronously so want to be able to fire on completed on my observable as soon as i see the shared prefs have a version number and then ill kick of the update completely asynchronously
How can i set up a stream to represent this. I think the stream type will probably be void and i will just fire onCompleted/error as the subscriber doesnt care about the data, only what the process is complete
You could do something like this:
updateChecker.hasUpdates()
.flatMap(hasUpdates -> {
if (hasUpdates) {
return dataUpdater.update();
}
return Observable.just(false);
})
Assuming that
class UpdateChecker {
public Observable<Boolean> hasUpdates() {
return Observable.just(true); // Replace by API call
}
}
class DataUpdater {
public Observable<Boolean> update() {
// update the database here
return Observable.just(true);
}
}
I am currently trying to enhance the To-Do List tutorial from Play framework's website. I've added a login form, (and of course a User class acting as a model), and it works perfectly well. I also made a small "dashboard" in which the logged user is able to change his password and his email address. But when I submit the form, I get a "Datasource user is null ?" error (RuntimeException).
The whole problem came when I wanted to restrict the edition possibilities (I first used a whole User form, which is quite over the top (User do not need to edit their ID). So I made a small inner class in my Application file called UpdateUser which gathers the required informations, just as I did for the login system.
Searching this error gave me many results but people saw their problem fixed by uncommenting the ebean.default line in the conf file, which I already did.
Here is the method I used to update user's informations :
Firstly, I made a small class in my Application to hold the form (exactly like I did for the login thing).
Then I made a update function as found here in my user class :
public static String update(String id, User newuser) {
newuser.update(id);
return("Your profile has been updated");
}
which returns the String that will be in my flash and which is according to my compiler the problem function.
This function is called in my Application like this :
public static Result updateUser(String id)
{
Form<UpdateUser> filledForm = updateUserForm.bindFromRequest();
System.out.println("Updated User : "+filledForm.get().id);
if(filledForm.hasErrors())
{
flash("success","Error while updating");
}else{
User user = new User(filledForm.get().id, filledForm.get().email, User.find.byId(filledForm.get().id).name, User.find.byId(filledForm.get().id).surname, filledForm.get().password);
flash("success", User.update(id,user));
}
return redirect(routes.Application.dashboard());
}
I tracked the data in the Form and it is not null (I mean I can get everything from the form). But I wonder if I have to create another ebean or if it's my function which is wrong. I also wonder if it's not my User creation that fail. Or maybe I should take the updateUser function and put it in my inner UpdateUser class ?
I have to admit that I worked on that all of yesterday (and probably today too), and I can't find anything on the internet except the ebean.default thing.
------EDIT
I continued to search, so here's what I tried :
1) Getting the form result into an instance of UpdateUser in order to use it
2) Use this instance instead of getting the data from the form
But it failed too. What's really weird is that I've added a toString() method for User class, and calling it on the user I want to insert (as an update) gives me the full stuff. I think it must be a configuration problem, but I can't see it.
Another thing : when I come to the error page and when I try to come back to the application by modifying the URL, I am disconnected. Is it my ebean that closes himself ?
Last edit for the day, I'm getting tired of this. I tried to delay the action (i.e. making it happen after the user has logged out), the new data are correctly saved but I still get the error when calling the update function.
Alright, I finally found it, but totally by chance.
I just had to write this :
public static String update(String id, User user) {
user.update((Object)id);
return ("Your profile has been updated");
}
Because for some reason that I don't really understand, The id String needs to be cast to Object. The rest of the code was correct. But apparently, when using update() on this particular case (is it because my id is a String or because I get the informations from another class before using it as my Model), the parameter which is supposed to be a String (even in the documentation) HAS to be cast.
That's it.