Implement Domain Model Modification - dswarm/dswarm-documentation GitHub Wiki
note: the description of the process at this page are probably outdated - contact us, if you plan to extend the domain model (and we'll update the instructions ;) )
If you would like to implement modifications (incl. additions) of the domain model in the backend, you first need to identify, which parts are affected from these changes, i.e., e.g. whether they are located in the model package (which is valid for the majority) or somewhere else. If the entities are located or should be located in the model package, then you need to create a POJO class for them or modify an existing one.
POJO Classes
POJO classes are implementations of a domain model entities. Since we make use of JPA as abstraction for persistence, you need to ensure the appropriate utilisation of the JPA annotations (you can also have a look at existing POJO classes, i.e., how they are utilised there, e.g., ContentSchema). Furthermore, since we also make use of Jackson for data exchange (de-/serialisation), which can also handle JAXB annotations, you also need to ensure the appropriate utilisation of the Jackson/JAXB annotations (here you can also have a look at the existing POJO classes, i.e., how they are utilised there).
Each domain model entity implementation has it's companion proxy class to carry processing states etc. (e.g. RetrievalType) that are created when working with the domain model entities - however, that are not part of the domain model entity itself. The concrete companion proxy classes are simply for guaranteeing type-safeness of the carry POJO classes. Since the related logic is contain in the abstract proxy class (i.e. in ProxyDMPObject and extended abstract classes), you can simply create a proxy class for your new POJO class and make sure that the class signature point to your POJO class and that you extend from the companion abstract proxy class (of the abstract POJO class your concrete POJO class extends from). You can also have a look at other concrete proxy classes, e.g., ProxyContentSchema to get an impression how should look like.
Each POJO class has it's companion util class as well to provide processing logic that can be applied on one or more (i.e. collection) objects (instances) of a domain model entity. Currently, the util classes mainly provide logic to completely compare objects of a certain POJO class with each other (see the completeEquals
method in DMPObjectUtils, since the equals
implementations of the POJO classes compare only for identifier equality right now). This logic is also mainly generalized in the abstract POJO util classes. So you can also simply create a util class for your new domain model entity implementation, point to the POJO class in the class signature and ensure that it extends from the correct related abstract util class (see, e.g., ContentSchemaUtils to get an expression how it should look like).
Metadata Repository Schema Generation
When you've finished creating and/or modifying your POJOs in the model package, then you can re-create the schema of the metadata repository (see also here). You can simply make use of the following Maven command to generate schema script automatically (you need to call this command within the persistence
module (directory)):
mvn hibernate4:export
The result should be a schema.sql
script in the target
directory of the persistence
module.
Afterwards, you can utilise a diff tool of your choice to compare the new schema script with the existing on in persistence/src/main/resources. Now it's getting a bit complicated (right now). You should only change (insert, remove, ...) necessary parts of the script.
- You can skip the "alter table" part (at the beginning!) of the new script (since we make use of
SET foreign_key_checks = 0;
at the beginning of the script to unlock foreign key constraints, when processing the script (they will be enabled at the end of the script)) - At the "drop table" part the relevant changes should be easily visible in your diff tool (i.e. often it's just the case that a new table should be dropped as well or that existing one was renamed)
- At the following "create table" and "alter table" parts the relevant changes should also be easily visible in your diff tool (note: sometimes it's the case that the generated foreign key identifier change over the whole script - then it might be a bit difficult to just cherry pick only the new ones)
It's recommended to change smaller parts step-by-step and compare the result with the diff tool again. Generally, it's also recommended to apply all these changes to the schema script with care, since it's an essential part of the application.
Persistence Services
Each POJO class (domain model entity implementation) has a companion persistence service (you can probably view them as DAO) that is located in/below the src/main/java/org/dswarm/persistence/service package. These service take care of the communication/handling with the metadata repository (e.g. read objects, write objects, database transactions etc.).
Depending on which abstract DMPObject implementation your POJO relies on, you'll also find a companion abstract persistence service where your concrete domain model entity persistence service can extend from (e.g. BasicJPAService). You can have a look at other concrete domain model entity persistence service classes, e.g., ContentSchemaService to get an expression which methods just need to be overwritten/implemented there.
Mainly, you need to take care of decoupling related objects when deleting a persistently stored object (see the prepareObjectForRemoval
method) and setting related objects when an update should be processed on the object (see the updateObjectInternal
method). Make sure to also updated existing POJO persistence services as needed (e.g. when you've introduced a new relationship to another domain model entity).
Persistence Layer Tests
Now it's time to test your domain model modifications. It's a good choice to first test single parts and then affected compound entities (that make use of e.g. the new entity that was introduced in you domain model modification). You can (optionally) first create unit tests in/below the persistence/src/test/java/org/dswarm/persistence/model package (depending where your domain model POJOs are located). However, since we only rely on identifiers that are generated by the metadata repository right now, you probably cannot fully test the functionality of your domain model modifications right now without the persistence layer (this issue will be fixed in the future).
That's why, the more important step is to create integration tests to verify the functionality of your domain model modifications in context of the persistence layer, i.e., that the objects are stored as intended in the metadata repository. Persistence service tests are powered by a framework
- that generalized some common tests (via abstract persistence service test classes starting from BasicJPAServiceTest), e.g.,
idGenerationTest
in IDBasicJPAServiceTest, - that provides (i.e. creates, composes etc.) persistent objects as necessary for testing and
- that contain
compare
methods for comparing test result objects with expected ones
(the last two features are provided by persistence service test util classes starting from BasicJPAServiceTestUtils).
So, when you would like to create a new test class for your new concrete persistence service (of your new POJO), you can simply extend it from the appropriated abstract persistence service test class, set the pointers to the related POJO class etc. and start implementing your tests as necessary (see, e.g., ContentSchemaServiceTest). Whereby, the object creation should mainly take place in the related persistence service test utils class (see, e.g., ContentSchemaServiceTestUtils). This should ensure the re-usability of persistent domain model entity creation for other tests. This requires the creation of the companion persistence service test utils for your new domain model entity as well.
Note: Please first read the following section (Initial Data Provisioning) carefully before starting to test the persistence services after your domain model modification
Initial Data Provisioning
Initial data provisioning ensures that the metadata repository gets filled with data that should be available from start of the application. Since the metadata repository relies on a relational database right now, this content is provided via SQL scripts that are located at persistence/src/main/resources. Currently, these are
- functions that provides the set of built-in functions and
- init_internal_schema that provides some schemata, e.g., one for MABxml. If your domain model modifications affect the initial data provisioning you should first modify the SQL scripts as necessary, since they are utilised before each persistence service test to guarantee the correct state of the metadata repository.
- So it's a good choice to start with the persistence service tests that are affected from your domain model modification and that influence the initial data provisioning (i.e. create new persistence service tests and modify existing persistence service tests as necessary). Thereby, you should temporarily switch off the MaintainDBService#initDB() calls in the
prepare
andtearDown
method of BasicJPAServiceTest. - After you've finished testing the related persistence service, you can modify the initial data provisioning script ... TODO (point to related tests)
- Then you can re-enable the MaintainDBService#initDB() calls in the
prepare
andtearDown
method of BasicJPAServiceTest. - And (optionally) continue (or start with) testing the rest of the affect persistence service re. your domain model modifications.