I want to create a simple CRUD application to test out the data handling capabilities of the Blackberry.
How do I create a simple save function?
In this example I'm storing a vector in the persistent store.
You have to come up with a store ID, which should be of type long. I usually create this by concating the fully qualified Application's Class name to some string that makes it unique with in my application.
//class Fields...
//Use the application fully qualified name so that you don't have store collisions.
static String ApplicaitonID = Application.getApplication().getClass().getName();
static String STORE_NAME = "myTestStore_V1";
long storeId = StringUtilities.stringHashToLong( ApplicationID + STORE_NAME );
private static PersistentObject myStoredObject;
private static ContentProtectedVector myObjects;
//End class fields.
Example of loading a Vector from the store:
myStoredObject = PersistentStore.getPersistentObject( storeId );
myObjects = (ContentProtectedVector) myStoredObject.getContents();
//Print the number of objects in storeage:
System.out.println( myObjects.size() );
//Insert an element and update the store on "disk"...
myObjects.addElement( "New String" );
myStoredObject.setContents(myObjects);
myStoredObject.commit();
Example of initializing this store and saving it to disk for the first time:
myStoredObject = PersistentStore.getPersistentObject( storeId );
myObjects = (ContentProtectedVector) myStoredObject.getContents();
if(myObjects == null)
myObjects = new ContentProtectedVector();
myStoredObject.setContents(myObjects);
myStoredObject.commit();
If you want to commit changes (aka save changes to disk), you need to repeat the bottom two lines. setContents(OBJ); and Commit().
You can store the following without having to do anything special:
java.lang.Boolean
java.lang.Byte
java.lang.Character
java.lang.Integer
java.lang.Long
java.lang.Object
java.lang.Short
java.lang.String
java.util.Vector
java.util.Hashtable
#see : http://docs.blackberry.com/en/developers/deliverables/17952/Storing_objects_persistently_1219782_11.jsp
To store your own Classes, they (and all sub classes) have to implement the "Persistable" interface. I recommend that you do this, as these stores get cleaned up automatically when your application is uninstalled. This is because the OS cleans stored objects up, when "any" referenced classname in the store no longer has an application associated with it. So if your store is only using Strings, it's never going to get cleaned up.
Related
I've been following my new journey into learning Solidity. Now I'm into a structs + Data locations course, and I came to a situation when I didn't use the exact same example as the instructor did, both works. I would like to know which one is technically more correct.
Concerning the way the instructor did, I understand that if that data variable already exists, filled with data, and we're using it on a Storage, that would be understandable but for the Memory case, I still don't get the meaning of it.
Here are the two exmples:
Mine:
struct PERSON {
uint256 id;
string name;
}
PERSON public personList;
function updateNewPerson(uint256 _index, string memory _name) public {
PERSON memory newUpdatedPerson;
newUpdatedPerson.name = _name;
personList[_index] = newUpdatedPerson;
}
Instructor code:
struct PERSON {
uint256 id;
string name;
}
PERSON public personList;
function updateNewPerson(uint256 _index, string memory _name) public {
PERSON memory newUpdatedPerson = personList[index];
newUpdatedPerson.name = _name;
personList[_index] = newUpdatedPerson;
}
This is the same example with Storage data location I'm reffering to:
function updateStoragePerson(uint256 _index, string memory _name) public {
PERSON storage newUpdatedPerson = personList[_index];
newUpdatedPerson.name = _name;
}
I'm trying to figure out the is there's any difference there and i think I'm starting to uderstand it, and please correct me if I'm wrong.
So in my example I'm basically just passing the new user insert new value, which is in this case _name, then when giving it back to the array handing it to its position through the index array.
When on the instructor example, he's passing through the array index case content, which is id and name, then insering the new name value from the function before passing back the data to the array, and in this case id and _name are identical.
What I can see is that, in your code, when you create a newUpdatedPerson, you are creating an empty variable of type PERSON, and then you only fill it with the name, whereas your instructor takes the original value from a person which already exists and then updates its value. This will result in your newUpdatedPerson in your personList to update its name but its id will become empty.
The newUpdatedPerson will be stored in personList as copies from storage to local storage actually copy a reference to the storage so any update on newUpdatedPerson will result in an update to personList.
Assignments from storage to a local storage variable also only assign a reference.
I hope you find this information helpful :)
State variables are storage by default (values are stored in the blockchain).
Local variables in functions are memory by default (values are stored temporarily in memory).
Structs are storage by default (values are stored in the blockchain).
I explained how memory and storage type behave differently on this stackoverflow post
I'm trying to implement a settings module in my app which should contain information about current state of application. For example, if the user opens some file I need to store the file name. Since I'm still learning F# I want to do it as functional a possible.
I know I should create a new value everytime I change something, but where do I store this value? It should be a singleton and since it's immutable I struggle with the solution.
How do I implement such "global variable"? Does it even play well within functional approach?
This works just as it would within a function, with let mutable (used inside a module):
let mutable a = 4
a // gets a
a <- 6 // sets a
Or, you could use a mutable object as a static member (this example uses a mutable reference cell):
type Settings =
static member Filename = ref ""
Settings.Filename := "OpenMe.txt"
Global variables may be necessary sometimes, and this could be a viable use case, but they are considered dangerous. Values that change and influence a large portion of the program can make things rather unpredictable.
That said, in cases like yours, a single global variable can be a good solution. It could hold a record with the individual settings. I'd pay attention that any operations changing the global variable happen only when the program is in a well-defined state (i.e. not in the middle of a complicated operation) and guarantee that the variable's new value is sound.
Example:
type StateVariables =
{ Filename : string
Opened : int }
module State =
let mutable private cur = { Filename = ""; Opened = 0 }
let get () = cur
let openFile name =
// ...
cur <- { cur with Filename = name; Opened = cur.Opened + 1 }
You can store a global variable in a module:
module Settings =
let mutable FileName = ""
open Settings
FileName <- "foo"
We are using Tapestry 5.4-beta-4. My problem is:
I need to keep files with locale data in an external location and under different file name then tapestry usual app.properties or pageName_locale.properties. Those files pool messages that should be then used on all pages as required (so no tapestry usual one_page-one_message_file). The files are retrieved and loaded into tapestry during application startup. Currently i am doing it like this:
#Contribute(ComponentMessagesSource.class)
public void contributeComponentMessagesSource(OrderedConfiguration<Resource> configuration, List<String> localeFiles, List<String> languages) {
for(String language: languages){
for(String fileName : localeFiles){
String localeFileName = fileName + "_" + language + ".properties";
Resource resource = new Resource(localeFileName );
configuration.add(localeFileName, resource, "before:AppCatalog");
}
}
}
The above code works in that the message object injected into pages is populated with all the messages. Unfortunatly these are only the messages that are in the default ( first on the tapestry.supported-locales list) locale. This never changes.
We want the locale to be set to the browser locale, send to the service in the header. This works for those messages passed to tapestry in the traditional way (through app.properties) but not for those set in the above code. Actually, if the browser language changes, the Messages object changes too but only those keys that were in the app.properties are assigned new values. Keys that were from external files always have the default values.
My guess is that tapestry doesn't know which keys from Messages object it should refresh (the keys from external files ale not beeing linked to any page).
Is there some way that this could be solved with us keeping the current file structure?
I think the problem is that you add the language (locale) to the file name that you contribute to ComponentMessagesSource.
For example if you contribute
example_de.properties
Tapestry tries to load
example_de_<locale>.properties
If that file does not exist, it will fall back to the original file (i.e. example_de.properties).
Instead you should contribute
example.properties
and Tapestry will add the language to the file name automatically (see MessagesSourceImpl.findBundleProperties() for actual implementation).
#Contribute(ComponentMessagesSource.class)
public void contributeComponentMessagesSource(OrderedConfiguration<Resource> configuration, List<String> localeFiles, List<String> languages) {
for(String language: languages){
for(String fileName : localeFiles){
String localeFileName = fileName + ".properties";
Resource resource = new Resource(localeFileName );
configuration.add(localeFileName, resource, "before:AppCatalog");
}
}
}
I'm experimenting with BreezeJS with Web API using the BreezeControllerAttribute. How should calculated properties on an entity be exposed? The only way I've found to do this reliably is to create an intermediate DTO that inherits from the entity or use a projection. Normally I would use a readonly property for this scenario, but those appear to be ignored.
When Breeze maps JSON property data to entities, it ignores properties that it does not recognize. That's why your server class's calculated property data are discarded even though you see them in the JSON on the wire.
Fortunately, you can teach Breeze to recognize the property by registering it as an unmapped property. I'll show you how. Let me give some background first.
Background
Your calculated property would be "known" to the Breeze client had it been a property calculated by the database. Database-backed properties (regular and calculated) are picked up in metadata as mapped properties.
But in your case (if I understand correctly) the property is defined in the logic of the server-side class, not in the database. Therefore it is not among the mapped properties in metadata. It is hidden from metadata. It is an unmapped instance property.
I assume you're not hiding it from the serializer. If you look at the network traffic for a query of the class, you can see your calculated property data arriving at the client. The problem is that Breeze is ignoring it when it "materializes" entities from these query results.
Solution with example
The solution is to register the calculated property in the MetadataStore.
I modified the entityExtensionTests.js of the DocCode sample to include this scenario; you can get that code from GitHub or wait for the next Breeze release.
Or just follow along with the code below, starting with this snippet from the Employee class in NorthwindModel.cs:
// Unmapped, server-side calculated property
[NotMapped] // Hidden from Entity Framework; still serialized to the client
public string FullName {
get { return LastName +
(String.IsNullOrWhiteSpace(FirstName)? "" : (", " + FirstName)); }
}
And here is the automated test in entityExtensionTests.js
test("unmapped property can be set by a calculated property of the server class", 2,
function () {
var store = cloneModuleMetadataStore(); // clones the Northwind MetadataStore
// custom Employee constructor
var employeeCtor = function () {
//'Fullname' is a server-side calculated property of the Employee class
// This unmapped property will be empty for new entities
// but will be set for existing entities during query materialization
this.FullName = "";
};
// register the custom constructor
store.registerEntityTypeCtor("Employee", employeeCtor);
var fullProp = store.getEntityType('Employee').getProperty('FullName');
ok(fullProp && fullProp.isUnmapped,
"'FullName' should be an unmapped property after registration");
var em = newEm(store); // helper creates a manager using this MetadataStore
var query = EntityQuery.from('Employees').using(em);
stop(); // going async
query.execute().then(success).fail(handleFail).fin(start);
function success(data) {
var first = data.results[0];
var full = first.FullName();
// passing test confirms that the FulllName property has a value
ok(full, "queried 'Employee' should have a fullname ('Last, First'); it is "+full);
}
});
What you need to do is in this small part of the test example:
var yourTypeCtor = function () {
this.calculatedProperty = ""; // "" or instance of whatever type is is supposed to be
};
// register your custom constructor
store.registerEntityTypeCtor("YourType", yourTypeCtor);
I have a BlackBerry application that starts (App load) with a Registration screen when the App is first installed. Later, the App will load with the home screen. Registration screen only appears on first load. I am achieving this by storing a boolean value in PersistentStore. If the value exists, then Registration screen will not appear.
PersistentStoreHelper.persistentHashtable.put("flagged",Boolean.TRUE);
PersistentStoreHelper.persistentObject.commit();
UiApplication.getUiApplication().pushScreen(new MyScreen());
I am aware of the fact that in order to delete the Persistent Store on deleting/uninstalling the App, I have to make the Hashtable a subclass of my own and therefore I have declared the Hashtable in a separate class:
public class PersistentStoreHelper extends Hashtable implements Persistable{
public static PersistentObject persistentObject;
public static final long KEY = 0x9df9f961bc6d6daL;
public static Hashtable persistentHashtable;
}
However this has not helped and the boolean value of flag is not cleared from PersistentStore. Please advice.
EDIT: When I change the above PersistentStoreHelper class to
public static PersistentObject persistentObject =
PersistentStore.getPersistentObject(KEY);
and remove
PersistentStoreHelper.persistentObject =
PersistentStore.getPersistentObject(PersistentStoreHelper.KEY);
from class B where boolean value is being saved, I observe that the boolean value is removed every time the App is closed. This should not happen and the value should only be removed in case the App is deleted/uninstalled. Any pointers?
The way this works is that the BlackBerry OS looks at the objects you are storing in the PersistentStore. If it recognizes that those objects can only be used by your app, then it will delete them when you uninstall the app. However, if the classes of the stored objects are classes that are used by other apps, then your data will not be deleted.
You have declared your helper class like this:
public class PersistentStoreHelper extends Hashtable implements Persistable{
but the helper class is not what is being stored. Your helper class is just a helper, that stores other things for you. In your case, it is storing this:
public static Hashtable persistentHashtable;
but, that object is of type java.util.Hashtable, which is a class used by many apps. So, it won't be deleted when you uninstall your app. What you should do is something like this:
public class PersistentStoreHelper implements Persistable { // so inner class = Persistable
public static PersistentObject persistentObject;
public static final long KEY = 0x9df9f961bc6d6daL;
/**
* persistentHashtable is now an instance of a class that
* only exists in your app
*/
public static MyAppsHashtable persistentHashtable;
private class MyAppsHashtable extends Hashtable implements Persistable {
// don't need anything else ... the declaration does it all!
}
}
I can't see it here, but I'm assuming that somewhere you have this code:
persistentObject = PersistentStore.getPersistentObject(KEY);
and then when you want to save the data back to the store, you're doing something like this;
persistentHashtable.put("SomeKey", someNewData);
persistentObject.setContents(persistentHashtable);
persistentObject.commit();
just adding data to the persistentHashtable doesn't save it (permanently). Hopefully, you already had that part somewhere.
Note: if you make these changes, don't expect this line of code to work, the next time you run your app:
persistentHashtable = (MyAppsHashtable)persistentObject.getContents();
because the last version of your code did not use the MyAppsHashtable class, so the loaded data won't be of that type. This is one reason that it's important to get this right the first time. In general, I always wind up saving data in the PersistentStore that's contained in one top level Hashtable subclass, that implements Persistable. I may later change what goes in it, but I won't ever change the signature of that top-level storage object. Hopefully, you haven't released your app already.
Update: In response to your comment/question below:
if (PersistentStoreHelper.persistentObject.getContents() == null) {
PersistentStoreHelper.persistentHashtable = new MyAppsHashtable();
PersistentStoreHelper.persistentObject.setContents(PersistentStoreHelper.persist‌entHashtable);
} else {
PersistentStoreHelper.persistentHashtable =
(MyAppsHashtable)PersistentStoreHelper.persistentObject.getContents();
}