The Database - struct-by-lightning/wpi-suite GitHub Wiki

Introduction

The Database currently used by the core of the project is database for objects (db4o). All databases that are used by the core must follow the following guidelines from the data interface. This interface is what all modules and entity managers are programmed against to both store and retrieve objects from the database.

Many of the implementations have two options, one with a project and one without a project. Methods that take in a project will only alter items associated with that project, whereas those without a project will affect ALL matching items in the database.

Implementation

The function prototypes for the data methods are:

public <T> boolean save(T aModel);

public <T> boolean save(T aModel, Project aProject);

public List<Model> retrieve(final Class anObjectQueried, String aFieldName, final Object theGivenValue) throws WPISuiteException;

public List<Model> retrieve(final Class anObjectQueried, String aFieldName, final Object theGivenValue, final Project theProject) throws WPISuiteException;

public <T> T delete(T aTNG);

public void update(final Class anObjectToBeModified, String fieldName, Object uniqueID, String changeField, Object changeValue) throws WPISuiteException;

public <T> List<T> retrieveAll(T aSample);

public <T> List<Model> retrieveAll(T aSample, Project aProject);

public <T> List<T> deleteAll(T aSample);

public <T> List<Model> deleteAll(T aSample, Project aProject);

public List<Model> andRetrieve(final Class anObjectQueried, String[] aFieldNameList, final List<Object> theGivenValueList) throws WPISuiteException, IllegalArgumentException, IllegalAccessException, InvocationTargetException;

public List<Model> andRetrieve(final Class anObjectQueried, String[] aFieldNameList, final List<Object> theGivenValueList, Project aProject) throws WPISuiteException, IllegalArgumentException, IllegalAccessException, InvocationTargetException;

public List<Model> orRetrieve(final Class anObjectQueried, String[] aFieldNameList, final List<Object> theGivenValueList) throws WPISuiteException, IllegalAccessException, InvocationTargetException;

public List<Model> orRetrieve(final Class anObjectQueried, String[] aFieldNameList, final List<Object> theGivenValueList, Project aProject) throws WPISuiteException, IllegalAccessException, InvocationTargetException;

public List<Model> complexRetrieve(final Class andanObjectQueried, String[] andFieldNameList, final List<Object> andGivenValueList, final Class orAnObjectQueried, String[] orFieldNameList, final List<Object> orGivenValueList) throws WPISuiteException, IllegalArgumentException, IllegalAccessException, InvocationTargetException;

public List<Model> complexRetrieve(final Class andanObjectQueried, String[] andFieldNameList, final List<Object> andGivenValueList, final Class orAnObjectQueried, String[] orFieldNameList, final List<Object> orGivenValueList, Project aProject) throws WPISuiteException, IllegalArgumentException, IllegalAccessException, InvocationTargetException;

The implementation of these methods is specific to each data. The db4o usage is explained below.

Server Configuration

In order to ensure consistency across threads and different database access times, some settings are needed in order to ensure that all objects are stored the same way and with only select fields. To do so a ServerConfiguration is used. The ServerConfiguration stores information about how the db4o client server is set up to store objects.

The first setting is a reflection setting in place with the line: config.common().reflectWith(new JdkReflector(Thread.currentThread().getContextClassLoader()));

This config setting tells the server that it should use the current thread's Class context when storing and pulling items out of the database. This will ensure that all models that are retrieved and stored into the database have the same signature. The signature is a part of the reflection process utilized by db4o to ensure that the correct object is being stored and retrieved since two objects could have the same field values but be different objects. The thread's context class loader is one of the main ways db4o differentiates the differences between objects.

The second setting is security feature for User objects in place with the line: config.common().objectClass(User.class).storeTransientFields(true);

User objects contain a password that need controlled access. We do not want the user's password being passed around from the client to the server when this is not necessary in order to prevent the user's password from leaking, even if hashed.

To accomplish this, a user's password is a transient field, meaning that it will not be serialized at all, and will be left out when the User is passed along to and from the entity manager. However we still need the password to be saved in the database so it can be checked against when authenticating a User. This configuration setting is a workaround for db4o that it needs to store this field, even though it will not be serializing the password field when it deals with users.

Save

The save function stores the given Model into the database.

When Save is called with a valid project, the Model's setProject method is called to associate the Model with the given project, and then saved into the database. This model can then be searched for by project by the other available methods.

The method returns true if the Model was saved correctly.

Retrieve

For this function to work you need to have a getter that takes zero arguments, and has the name convention of get + the given fieldName (ie getID for the field id from an object). The value can be of any type, provided that there is a .equals method for it. To query by something else, like by a user object or defect object, you must create a .equals function for it, that will return true if and only if all the fields of the object have the same values. To get a class to give as anObjectQueried you get an object of the desired type and call .getClass(). For aFieldName, this should be the suffix of the getter (ie for getID you would make this field be "ID"). If a project is provided then all the returned models will be a part of that project.

Returns all models of the given class with the given value for the given field. If a project is specified then all models will belong to that project, otherwise the models will come from all projects. The models come back as a list that the client module can then filter through.

Delete

Deletes the given object from the database, returns the object deleted.

For db4o the native query by example is used to select the exact object from the database, which is then deleted. Once an object is deleted from the database it cannot be recovered.

Update

Updates the given field in every object which has the uniqueID value in a specific project.

anObjectToBeModified - Class of object to be updated fieldName - Field the object will be identified by uniqueID - Value of fieldName that the object will be identified by changeField - Field whose value will be changed changeValue - Value that changeField will be changed to aProject - The project the object to be updated belongs to (optional)

For this function to work you need to have a getter that takes zero arguments, and has the name convention of get + the given fieldName (ie getID for the field id from an object). For this function to work you need to have a setter that takes one argument, the changeValue, and has the name convention of set + the given fieldName (ie getID for the field id from an object).

This function will call retrieve to get the objects of the given class with the given uniqueID value for the given fieldName. It will then run set"changeField"(changeValue) on all of the retrieved objects. It then saves all of the updates objects back into the database.

RetrieveAll

Retrieves all objects of the given Class in a given Project, returns a list of all of the objects of the given class. If a project is provided, then all objects returned will be a part of the given project.

aSample - an object of the class we want to retrieve All of aProject - Project to search in for the objects (optional)

This function calls the db4o query by example where a sample object is given to the database and then the database will return all objects of the same type. When a project is provided this list of objects is then iterated through checking each object's project against the given project.

DeleteAll

Deletes all objects of the given Class (in a given Project if provided), returns a list of all of the objects of the given class which were deleted aSample - an object of the class we want to retrieve All of aProject - Project to search in for the objects (optional)

This function retrieves all of the given objects and then deletes them one by one from the database.

AndRetrieve

/**
 * Retrieves objects which match all of the given fields to all of the given values
 * @param anObjectQueried - Class of the object to be queried
 * @param aFieldName - Array of names of the Field to check in order
 * @param theGivenValueList - Array of values the field should equal in order
 * @param aProject - Project that all returned models must belong to (optional)
 * @return A List of Models containing all of the models that match all of the given fields
 * @throws WPISuiteException
 */

Retrieves objects which match all of the given fields to all of the given values. It returns a list of the objects returned. aFieldName is an array of the string names of all the fields you want to search. If you want to search by name, then there should be a field "name", which has an associated getter "getName". Every field named should be in the class queried. The given values in theGivenValueList must appear in the same order as the fields they belong to appear in the aFieldName list.

OrRetrieve

/**
 * Retrieves objects which match one of the given fields to one of the given values
 * @param anObjectQueried - Class of the object to be queried
 * @param aFieldName - Array of names of the Field to check in order
 * @param theGivenValueList - Array of values the field should equal in order
 * @param aProject - Project that all returned models must belong to
 * @return A List of Models containing all of the models that match one of the given fields
 * @throws WPISuiteException
 */

Retrieves objects which match one of the given fields to one of the given values. It returns a list of the objects returned. aFieldName is an array of the string names of all the fields you want to search. If you want to search by name, then there should be a field "name", which has an associated getter "getName". Every field named should be in the class queried. The given values in theGivenValueList must appear in the same order as the fields they belong to appear in the aFieldName list.

ComplexRetrieve

/**
 * Retrieves objects which match all of the given "and" fields to all of the given "and" values AND 
 * which match one of the given "or" fields to one of the given "or" values 
 * @param andAnObjectQueried - Class of the "and" object to be queried
 * @param andFieldNameList - Array of names of the "and" Fields to check in order
 * @param andGivenValueList - Array of values the "and" fields should equal in order
 * @param orObjectQueried - Class of the "or" object to be queried
 * @param orFieldNameList - Array of names of the "or" Fields to check in order
 * @param orGivenValueList - Array of values the "or" fields should equal in order
 * @return A List of Models containing all of the models that match all of the given fields
 * @throws WPISuiteException
 */

Complex Retrieve is a combination of both AND retrieve and OR retrieve. The function works by running the AND retrieve on the ANDAnObjectQueried with the fields in andFieldNameList and the values in andGivenValueList. All objects returned from that will match the given fieldvalue to the given field name in order. The function will run the OR retrieve on the orObject and will return all objects that match one of the givenValues to thefieldName in order. The function then filters through the two returned lists to return only a list of the objects that appeared in both lists.

Known Issues and Restrictions:

  • The database is not configured to work with large objects like image files.
  • The database must be configured to work with certain Java objects, like Calendar or GregorianCalendar, that don't get serialized properly. The following line must be added to the database constructor. For DataStore, it is the getDataStore() function that must be modified. config.common().objectClass(YOUR_CLASS_HERE.class).callConstructor(true);
  • Models with too many levels of nested objects will not work.
⚠️ **GitHub.com Fallback** ⚠️