1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
|
19 |
|
|
20 |
|
package org.xwiki.refactoring.internal; |
21 |
|
|
22 |
|
import java.util.ArrayList; |
23 |
|
import java.util.Collections; |
24 |
|
import java.util.List; |
25 |
|
import java.util.Map; |
26 |
|
import java.util.regex.Pattern; |
27 |
|
|
28 |
|
import javax.inject.Inject; |
29 |
|
import javax.inject.Named; |
30 |
|
import javax.inject.Provider; |
31 |
|
import javax.inject.Singleton; |
32 |
|
|
33 |
|
import org.slf4j.Logger; |
34 |
|
import org.xwiki.component.annotation.Component; |
35 |
|
import org.xwiki.job.event.status.JobProgressManager; |
36 |
|
import org.xwiki.model.EntityType; |
37 |
|
import org.xwiki.model.reference.DocumentReference; |
38 |
|
import org.xwiki.model.reference.DocumentReferenceResolver; |
39 |
|
import org.xwiki.model.reference.EntityReference; |
40 |
|
import org.xwiki.model.reference.EntityReferenceProvider; |
41 |
|
import org.xwiki.model.reference.EntityReferenceSerializer; |
42 |
|
import org.xwiki.model.reference.LocalDocumentReference; |
43 |
|
import org.xwiki.model.reference.SpaceReference; |
44 |
|
import org.xwiki.query.Query; |
45 |
|
import org.xwiki.query.QueryManager; |
46 |
|
|
47 |
|
import com.xpn.xwiki.XWiki; |
48 |
|
import com.xpn.xwiki.XWikiContext; |
49 |
|
import com.xpn.xwiki.XWikiException; |
50 |
|
import com.xpn.xwiki.doc.XWikiDocument; |
51 |
|
import com.xpn.xwiki.internal.parentchild.ParentChildConfiguration; |
52 |
|
|
53 |
|
|
54 |
|
@link |
55 |
|
|
56 |
|
@version |
57 |
|
@since |
58 |
|
|
59 |
|
@Component |
60 |
|
@Singleton |
|
|
| 87.1% |
Uncovered Elements: 21 (163) |
Complexity: 38 |
Complexity Density: 0.31 |
|
61 |
|
public class DefaultModelBridge implements ModelBridge |
62 |
|
{ |
63 |
|
|
64 |
|
|
65 |
|
|
66 |
|
|
67 |
|
private static final Pattern LIKE_SPECIAL_CHARS = Pattern.compile("([%_/])"); |
68 |
|
|
69 |
|
|
70 |
|
|
71 |
|
|
72 |
|
private static final LocalDocumentReference REDIRECT_CLASS_REFERENCE = new LocalDocumentReference( |
73 |
|
XWiki.SYSTEM_SPACE, "RedirectClass"); |
74 |
|
|
75 |
|
@Inject |
76 |
|
private Logger logger; |
77 |
|
|
78 |
|
|
79 |
|
|
80 |
|
|
81 |
|
@Inject |
82 |
|
private Provider<XWikiContext> xcontextProvider; |
83 |
|
|
84 |
|
|
85 |
|
|
86 |
|
|
87 |
|
@Inject |
88 |
|
private QueryManager queryManager; |
89 |
|
|
90 |
|
|
91 |
|
|
92 |
|
|
93 |
|
@Inject |
94 |
|
@Named("local") |
95 |
|
private EntityReferenceSerializer<String> localEntityReferenceSerializer; |
96 |
|
|
97 |
|
|
98 |
|
|
99 |
|
|
100 |
|
@see |
101 |
|
|
102 |
|
@Inject |
103 |
|
private EntityReferenceSerializer<String> defaultEntityReferenceSerializer; |
104 |
|
|
105 |
|
|
106 |
|
|
107 |
|
|
108 |
|
@Inject |
109 |
|
@Named("explicit") |
110 |
|
private DocumentReferenceResolver<String> explicitDocumentReferenceResolver; |
111 |
|
|
112 |
|
@Inject |
113 |
|
private JobProgressManager progressManager; |
114 |
|
|
115 |
|
@Inject |
116 |
|
private ParentChildConfiguration parentChildConfiguration; |
117 |
|
|
118 |
|
@Inject |
119 |
|
private EntityReferenceProvider entityReferenceProvider; |
120 |
|
|
|
|
| 75% |
Uncovered Elements: 2 (8) |
Complexity: 2 |
Complexity Density: 0.25 |
|
121 |
1 |
@Override... |
122 |
|
public boolean create(DocumentReference documentReference) |
123 |
|
{ |
124 |
1 |
XWikiContext xcontext = this.xcontextProvider.get(); |
125 |
|
|
126 |
1 |
try { |
127 |
1 |
XWikiDocument newDocument = xcontext.getWiki().getDocument(documentReference, xcontext); |
128 |
1 |
xcontext.getWiki().saveDocument(newDocument, xcontext); |
129 |
1 |
this.logger.info("Document [{}] has been created.", documentReference); |
130 |
1 |
return true; |
131 |
|
} catch (Exception e) { |
132 |
0 |
this.logger.error("Failed to create document [{}].", documentReference, e); |
133 |
0 |
return false; |
134 |
|
} |
135 |
|
} |
136 |
|
|
|
|
| 71.4% |
Uncovered Elements: 4 (14) |
Complexity: 4 |
Complexity Density: 0.4 |
|
137 |
4 |
@Override... |
138 |
|
public boolean copy(DocumentReference source, DocumentReference destination) |
139 |
|
{ |
140 |
4 |
XWikiContext xcontext = this.xcontextProvider.get(); |
141 |
4 |
try { |
142 |
4 |
String language = source.getLocale() != null ? source.getLocale().toString() : null; |
143 |
4 |
boolean result = |
144 |
|
xcontext.getWiki().copyDocument(source, destination, language, false, true, true, xcontext); |
145 |
4 |
if (result) { |
146 |
4 |
this.logger.info("Document [{}] has been copied to [{}].", source, destination); |
147 |
|
} else { |
148 |
0 |
this.logger.warn("Cannot fully copy [{}] to [{}] because an orphan translation" |
149 |
|
+ " exists at the destination.", source, destination); |
150 |
|
} |
151 |
4 |
return result; |
152 |
|
} catch (Exception e) { |
153 |
0 |
this.logger.error("Failed to copy [{}] to [{}].", source, destination, e); |
154 |
0 |
return false; |
155 |
|
} |
156 |
|
} |
157 |
|
|
|
|
| 84.6% |
Uncovered Elements: 2 (13) |
Complexity: 3 |
Complexity Density: 0.27 |
|
158 |
27 |
@Override... |
159 |
|
public boolean delete(DocumentReference reference) |
160 |
|
{ |
161 |
27 |
XWikiContext xcontext = this.xcontextProvider.get(); |
162 |
27 |
try { |
163 |
27 |
XWikiDocument document = xcontext.getWiki().getDocument(reference, xcontext); |
164 |
27 |
if (document.getTranslation() == 1) { |
165 |
1 |
xcontext.getWiki().deleteDocument(document, xcontext); |
166 |
1 |
this.logger.info("Document [{}] has been deleted.", reference); |
167 |
|
} else { |
168 |
26 |
xcontext.getWiki().deleteAllDocuments(document, xcontext); |
169 |
26 |
this.logger.info("Document [{}] has been deleted with all its translations.", reference); |
170 |
|
} |
171 |
27 |
return true; |
172 |
|
} catch (Exception e) { |
173 |
0 |
this.logger.error("Failed to delete document [{}].", reference, e); |
174 |
0 |
return false; |
175 |
|
} |
176 |
|
} |
177 |
|
|
|
|
| 81.8% |
Uncovered Elements: 2 (11) |
Complexity: 3 |
Complexity Density: 0.33 |
|
178 |
17 |
@Override... |
179 |
|
public boolean removeLock(DocumentReference reference) |
180 |
|
{ |
181 |
17 |
XWikiContext xcontext = this.xcontextProvider.get(); |
182 |
17 |
try { |
183 |
17 |
XWikiDocument document = xcontext.getWiki().getDocument(reference, xcontext); |
184 |
|
|
185 |
17 |
if (document.getLock(xcontext) != null) { |
186 |
14 |
document.removeLock(xcontext); |
187 |
14 |
this.logger.info("Document [{}] has been unlocked.", reference); |
188 |
|
} |
189 |
|
|
190 |
17 |
return true; |
191 |
|
} catch (Exception e) { |
192 |
|
|
193 |
0 |
this.logger.warn("Failed to unlock document [{}].", reference, e); |
194 |
0 |
return false; |
195 |
|
} |
196 |
|
} |
197 |
|
|
|
|
| 80% |
Uncovered Elements: 3 (15) |
Complexity: 3 |
Complexity Density: 0.23 |
|
198 |
3 |
@Override... |
199 |
|
public void createRedirect(DocumentReference oldReference, DocumentReference newReference) |
200 |
|
{ |
201 |
3 |
XWikiContext xcontext = this.xcontextProvider.get(); |
202 |
3 |
DocumentReference redirectClassReference = |
203 |
|
new DocumentReference(REDIRECT_CLASS_REFERENCE, oldReference.getWikiReference()); |
204 |
3 |
if (xcontext.getWiki().exists(redirectClassReference, xcontext)) { |
205 |
3 |
try { |
206 |
3 |
XWikiDocument oldDocument = xcontext.getWiki().getDocument(oldReference, xcontext); |
207 |
3 |
int number = oldDocument.createXObject(redirectClassReference, xcontext); |
208 |
3 |
String location = this.defaultEntityReferenceSerializer.serialize(newReference); |
209 |
3 |
oldDocument.getXObject(redirectClassReference, number).setStringValue("location", location); |
210 |
3 |
oldDocument.setHidden(true); |
211 |
3 |
xcontext.getWiki().saveDocument(oldDocument, "Create automatic redirect.", xcontext); |
212 |
3 |
this.logger.info("Created automatic redirect from [{}] to [{}].", oldReference, newReference); |
213 |
|
} catch (XWikiException e) { |
214 |
0 |
this.logger.error("Failed to create automatic redirect from [{}] to [{}].", oldReference, newReference, |
215 |
|
e); |
216 |
|
} |
217 |
|
} else { |
218 |
0 |
this.logger.warn("We can't create an automatic redirect from [{}] to [{}] because [{}] is missing.", |
219 |
|
oldReference, newReference, redirectClassReference); |
220 |
|
} |
221 |
|
} |
222 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (2) |
Complexity: 1 |
Complexity Density: 0.5 |
|
223 |
31 |
@Override... |
224 |
|
public boolean exists(DocumentReference reference) |
225 |
|
{ |
226 |
31 |
XWikiContext xcontext = this.xcontextProvider.get(); |
227 |
31 |
return xcontext.getWiki().exists(reference, xcontext); |
228 |
|
} |
229 |
|
|
|
|
| 60% |
Uncovered Elements: 2 (5) |
Complexity: 2 |
Complexity Density: 0.4 |
|
230 |
3 |
@Override... |
231 |
|
public List<DocumentReference> getBackLinkedReferences(DocumentReference documentReference) |
232 |
|
{ |
233 |
3 |
XWikiContext xcontext = this.xcontextProvider.get(); |
234 |
3 |
try { |
235 |
3 |
return xcontext.getWiki().getDocument(documentReference, xcontext).getBackLinkedReferences(xcontext); |
236 |
|
} catch (XWikiException e) { |
237 |
0 |
this.logger.error("Failed to retrieve the back-links for document [{}].", documentReference, e); |
238 |
0 |
return Collections.emptyList(); |
239 |
|
} |
240 |
|
} |
241 |
|
|
|
|
| 85.7% |
Uncovered Elements: 2 (14) |
Complexity: 2 |
Complexity Density: 0.14 |
|
242 |
10 |
@Override... |
243 |
|
public List<DocumentReference> getDocumentReferences(SpaceReference spaceReference) |
244 |
|
{ |
245 |
10 |
try { |
246 |
|
|
247 |
|
|
248 |
10 |
String statement = |
249 |
|
"select distinct(doc.fullName) from XWikiDocument as doc " |
250 |
|
+ "where doc.space = :space or doc.space like :spacePrefix escape '/'"; |
251 |
10 |
Query query = this.queryManager.createQuery(statement, Query.HQL); |
252 |
10 |
query.setWiki(spaceReference.getWikiReference().getName()); |
253 |
10 |
String localSpaceReference = this.localEntityReferenceSerializer.serialize(spaceReference); |
254 |
10 |
query.bindValue("space", localSpaceReference); |
255 |
10 |
String spacePrefix = LIKE_SPECIAL_CHARS.matcher(localSpaceReference).replaceAll("/$1"); |
256 |
10 |
query.bindValue("spacePrefix", spacePrefix + ".%"); |
257 |
|
|
258 |
10 |
List<DocumentReference> descendants = new ArrayList<>(); |
259 |
10 |
for (Object fullName : query.execute()) { |
260 |
13 |
descendants.add(this.explicitDocumentReferenceResolver.resolve((String) fullName, spaceReference)); |
261 |
|
} |
262 |
10 |
return descendants; |
263 |
|
} catch (Exception e) { |
264 |
0 |
this.logger.error("Failed to retrieve the documents from [{}].", spaceReference, e); |
265 |
0 |
return Collections.emptyList(); |
266 |
|
} |
267 |
|
} |
268 |
|
|
|
|
| 92.6% |
Uncovered Elements: 2 (27) |
Complexity: 5 |
Complexity Density: 0.24 |
|
269 |
5 |
@Override... |
270 |
|
public boolean updateParentField(final DocumentReference oldParentReference, |
271 |
|
final DocumentReference newParentReference) |
272 |
|
{ |
273 |
5 |
XWikiContext context = xcontextProvider.get(); |
274 |
5 |
XWiki wiki = context.getWiki(); |
275 |
|
|
276 |
5 |
boolean popLevelProgress = false; |
277 |
5 |
try { |
278 |
|
|
279 |
|
|
280 |
|
|
281 |
5 |
XWikiDocument oldParentDocument = wiki.getDocument(oldParentReference, context); |
282 |
|
|
283 |
5 |
List<DocumentReference> childReferences = oldParentDocument.getChildrenReferences(context); |
284 |
|
|
285 |
5 |
if (childReferences.size() > 0) { |
286 |
1 |
this.progressManager.pushLevelProgress(childReferences.size(), this); |
287 |
1 |
popLevelProgress = true; |
288 |
|
} |
289 |
|
|
290 |
5 |
for (DocumentReference childReference : childReferences) { |
291 |
2 |
this.progressManager.startStep(this); |
292 |
|
|
293 |
2 |
XWikiDocument childDocument = wiki.getDocument(childReference, context); |
294 |
2 |
childDocument.setParentReference(newParentReference); |
295 |
|
|
296 |
2 |
wiki.saveDocument(childDocument, "Updated parent field.", true, context); |
297 |
|
} |
298 |
|
|
299 |
5 |
if (childReferences.size() > 0) { |
300 |
1 |
this.logger.info("Document parent fields updated from [{}] to [{}] for [{}] documents.", |
301 |
|
oldParentReference, newParentReference, childReferences.size()); |
302 |
|
} |
303 |
|
} catch (Exception e) { |
304 |
0 |
this.logger.error("Failed to update the document parent fields from [{}] to [{}].", oldParentReference, |
305 |
|
newParentReference, e); |
306 |
0 |
return false; |
307 |
|
} finally { |
308 |
5 |
if (popLevelProgress) { |
309 |
1 |
this.progressManager.popLevelProgress(this); |
310 |
|
} |
311 |
|
} |
312 |
|
|
313 |
5 |
return true; |
314 |
|
} |
315 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (4) |
Complexity: 1 |
Complexity Density: 0.25 |
|
316 |
39 |
@Override... |
317 |
|
public DocumentReference setContextUserReference(DocumentReference userReference) |
318 |
|
{ |
319 |
39 |
XWikiContext context = xcontextProvider.get(); |
320 |
39 |
DocumentReference previousUserReference = context.getUserReference(); |
321 |
39 |
context.setUserReference(userReference); |
322 |
39 |
return previousUserReference; |
323 |
|
} |
324 |
|
|
|
|
| 92.3% |
Uncovered Elements: 2 (26) |
Complexity: 7 |
Complexity Density: 0.39 |
|
325 |
8 |
@Override... |
326 |
|
public void update(DocumentReference documentReference, Map<String, String> parameters) |
327 |
|
{ |
328 |
8 |
try { |
329 |
8 |
XWikiContext context = xcontextProvider.get(); |
330 |
8 |
XWiki wiki = context.getWiki(); |
331 |
8 |
XWikiDocument document = wiki.getDocument(documentReference, context); |
332 |
8 |
boolean save = false; |
333 |
|
|
334 |
8 |
String title = parameters.get("title"); |
335 |
8 |
if (title != null && !title.equals(document.getTitle())) { |
336 |
1 |
document.setTitle(title); |
337 |
1 |
save = true; |
338 |
|
} |
339 |
|
|
340 |
|
|
341 |
|
|
342 |
|
|
343 |
|
|
344 |
|
|
345 |
|
|
346 |
|
|
347 |
|
|
348 |
8 |
if (!parentChildConfiguration.isParentChildMechanismEnabled()) { |
349 |
7 |
DocumentReference hierarchicalParent = getHierarchicalParent(documentReference); |
350 |
7 |
if (!hierarchicalParent.equals(document.getParentReference())) { |
351 |
7 |
document.setParentReference(hierarchicalParent); |
352 |
7 |
save = true; |
353 |
|
} |
354 |
|
} |
355 |
|
|
356 |
8 |
if (save) { |
357 |
7 |
wiki.saveDocument(document, "Update document after refactoring.", true, context); |
358 |
7 |
this.logger.info("Document [{}] has been updated.", documentReference); |
359 |
|
} |
360 |
|
} catch (Exception e) { |
361 |
0 |
this.logger.error("Failed to update the document [{}] after refactoring.", documentReference, e); |
362 |
|
} |
363 |
|
} |
364 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (12) |
Complexity: 5 |
Complexity Density: 0.62 |
|
365 |
7 |
private DocumentReference getHierarchicalParent(DocumentReference documentReference)... |
366 |
|
{ |
367 |
7 |
final String spaceHomePage = entityReferenceProvider.getDefaultReference(EntityType.DOCUMENT).getName(); |
368 |
|
|
369 |
7 |
EntityReference parentOfTheSpace = documentReference.getLastSpaceReference().getParent(); |
370 |
|
|
371 |
7 |
boolean pageIsNotTerminal = documentReference.getName().equals(spaceHomePage); |
372 |
|
|
373 |
|
|
374 |
|
|
375 |
7 |
if (pageIsNotTerminal && parentOfTheSpace.getType() == EntityType.SPACE) { |
376 |
3 |
return new DocumentReference(spaceHomePage, new SpaceReference(parentOfTheSpace)); |
377 |
|
} |
378 |
|
|
379 |
|
|
380 |
|
|
381 |
4 |
if (pageIsNotTerminal && parentOfTheSpace.getType() == EntityType.WIKI) { |
382 |
1 |
return new DocumentReference(spaceHomePage, new SpaceReference( |
383 |
|
entityReferenceProvider.getDefaultReference(EntityType.SPACE).getName(), |
384 |
|
documentReference.getWikiReference())); |
385 |
|
} |
386 |
|
|
387 |
|
|
388 |
|
|
389 |
3 |
return new DocumentReference(spaceHomePage, documentReference.getLastSpaceReference()); |
390 |
|
} |
391 |
|
} |