1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
|
19 |
|
|
20 |
|
package org.xwiki.annotation.io.internal.migration.hibernate; |
21 |
|
|
22 |
|
import java.util.ArrayList; |
23 |
|
import java.util.Collections; |
24 |
|
import java.util.Comparator; |
25 |
|
import java.util.Date; |
26 |
|
import java.util.HashMap; |
27 |
|
import java.util.List; |
28 |
|
import java.util.Map; |
29 |
|
import java.util.Map.Entry; |
30 |
|
|
31 |
|
import javax.inject.Inject; |
32 |
|
import javax.inject.Named; |
33 |
|
import javax.inject.Singleton; |
34 |
|
|
35 |
|
import org.hibernate.HibernateException; |
36 |
|
import org.hibernate.Query; |
37 |
|
import org.hibernate.Session; |
38 |
|
import org.slf4j.Logger; |
39 |
|
import org.xwiki.annotation.AnnotationConfiguration; |
40 |
|
import org.xwiki.component.annotation.Component; |
41 |
|
import org.xwiki.model.EntityType; |
42 |
|
import org.xwiki.model.reference.DocumentReference; |
43 |
|
import org.xwiki.model.reference.EntityReference; |
44 |
|
import org.xwiki.model.reference.EntityReferenceSerializer; |
45 |
|
import org.xwiki.model.reference.WikiReference; |
46 |
|
|
47 |
|
import com.xpn.xwiki.XWikiContext; |
48 |
|
import com.xpn.xwiki.XWikiException; |
49 |
|
import com.xpn.xwiki.objects.BaseObject; |
50 |
|
import com.xpn.xwiki.objects.BaseProperty; |
51 |
|
import com.xpn.xwiki.objects.DateProperty; |
52 |
|
import com.xpn.xwiki.objects.LargeStringProperty; |
53 |
|
import com.xpn.xwiki.objects.StringListProperty; |
54 |
|
import com.xpn.xwiki.objects.StringProperty; |
55 |
|
import com.xpn.xwiki.objects.classes.BaseClass; |
56 |
|
import com.xpn.xwiki.store.XWikiHibernateBaseStore.HibernateCallback; |
57 |
|
import com.xpn.xwiki.store.migration.DataMigrationException; |
58 |
|
import com.xpn.xwiki.store.migration.XWikiDBVersion; |
59 |
|
import com.xpn.xwiki.store.migration.hibernate.AbstractHibernateDataMigration; |
60 |
|
|
61 |
|
|
62 |
|
|
63 |
|
|
64 |
|
|
65 |
|
|
66 |
|
|
67 |
|
|
68 |
|
@version |
69 |
|
@since |
70 |
|
|
71 |
|
@Component |
72 |
|
@Named("R40001XWIKI7540") |
73 |
|
@Singleton |
|
|
| 5% |
Uncovered Elements: 38 (40) |
Complexity: 8 |
Complexity Density: 0.27 |
|
74 |
|
public class R40001XWIKI7540DataMigration extends AbstractHibernateDataMigration |
75 |
|
{ |
76 |
|
|
77 |
|
private static final EntityReference XWIKI_COMMENT_CLASS_REFERENCE = new EntityReference("XWikiComments", |
78 |
|
EntityType.DOCUMENT, new EntityReference("XWiki", EntityType.SPACE)); |
79 |
|
|
80 |
|
|
81 |
|
private static final EntityReference XWIKI_ANNOTATION_CLASS_REFERENCE = new EntityReference("AnnotationClass", |
82 |
|
EntityType.DOCUMENT, new EntityReference("AnnotationCode", EntityType.SPACE)); |
83 |
|
|
84 |
|
|
85 |
|
@Inject |
86 |
|
protected Logger logger; |
87 |
|
|
88 |
|
|
89 |
|
@Inject |
90 |
|
protected EntityReferenceSerializer<String> referenceSerializer; |
91 |
|
|
92 |
|
|
93 |
|
@Inject |
94 |
|
protected AnnotationConfiguration configuration; |
95 |
|
|
96 |
|
|
97 |
|
protected Map<DocumentReference, List<Entry<Date, BaseObject>>> documentToDatedObjectsMap = |
98 |
|
new HashMap<DocumentReference, List<Entry<Date, BaseObject>>>(); |
99 |
|
|
100 |
|
|
101 |
|
protected Map<BaseObject, List<BaseProperty>> objectToPropertiesMap = new HashMap<BaseObject, List<BaseProperty>>(); |
102 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
103 |
0 |
@Override... |
104 |
|
public String getDescription() |
105 |
|
{ |
106 |
0 |
return "See http://jira.xwiki.org/browse/XWIKI-7540"; |
107 |
|
} |
108 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
109 |
3 |
@Override... |
110 |
|
public XWikiDBVersion getVersion() |
111 |
|
{ |
112 |
|
|
113 |
3 |
return new XWikiDBVersion(40001); |
114 |
|
} |
115 |
|
|
116 |
|
|
117 |
|
|
118 |
|
|
119 |
|
|
120 |
|
@link |
121 |
|
|
122 |
|
|
123 |
|
@return |
124 |
|
@throws |
125 |
|
|
|
|
| 0% |
Uncovered Elements: 20 (20) |
Complexity: 4 |
Complexity Density: 0.25 |
|
126 |
0 |
protected boolean checkAnnotationsAndComments() throws DataMigrationException... |
127 |
|
{ |
128 |
0 |
XWikiContext context = getXWikiContext(); |
129 |
0 |
String resultOfSkippingDatabase = "Comments and anotations will remain separated"; |
130 |
|
|
131 |
0 |
try { |
132 |
0 |
EntityReference currentAnnotationClassReference = configuration.getAnnotationClassReference(); |
133 |
0 |
currentAnnotationClassReference = |
134 |
|
currentAnnotationClassReference.removeParent(new WikiReference(context.getWikiId())); |
135 |
0 |
if (!XWIKI_ANNOTATION_CLASS_REFERENCE.equals(currentAnnotationClassReference)) { |
136 |
0 |
logger.warn("Skipping database [{}] because it uses a custom annotation class. " |
137 |
|
+ resultOfSkippingDatabase, context.getWikiId()); |
138 |
0 |
return false; |
139 |
|
} |
140 |
|
|
141 |
0 |
BaseClass commentsClass = context.getWiki().getCommentsClass(context); |
142 |
0 |
if (commentsClass.hasCustomMapping()) { |
143 |
0 |
logger.warn("Skipping database [{}] because it uses a custom mapping for comments. " |
144 |
|
+ resultOfSkippingDatabase, context.getWikiId()); |
145 |
0 |
return false; |
146 |
|
} |
147 |
|
} catch (Exception e) { |
148 |
|
|
149 |
0 |
String message = |
150 |
|
"Failed to check the current annotation and comments classes for customizations. " |
151 |
|
+ "Migration will not execute"; |
152 |
0 |
logger.error(message, e); |
153 |
0 |
throw new DataMigrationException(message, e); |
154 |
|
} |
155 |
|
|
156 |
0 |
return true; |
157 |
|
} |
158 |
|
|
|
|
| 0% |
Uncovered Elements: 14 (14) |
Complexity: 2 |
Complexity Density: 0.17 |
|
159 |
0 |
@Override... |
160 |
|
protected void hibernateMigrate() throws DataMigrationException, XWikiException |
161 |
|
{ |
162 |
|
|
163 |
0 |
if (!checkAnnotationsAndComments()) { |
164 |
0 |
return; |
165 |
|
} |
166 |
|
|
167 |
|
|
168 |
0 |
documentToDatedObjectsMap.clear(); |
169 |
0 |
objectToPropertiesMap.clear(); |
170 |
|
|
171 |
0 |
logger.info("Computing the work to be done."); |
172 |
|
|
173 |
|
|
174 |
0 |
getStore().executeRead(getXWikiContext(), true, new GetWorkToBeDoneHibernateCallback()); |
175 |
|
|
176 |
0 |
logger.info("There is a total of {} documents to migrate.", documentToDatedObjectsMap.keySet().size()); |
177 |
|
|
178 |
|
|
179 |
|
|
180 |
0 |
DoWorkOnDocumentHibernateCallback doWorkOnDocumentHibernateCallback = new DoWorkOnDocumentHibernateCallback(); |
181 |
0 |
for (DocumentReference documentReference : documentToDatedObjectsMap.keySet()) { |
182 |
0 |
logger.info("Migrating document [{}]", referenceSerializer.serialize(documentReference, (Object[]) null)); |
183 |
|
|
184 |
0 |
doWorkOnDocumentHibernateCallback.setDocumentReference(documentReference); |
185 |
0 |
getStore().executeWrite(getXWikiContext(), true, doWorkOnDocumentHibernateCallback); |
186 |
|
} |
187 |
|
} |
188 |
|
|
189 |
|
|
190 |
|
|
191 |
|
|
192 |
|
@version |
193 |
|
|
|
|
| 0% |
Uncovered Elements: 31 (31) |
Complexity: 6 |
Complexity Density: 0.26 |
|
194 |
|
private class GetWorkToBeDoneHibernateCallback implements HibernateCallback<Object> |
195 |
|
{ |
|
|
| 0% |
Uncovered Elements: 6 (6) |
Complexity: 2 |
Complexity Density: 0.33 |
|
196 |
0 |
@Override... |
197 |
|
public Object doInHibernate(Session session) throws HibernateException, XWikiException |
198 |
|
{ |
199 |
0 |
try { |
200 |
|
|
201 |
|
|
202 |
0 |
Query getExistingAnnotationsAndCommentsQuery = |
203 |
|
session.createQuery("SELECT obj, prop FROM BaseObject obj, BaseProperty prop WHERE " |
204 |
|
+ "(obj.className='AnnotationCode.AnnotationClass' OR obj.className='XWiki.XWikiComments') " |
205 |
|
+ "AND prop.id.id=obj.id AND obj.name in " |
206 |
|
+ "(SELECT doc.fullName FROM XWikiDocument doc, BaseObject ann WHERE " |
207 |
|
+ "ann.name=doc.fullName AND ann.className='AnnotationCode.AnnotationClass')"); |
208 |
0 |
List<Object[]> queryResults = (List<Object[]>) getExistingAnnotationsAndCommentsQuery.list(); |
209 |
|
|
210 |
0 |
preProcessResults(queryResults); |
211 |
|
} catch (Exception e) { |
212 |
0 |
throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_STORE_MIGRATION, |
213 |
|
getName() + " failed to read the work to be done.", e); |
214 |
|
} |
215 |
|
|
216 |
0 |
return Boolean.TRUE; |
217 |
|
} |
218 |
|
|
219 |
|
|
220 |
|
|
221 |
|
|
222 |
|
@param |
223 |
|
@throws |
224 |
|
|
|
|
| 0% |
Uncovered Elements: 23 (23) |
Complexity: 4 |
Complexity Density: 0.24 |
|
225 |
0 |
private void preProcessResults(List<Object[]> queryResults) throws HibernateException... |
226 |
|
{ |
227 |
0 |
for (Object[] queryResult : queryResults) { |
228 |
0 |
BaseObject object = (BaseObject) queryResult[0]; |
229 |
0 |
BaseProperty property = (BaseProperty) queryResult[1]; |
230 |
0 |
DocumentReference documentReference = object.getDocumentReference(); |
231 |
|
|
232 |
0 |
if (property instanceof DateProperty) { |
233 |
0 |
List<Entry<Date, BaseObject>> datedObjects = documentToDatedObjectsMap.get(documentReference); |
234 |
0 |
if (datedObjects == null) { |
235 |
0 |
datedObjects = new ArrayList<Map.Entry<Date, BaseObject>>(); |
236 |
0 |
documentToDatedObjectsMap.put(documentReference, datedObjects); |
237 |
|
} |
238 |
|
|
239 |
0 |
Date date = (Date) ((DateProperty) property).getValue(); |
240 |
0 |
Entry<Date, BaseObject> datedObject = new HashMap.SimpleEntry<Date, BaseObject>(date, object); |
241 |
0 |
datedObjects.add(datedObject); |
242 |
|
} |
243 |
|
|
244 |
0 |
List<BaseProperty> properties = objectToPropertiesMap.get(object); |
245 |
0 |
if (properties == null) { |
246 |
0 |
properties = new ArrayList<BaseProperty>(); |
247 |
0 |
objectToPropertiesMap.put(object, properties); |
248 |
|
} |
249 |
0 |
properties.add(property); |
250 |
|
} |
251 |
|
} |
252 |
|
} |
253 |
|
|
254 |
|
|
255 |
|
|
256 |
|
|
257 |
|
@version |
258 |
|
|
|
|
| 0% |
Uncovered Elements: 83 (83) |
Complexity: 17 |
Complexity Density: 0.3 |
|
259 |
|
private class DoWorkOnDocumentHibernateCallback implements HibernateCallback<Object> |
260 |
|
{ |
261 |
|
@see |
262 |
|
private DocumentReference documentReference; |
263 |
|
|
264 |
|
@see |
265 |
|
private Map<BaseObject, BaseObject> oldToNewObjectMap; |
266 |
|
|
267 |
|
@see |
268 |
|
private Map<Integer, Integer> oldToNewCommentNumberMap; |
269 |
|
|
270 |
|
@param |
|
|
| 0% |
Uncovered Elements: 3 (3) |
Complexity: 1 |
Complexity Density: 0.33 |
|
271 |
0 |
public void setDocumentReference(DocumentReference documentReference)... |
272 |
|
{ |
273 |
0 |
this.documentReference = documentReference; |
274 |
0 |
this.oldToNewObjectMap = new HashMap<BaseObject, BaseObject>(); |
275 |
0 |
this.oldToNewCommentNumberMap = new HashMap<Integer, Integer>(); |
276 |
|
} |
277 |
|
|
|
|
| 0% |
Uncovered Elements: 4 (4) |
Complexity: 2 |
Complexity Density: 0.5 |
|
278 |
0 |
@Override... |
279 |
|
public Object doInHibernate(Session session) throws HibernateException, XWikiException |
280 |
|
{ |
281 |
0 |
try { |
282 |
|
|
283 |
|
|
284 |
0 |
processObjects(session); |
285 |
|
} catch (Exception e) { |
286 |
0 |
throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_STORE_MIGRATION, |
287 |
|
getName() + " failed to do the work for document " |
288 |
|
+ referenceSerializer.serialize(documentReference, (Object[]) null), e); |
289 |
|
} |
290 |
|
|
291 |
0 |
return Boolean.TRUE; |
292 |
|
} |
293 |
|
|
294 |
|
|
295 |
|
|
296 |
|
|
297 |
|
|
298 |
|
@param |
299 |
|
@throws |
300 |
|
|
|
|
| 0% |
Uncovered Elements: 29 (29) |
Complexity: 4 |
Complexity Density: 0.17 |
|
301 |
0 |
private void processObjects(Session session) throws HibernateException... |
302 |
|
{ |
303 |
0 |
List<Entry<Date, BaseObject>> datedObjects = documentToDatedObjectsMap.get(documentReference); |
304 |
|
|
305 |
|
|
306 |
|
|
307 |
|
|
308 |
|
|
309 |
0 |
for (Entry<Date, BaseObject> datedObject : datedObjects) { |
310 |
0 |
BaseObject object = datedObject.getValue(); |
311 |
|
|
312 |
0 |
for (BaseProperty property : objectToPropertiesMap.get(object)) { |
313 |
0 |
session.delete(property); |
314 |
|
} |
315 |
|
|
316 |
0 |
session.delete(object); |
317 |
|
} |
318 |
|
|
319 |
|
|
320 |
|
|
321 |
0 |
session.flush(); |
322 |
0 |
session.clear(); |
323 |
|
|
324 |
|
|
325 |
0 |
Collections.sort(datedObjects, new Comparator<Entry<Date, BaseObject>>() |
326 |
|
{ |
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
327 |
0 |
@Override... |
328 |
|
public int compare(Entry<Date, BaseObject> datedObject1, Entry<Date, BaseObject> datedObject2) |
329 |
|
{ |
330 |
0 |
return datedObject1.getKey().compareTo(datedObject2.getKey()); |
331 |
|
} |
332 |
|
}); |
333 |
|
|
334 |
|
|
335 |
0 |
for (int newObjectNumber = 0; newObjectNumber < datedObjects.size(); newObjectNumber++) { |
336 |
0 |
BaseObject deletedObject = datedObjects.get(newObjectNumber).getValue(); |
337 |
|
|
338 |
0 |
BaseObject newComment = getMigratedObject(deletedObject, newObjectNumber); |
339 |
|
|
340 |
|
|
341 |
|
|
342 |
0 |
if (deletedObject.getRelativeXClassReference().equals(XWIKI_COMMENT_CLASS_REFERENCE)) { |
343 |
0 |
oldToNewCommentNumberMap.put(deletedObject.getNumber(), newComment.getNumber()); |
344 |
|
} |
345 |
|
|
346 |
|
|
347 |
|
|
348 |
0 |
oldToNewObjectMap.put(deletedObject, newComment); |
349 |
|
|
350 |
0 |
session.save(newComment); |
351 |
|
} |
352 |
|
|
353 |
|
|
354 |
0 |
for (int newObjectNumber = 0; newObjectNumber < datedObjects.size(); newObjectNumber++) { |
355 |
0 |
BaseObject deletedObject = datedObjects.get(newObjectNumber).getValue(); |
356 |
|
|
357 |
|
|
358 |
0 |
BaseObject newComment = oldToNewObjectMap.get(deletedObject); |
359 |
|
|
360 |
0 |
List<BaseProperty> deletedProperties = objectToPropertiesMap.get(deletedObject); |
361 |
0 |
for (BaseProperty deletedProperty : deletedProperties) { |
362 |
0 |
BaseProperty newProperty = getMigratedProperty(deletedProperty, newComment); |
363 |
|
|
364 |
0 |
session.save(newProperty); |
365 |
|
} |
366 |
|
} |
367 |
|
} |
368 |
|
|
369 |
|
|
370 |
|
@param |
371 |
|
@param |
372 |
|
@return |
373 |
|
|
|
|
| 0% |
Uncovered Elements: 7 (7) |
Complexity: 2 |
Complexity Density: 0.4 |
|
374 |
0 |
private BaseObject getMigratedObject(BaseObject deletedObject, int newObjectNumber)... |
375 |
|
{ |
376 |
|
|
377 |
0 |
BaseObject newObject = deletedObject.clone(); |
378 |
0 |
newObject.setNumber(newObjectNumber); |
379 |
|
|
380 |
|
|
381 |
0 |
if (deletedObject.getRelativeXClassReference().equals(XWIKI_ANNOTATION_CLASS_REFERENCE)) { |
382 |
0 |
newObject.setXClassReference(XWIKI_COMMENT_CLASS_REFERENCE); |
383 |
|
} |
384 |
|
|
385 |
0 |
return newObject; |
386 |
|
} |
387 |
|
|
388 |
|
|
389 |
|
@param |
390 |
|
@param |
391 |
|
@return |
392 |
|
|
|
|
| 0% |
Uncovered Elements: 33 (33) |
Complexity: 7 |
Complexity Density: 0.33 |
|
393 |
0 |
private BaseProperty getMigratedProperty(BaseProperty deletedProperty, BaseObject newComment)... |
394 |
|
{ |
395 |
0 |
BaseProperty newProperty = null; |
396 |
|
|
397 |
|
|
398 |
|
|
399 |
|
|
400 |
|
|
401 |
|
|
402 |
0 |
if (deletedProperty instanceof StringListProperty) { |
403 |
|
|
404 |
|
|
405 |
0 |
if ("author".equals(deletedProperty.getName())) { |
406 |
0 |
newProperty = new StringProperty(); |
407 |
|
} else { |
408 |
0 |
newProperty = new LargeStringProperty(); |
409 |
|
} |
410 |
|
|
411 |
|
|
412 |
|
|
413 |
0 |
String deletedPropertyValue = null; |
414 |
0 |
List<String> internalListValue = ((StringListProperty) deletedProperty).getList(); |
415 |
0 |
if (internalListValue.size() != 0) { |
416 |
0 |
deletedPropertyValue = internalListValue.get(0); |
417 |
|
} |
418 |
|
|
419 |
0 |
newProperty.setValue(deletedPropertyValue); |
420 |
0 |
newProperty.setName(deletedProperty.getName()); |
421 |
|
} else { |
422 |
0 |
newProperty = deletedProperty.clone(); |
423 |
|
} |
424 |
0 |
newProperty.setId(newComment.getId()); |
425 |
|
|
426 |
0 |
if ("annotation".equals(deletedProperty.getName())) { |
427 |
|
|
428 |
|
|
429 |
0 |
newProperty.setName("comment"); |
430 |
0 |
} else if ("replyto".equals(deletedProperty.getName())) { |
431 |
|
|
432 |
|
|
433 |
|
|
434 |
0 |
if (deletedProperty.getValue() != null) { |
435 |
0 |
int oldValue = (Integer) deletedProperty.getValue(); |
436 |
0 |
int newValue = oldToNewCommentNumberMap.get(oldValue); |
437 |
|
|
438 |
0 |
newProperty.setValue(newValue); |
439 |
|
} |
440 |
|
} |
441 |
0 |
return newProperty; |
442 |
|
} |
443 |
|
} |
444 |
|
} |