Implementing IDataAccess
First, in order to implement a data access, there are a few things you need to keep in mind:
IDataAccess
is an OSGi service. This means that in order for your implementation to be recognized at runtime, you need to export it as a service. The preferred way to do this is via declarative services, probably auto-generated via OSGi service annotations TODO gradle build reference here.- The data access implementation must not depend on UBStore
on the service level. Since UBStore itself depends on a data
access service, this would lead to a dependency cycle. However,
it is necessary to depend on the
IUBStore
interface on the bundle level. To make possible accessing theIUBStore
object, theIDataAccess.init(IUBStore)
is called at runtime (see initialization)
Initialization
You will notice the IDataAccess.init(IUBStore)
method when
implementing the IDataAccess
interface. It has two purposes:
- Make sure the data access implementation is initialized at the right point in the bootstrapping process of UBStore.
- Providing the data access with a way to access UBStore and its functionality.
Since UBStore will give you a reference to the IUBStore
object, you can access UBStore functionality in the initialization
process. Possible use cases include:
- setting defaults in UBStores
IConfig
- reading user configuration from
IConfig
- exporting interfaces to the UBStore RMI registry
- connecting to remote nodes via UBStores
ICommunication
UBStore will make sure that everything has been initialized
when init(IUBStore)
is called except:
- the shepherd
- the router
These two modules are initialized after the data access, and the router might depend on the data access to be already up and running.
Input validation
The implementation is responsible for validating input for
the put()
, get()
and remove()
methods and throwing
exceptions if appropriate (see put requirements and get
semantics).
However, to avoid forcing all data access implementations to
implement all checks manually, there are helper methods in the
Helper modules DataItems
class.
Testing
In order to verify that your data access implementation
behaves properly, we recommend unit testing it. UBStore
provides an IDataAccessTest
module that can be used
to test the public behaviour defined in IDataAccess
(although it is probably a good idea to test
implementation specifics, too).
To use IDataAccess
, simply define a JUnit test case
and let the class extend IDataAccessTest
. You are then
required to implement two abstract methods:
dataAccessFactory()
should return an initialized instance of the data access implementation class you wish to test. All tests are run against this instance.regexTestCasesFile()
should return a Java Path object pointing to a text file that contains Regex test cases. You can get such a file from the OpenJDK project. Sadly, we cannot include that text file for licensing reasons.
A Unit Test case that extends IDataAccessTest
will
automatically contain a lot of tests that check if the
public methods defined by IDataAccess
behave correctly.
Of course, the Unit Test can contain your own custom
test methods, defined as usual using JUnit (@Test
annotations and assert*
methods and all).
IDataAccessTest
also provides helper methods that
can be used when writing additional tests: the cleanLater()
variants will remove data items on test tear down, and
the getDataAccess()
method will give you a reference
to the data access you created in dataAccessFactory()
.