| 190 | === Doing changes === |
| 191 | * Basically the implementation of the changeResource method of the Service for DB. |
| 192 | * Everything is done in one transaction, if some part of the change can not be persisted all the changes are rollbacked. |
| 193 | * Algorithm: |
| 194 | * Two things must be stored, the persisted to XML Change and the new values of the keys (ChangeEffect). Also new revision should be created. |
| 195 | * Persisting the Change to XML is easy, it is Immutable and can be persisted with the Sophie 2 Persistence API. There is a Reader connected to the persisted value. |
| 196 | * Getting the Effect: |
| 197 | * If the change is MetaChange (Skip/Unskip/Undo/Redo) the skip algorithm is used to get its effect. |
| 198 | * If the chage is ModelChange (change created from AutoAction) the effect is retrieved from its getEffect method, which uses ResourceChanger. For model is used a ResourceReader which get raw gets the values from the DB using the findValue method of the service. |
| 199 | * When the change is stored to reader and the effect is retrieved a new revision is created in the DB using the ResourceDAO's createRevision method with parameters a new revision id and the IO Reader to the stored Change. |
| 200 | * The reads from the ChangeEffect are stored to the DB via the readKeys of the dao. |
| 201 | * The writes from the ChangeEffect are stored to the DB via the changeKeys method of the dao. |
| 202 | * They are converted to DB format using a special ResourceVisitor, that creates the paths for the Resources (the way of setting root and children keys in the DB). It stores the regular keys to IO Readers. |
| 203 | === Redo/Undo algorithm === |
| 204 | * The current logic of Skipping changes is generalized and moved to a special class [browser:branches/private/tsachev/paragraphs/modules/org.sophie2.base.model.resources.r4/src/main/java/org/sophie2/base/model/resources/r4/changes/SkipRevisionAlgorithm.java SkipRevisionAlgorithm] (think of a better name if you care...) It uses a special interface SkipContext to retrieve the data needed by the algorith to skip the changes. |
| 205 | * Interface : SkipContext (Inner for the SkipRevisionAlgorithm, if you want it can be pulled up). Represents the data (ResourceModel, writes, reads) for given revision, the algorith works with such contexts, not revisions, and retrieves the data from them. This way we can use different implementation to retrieve the data from different places... DB, Accesses, something else... |
| 206 | * Methods: |
| 207 | * {{{RevisionId getId()}}} -> Gets the id of the revision of the SKipContext. |
| 208 | * {{{SkipContext getPreviousRevisionContext()}}} -> Retrieves the previous context (the SkipContext of the previous revision) |
| 209 | * {{{ResourceReader getReader()}}} -> Gets the model of this context. Its reader because the model can be something different then simple ResourceModel. |
| 210 | * {{{ResourceReader getModifiedReader(Map<Key<?>, Object> writes)}}} -> Getter for a modified resource reader which will behave as the one returned by {@link #getReader()} but with modified values specified by <code>writes</code>. |
| 211 | * {{{Change getCausingChange()}}} -> Retrieves the causing change of the revision of the SkipContext. |
| 212 | * {{{<Key<?>> getWrittenKeys()}}} and {{{Iterable<Key<?>> getReads()}}} -> The writes and the reads for the revision of the Context |
| 213 | * Implementations : |
| 214 | * Class : ResourceRevisionSkipContext (better name?) embedded in the ResourceRevision class, the default SkipContext that uses ChangeEffect and ResourceModel to implement its methods. The old implementation. |
| 215 | * Class : [browser:branches/private/tsachev/paragraphs/modules/org.sophie2.server.core/src/main/java/org/sophie2/server/core/persistence/db/DBChangeContext.java DBChangeContext] -> The db implementation of the SkipContext: |
| 216 | * Getting the model -> A lazy reader to the database is created. |
| 217 | * If there is a model generated in the form of Key to Long (DB id of the value of the key), use a RootAndChildrenVisitor implementation to retrieve the value of the key from the DB. If the key is Root or Children the RootAndChildrenVisitor has logic to retrieve it, if it is regular yhe dao's getValueForKey method is used. The values are cached after retrieving. |
| 218 | * If there is no model initialized yet but we have a previous context initialized (it is lazy initialized when wanted with the getPreviousRevisionContext method) the value is retrieved from it's model or the current context's writes (If they contain it). |
| 219 | * If there is no model initialized and prev context, it is initialized via the dao's getRevisionModel method and the value is get from it using the logic described above. |
| 220 | * Getting the read and writed keys -> Simple using the dao's getRevisionCausingReads and getRevisionCausingWrites methods, lazy again. |
| 221 | * Getting the causing change -> using the dao's findHistory method in this way : findHistory(the_path_of_the_context_resource, revision_id_of_the_context, revision_id_of_the_context, 0, 1). Lazy. |
| 222 | * Getting the previous context -> lazy again, A new context for the same resource but with the id of the previous revision is constructed. The previous revision is retrieved with the dao's getPreviousRevision method. |
| 223 | * Getting modified reader -> A reader which getRaw method uses the Reader form the getReader method if the wanted key is not in the writes, otherwise retrieves the key from the writes. |
| 224 | === Web interface === |
| 225 | * The web interface currently works with ResourceHs. The logic will be kept, but the helpers will be constructed with a special ResourceAccess implementation which uses the ResourceServiceDBImpl to retrieve values and change resources. |
| 226 | * This access should extend the DelegatingAccess class to be able to register changes. The getRef method of the DelegatingAccess class will be rewritten, so it will be no more final, but it must always return absolute ref. In the current case the ref it returns is absolute too. There is a comment there about that. |
| 227 | * Class [browser:branches/private/tsachev/paragraphs/modules/org.sophie2.server.core/src/main/java/org/sophie2/server/core/persistence/access/DBResourceAccess.java DBResourceAccess] -> The implementation of DelegatingAccess that delegates to the DB via ResourceServiceDBImpl |
| 228 | * The constructor is private. Such access can be created with open, which calls the static method {{{public static DBResourceAccess findWebAccess(ResourceServiceDBImpl service, ResourceRefR4 ref, String parentLocation)}}} or with the method itself. |
| 229 | * The service is used to manipulate the Db, the resource ref can be absolute or relative ref to the resource which access is wanted, and the parent location is the full location of the parent resource (fro example http://localhost:8003/resources). |
| 230 | * Getting raw values -> Uses the findValue of it's service with smart parameters generated from the parent location, resource ref and the key wanted. |
| 231 | * Registering changes -> Calls directly the changeResource method of the service (The ResponseException here could be rethrown, but may be if the change can not be registered should be caught silently. The access use must be only on the server so the ResponseException used to notify clients is not important) |
| 232 | * The cloneHeadRevision method is rewritten, because of the persistence logic, it uses a special resource model which getRaw method uses the getReader of the DBChangeContext of the current revision. |
| 233 | === Problems === |
| 234 | * Modules and names -> We should deside to rename some thing, to move them and if is needed to create new modules (Persistence module for the persistence implementations and Mock module for the old implementations) |
| 235 | * Bugs |
| 236 | * A bug with the locations still exists, you can not upload a resource with the same location as an existing, deleted one from the Web UI. The problem is that th elives in the DB are not used properly. |
| 237 | * A problem with setting a whole model as a value for a key in the DB. Upload from the client makes the book buggy if not reopen. |
| 238 | * May be the Expirience team should try it from the branch to find bugs if there are any hidden. |
| 239 | === Tests === |
| 240 | * [browser:branches/private/tsachev/paragraphs/modules/org.sophie2.server.core/src/test/java/org/sophie2/server/core/persistence/db/DBTest.java DBTest] -> The test to be extended from all the DB tests. |
| 241 | * [browser:branches/private/tsachev/paragraphs/modules/org.sophie2.server.core/src/test/java/org/sophie2/server/core/persistence/db/DBModelTest.java DBModelTest] -> Test parent for all the tests using the database with the S2S persistence schema, it creates the schema and deletes the DB after testing. |
| 242 | * [browser:branches/private/tsachev/paragraphs/modules/org.sophie2.server.core/src/test/java/org/sophie2/server/core/persistence/db/DBContextTest.java DBContextTest] -> Tests the DBChangeContext class and with it most of the ResourceDAO's methods. |
| 243 | * [browser:branches/private/tsachev/paragraphs/modules/org.sophie2.server.core/src/test/java/org/sophie2/server/core/persistence/db/ResourceDAOTest.java ResourceDAOTest] -> Tests the most important of the ResourceDAO's methods. |
| 244 | * The web UI was tested manually. |