forked from sakaiproject/sakai
-
Notifications
You must be signed in to change notification settings - Fork 0
/
design.xml
210 lines (207 loc) · 11.1 KB
/
design.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<?xml version="1.0" encoding="UTF-8"?>
<document>
<properties>
<author email="[email protected]">Ian Boston</author>
<title>RWiki Design Issues</title>
</properties>
<body>
<section name="Component Preparation" >
<p>
When the code was added to the 2.1 Sakai release, it became apparent that
it would be difficult to extract a clean component/service/api layered structure.
If we use any hibernate based components that are loaded from the component, shared
or server class loaders in the request cycle it will become necessary to complete this
refactor.
</p>
<subsection name=" Package Sub Tree: uk.ac.cam.caret.sakai.rwiki.service" >
<p>
All packages in this subtree are pure API, that can be placed in the shared area.
They do not depend on components or tool.
</p>
</subsection>
<subsection name=" Package Sub Tree: uk.ac.cam.caret.sakai.rwiki.component" >
<p>
All packages in this subtree are pure Component. They depend on the service
api. They are used by the tool. It is expected that this super component will
be deployed under the components class loaded in the future. All Hibernate DAO's and related
POJO implementations are at this level. There is nothing specific to the tool at this
level.
</p>
</subsection>
<subsection name=" Package Sub Tree: uk.ac.cam.caret.sakai.rwiki.tool" >
<p>
The tool implementation is located in this package, which will in the future be
deployed in the war.
</p>
</subsection>
<subsection name="Status" >
<p>
Currently this code is only available under the Sakai 2.1 local branch which mirrors
the main Sakai 2.1 Trunk work. We have not separated the deployment descriptors, so the
application is still stove pipe in nature.
</p>
</subsection>
</section>
<section name="Model Implementation">
<subsection name="Seperated History">
<p>
We have now separated the Current wiki objects from the historical
or versioned wiki objects. They are no longer linked at the hibernate
level but are linked at a higher level.
</p>
<p>
The aim of this approach is to avoid loading all the history content when
a page is accessed. Lazy loading would have performed this, however the
implementation of Lazy loading in Hibernate is such that we loose some
control and often see multiple statements issued for each lazy object.
The code now contains RWikiCurrentObject to represent the current objects
in the model, and RWikiHistoryObject to represent the versioned objects.
</p>
<p>
<ul>
<li>Status: Implemented and tested</li>
<li>Loacation: In Trunk </li>
</ul>
</p>
</subsection>
<subsection name="Unlinked content" >
<p>
Even with the above restructure, Hibernate loads the content of each
page when any field in the page is accessed. Hence the service method
getRWikiCurrentObject will cause the whole of the content of the object to
be loaded regardless of if we wanted to use the content or not.
</p>
<p>
In effect this means as a page is rendered, and the exists() method
on the service is invoked, potential all the linked content could be
loaded. It would be far better if a lightweight index object was available
that contained the smaller fields and a lazy loaded content field was
present in the RWikiObject (Current and History) to ensure that the
content was only loaded when the content was required.
</p>
<p>
I don't know if you can have lazy loaded one-to-one relationships in the
same table. If you can, then that will address the issue. If not then
we will need a separate table with a one-to-one relationship with the
'index' table.
</p>
<p>
On further investigation one-to-one lazy loading in hibernate is not possible,
we could use one-to-many lazy loading, but only ever have one.
</p>
<p>
One to many lazy loading does not make sense, so we have implemented explicit lazy loading
with an object proxy to inject the necessary DAO objects so that loading can take place.
This approach works quite well but has the drawback that we have to proxy the object,
and that Lists need a proxy implementation, however this is far faster than using an AOP
or introspection based proxy, as its direct method to method calls.
</p>
<p>
<ul>
<li>Status: Implemented and tested</li>
<li>Loacation: In trunk</li>
</ul>
</p>
</subsection>
<subsection name="Data Migration">
<p>
The above generates a problem. When someone updates the wiki, changes in
schema will cause and apparent loss of functionality and content. Hibernate
will perform the schema update, but it will not migrate content to the new
scheama. So objects derived from the new schema will be missing data.
</p>
<p>
We need a mechanism, hooked into the last ContextListener that tomcat
invokes that will migrate the data. This could be a simple SQL statement
that is run against the schema, or it could use the objects present
in RWiki to do more complex transformations.
</p>
<p>
RWiki not has a context listener that loads an injected DataMigrationSpecification from spring.
This Specification contains a list of DataMigrationAgents, which it uses, insequence
to migrate the data between schema version. To perform the above migrations we have
a sql script migration agent, that runs sql script against the database. This is almost
the same as the update schema mechinsim in hibernate.
</p>
<p>
Since we have added SHA1 hashes against the content, we have also added a SHAHashMigration
component that extracts all objects of a type from the database using hibernate, and then computes
the SHA1 hash of the content before updating them. This is configred in components.xml
</p>
<p>
We have tested this on our content in sakai-beta, which contains about 200 pages with an average of 20 versions
per page. On a G4 1.3 the migration process, on startup takes 27 seconds.
</p>
<p>
<ul>
<li>Status: Implemented and Tested</li>
<li>Loacation: trunk</li>
</ul>
</p>
</subsection>
<subsection name="Schema Version Control">
<p>
In order to be able to perform schema data migration, we need to know
which version the code is and which version the database is at, independant
of Hibernate. A sepeperate object that stored persisntat site wide properties
will be created. This object will store, amongst other things, version numbers.
Once of these version numbers will be the database scheam version number.
This will enable the data migration listener to invoke the correct sequence of
sql data migration statements on startup.
</p>
<p>
If any of the statements fail, this operation will fail and refuse to
allow the Tool to start.
</p>
<p>
See data migration above
</p>
<p>
<ul>
<li>Status: Implemented and tested</li>
<li>Loacation: Trunk</li>
</ul>
</p>
</subsection>
<subsection name="SHA Hash of Content" >
<p>
Since we now version every change to the page including history, we need a fast
way of determining if the page has changed or not. We have added a SHA hash to the content
that can be used for this purpose, without going to the expense of loading all the content.
We still need to modify the History page to indicate where no content has been changed between pages.
At the moment it just displays the hash.
</p>
<p>
<ul>
<li>Status: Implemented and tested</li>
<li>Loacation: Trunk</li>
</ul>
</p>
</subsection>
<subsection name="Diagrams" >
<p>
Info Page
</p>
<ul>
<li><a href="infopagewireframe.pdf" >Info Page Wireframe</a></li>
<li><a href="infopage2.png" >Info Page Wireframe v2</a></li>
</ul>
<p>
Permissions Rules Diagrams
</p>
<ul>
<li><a href="canadminaction.pdf" >Can Admin a page</a></li>
<li><a href="cancreateaction.pdf" >Can Create a page</a></li>
<li><a href="canreadaction.pdf" >Can Read a page</a></li>
<li><a href="canwriteaction.pdf" >Can Update a page</a></li>
</ul>
<p>
Code Sequence
</p>
<ul>
<li><a href="requestprocessing.pdf" >Request Processing sequence</a></li>
</ul>
</subsection>
</section>
</body>
</document>