1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.refactoring.internal.job

File AbstractEntityJob.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

26
57
14
2
268
163
29
0.51
4.07
7
2.07

Classes

Class Line # Actions
AbstractEntityJob 52 57 0% 29 7
0.9278350592.8%
AbstractEntityJob.Visitor 61 0 - 0 0
-1.0 -
 

Contributing tests

This file is covered by 37 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.refactoring.internal.job;
21   
22    import java.util.Collection;
23   
24    import javax.inject.Inject;
25   
26    import org.xwiki.job.AbstractJob;
27    import org.xwiki.job.GroupedJob;
28    import org.xwiki.job.JobGroupPath;
29    import org.xwiki.job.Request;
30    import org.xwiki.model.EntityType;
31    import org.xwiki.model.reference.DocumentReference;
32    import org.xwiki.model.reference.EntityReference;
33    import org.xwiki.model.reference.EntityReferenceProvider;
34    import org.xwiki.model.reference.EntityReferenceTree;
35    import org.xwiki.model.reference.EntityReferenceTreeNode;
36    import org.xwiki.model.reference.SpaceReference;
37    import org.xwiki.refactoring.internal.ModelBridge;
38    import org.xwiki.refactoring.job.EntityJobStatus;
39    import org.xwiki.refactoring.job.EntityRequest;
40    import org.xwiki.refactoring.job.RefactoringJobs;
41    import org.xwiki.security.authorization.AuthorizationManager;
42    import org.xwiki.security.authorization.Right;
43   
44    /**
45    * Abstract job that targets multiple entities.
46    *
47    * @param <R> the request type
48    * @param <S> the job status type
49    * @version $Id: 29abf593307444d312674759a0f4ccc3cd8d7ce9 $
50    * @since 7.2M1
51    */
 
52    public abstract class AbstractEntityJob<R extends EntityRequest, S extends EntityJobStatus<? super R>> extends
53    AbstractJob<R, S> implements GroupedJob
54    {
55    /**
56    * Generic interface used to implement the Visitor pattern.
57    *
58    * @param <T> the type of nodes that are visited
59    * @version $Id: 29abf593307444d312674759a0f4ccc3cd8d7ce9 $
60    */
 
61    public interface Visitor<T>
62    {
63    /**
64    * Visit the given node.
65    *
66    * @param node the node to visit
67    */
68    void visit(T node);
69    }
70   
71    private static final JobGroupPath ROOT_GROUP = new JobGroupPath(RefactoringJobs.GROUP, null);
72   
73    private static final String PREFERENCES_DOCUMENT_NAME = "WebPreferences";
74   
75    /**
76    * The component used to access the XWiki model and to perform low level operations on it.
77    */
78    @Inject
79    protected ModelBridge modelBridge;
80   
81    /**
82    * Specifies the group this job is part of. If all the entities involved in this operation are from the same wiki
83    * then this job is part of a group of refactoring jobs that run on that wiki (it will only block the refactoring
84    * jobs that run on that wiki). Otherwise, if there are at least two entities from different wikis then this job is
85    * part of the group of refactoring jobs that run at farm level.
86    */
87    private JobGroupPath groupPath;
88   
89    /**
90    * Used to check access permissions.
91    *
92    * @see #hasAccess(Right, EntityReference)
93    */
94    @Inject
95    private AuthorizationManager authorization;
96   
97    /**
98    * Used to distinguish the space home page.
99    *
100    * @see #isSpaceHomeReference(DocumentReference)
101    */
102    @Inject
103    private EntityReferenceProvider defaultEntityReferenceProvider;
104   
 
105  41 toggle @Override
106    public JobGroupPath getGroupPath()
107    {
108  41 return this.groupPath;
109    }
110   
 
111  79 toggle @Override
112    public void initialize(Request request)
113    {
114  79 super.initialize(request);
115   
116    // Build the job group path.
117  79 String targetWiki = getTargetWiki();
118  79 if (targetWiki != null) {
119  69 this.groupPath = new JobGroupPath(targetWiki, ROOT_GROUP);
120    } else {
121  10 this.groupPath = ROOT_GROUP;
122    }
123    }
124   
 
125  75 toggle @Override
126    protected void runInternal() throws Exception
127    {
128  75 Collection<EntityReference> entityReferences = this.request.getEntityReferences();
129  75 if (entityReferences != null) {
130    // Set the context user before executing the job. We don't have to restore the previous context user when
131    // the job is finished because jobs are normally executed in a separate thread, with a separate execution
132    // context.
133  75 this.modelBridge.setContextUserReference(this.request.getUserReference());
134  75 process(entityReferences);
135    }
136    }
137   
 
138  67 toggle protected void process(Collection<EntityReference> entityReferences)
139    {
140  67 this.progressManager.pushLevelProgress(entityReferences.size(), this);
141   
142  67 try {
143  67 for (EntityReference entityReference : entityReferences) {
144  70 if (this.status.isCanceled()) {
145  0 break;
146    } else {
147  70 this.progressManager.startStep(this);
148  70 process(entityReference);
149    }
150    }
151    } finally {
152  67 this.progressManager.popLevelProgress(this);
153    }
154    }
155   
156    /**
157    * Process the specified entity.
158    *
159    * @param entityReference the entity to process
160    */
161    protected abstract void process(EntityReference entityReference);
162   
163    /**
164    * @return the wiki where the operation takes place, or {@code null} if the operation is cross wiki
165    */
 
166  58 toggle protected String getTargetWiki()
167    {
168  58 return getTargetWiki(this.request.getEntityReferences());
169    }
170   
171    /**
172    * @return the wiki name if all the given entity references are from the same wiki, {@code null} otherwise
173    */
 
174  79 toggle protected String getTargetWiki(Collection<EntityReference> entityReferences)
175    {
176  79 if (entityReferences == null) {
177  1 return null;
178    }
179   
180  78 String targetWiki = null;
181  78 for (EntityReference entityReference : entityReferences) {
182  106 EntityReference wikiReference = entityReference.extractReference(EntityType.WIKI);
183  106 if (wikiReference != null) {
184  106 if (targetWiki == null) {
185  77 targetWiki = wikiReference.getName();
186  29 } else if (!targetWiki.equals(wikiReference.getName())) {
187  8 return null;
188    }
189    } else {
190  0 return null;
191    }
192    }
193   
194  70 return targetWiki;
195    }
196   
 
197  74 toggle protected boolean hasAccess(Right right, EntityReference reference)
198    {
199  74 return !this.request.isCheckRights()
200    || this.authorization.hasAccess(right, this.request.getUserReference(), reference);
201    }
202   
 
203  33 toggle protected boolean isSpaceHomeReference(DocumentReference documentReference)
204    {
205  33 return documentReference.getName().equals(
206    this.defaultEntityReferenceProvider.getDefaultReference(documentReference.getType()).getName());
207    }
208   
 
209  37 toggle private boolean isSpacePreferencesReference(EntityReference entityReference)
210    {
211  37 return entityReference.getType() == EntityType.DOCUMENT
212    && PREFERENCES_DOCUMENT_NAME.equals(entityReference.getName());
213    }
214   
 
215  18 toggle protected void visitDocuments(SpaceReference spaceReference, Visitor<DocumentReference> visitor)
216    {
217  18 visitDocumentNodes(getDocumentReferenceTree(spaceReference), visitor);
218    }
219   
 
220  18 toggle private EntityReferenceTreeNode getDocumentReferenceTree(SpaceReference spaceReference)
221    {
222  18 return new EntityReferenceTree(this.modelBridge.getDocumentReferences(spaceReference)).get(spaceReference);
223    }
224   
 
225  55 toggle private void visitDocumentNodes(EntityReferenceTreeNode node, Visitor<DocumentReference> visitor)
226    {
227  55 EntityReference nodeReference = node.getReference();
228  47 EntityType nodeType = nodeReference != null ? nodeReference.getType() : null;
229  47 if (nodeType == EntityType.SPACE || nodeType == EntityType.WIKI || nodeType == null) {
230    // A node that corresponds to an entity that can contain documents.
231  22 visitDocumentAncestor(node, visitor);
232  25 } else if (nodeType == EntityType.DOCUMENT) {
233  25 visitor.visit((DocumentReference) node.getReference());
234    }
235    }
236   
 
237  22 toggle private void visitDocumentAncestor(EntityReferenceTreeNode node, Visitor<DocumentReference> visitor)
238    {
239  22 Collection<EntityReferenceTreeNode> children = node.getChildren();
240  22 this.progressManager.pushLevelProgress(children.size(), this);
241   
242  22 try {
243    // Visit the space preferences document at the end as otherwise we may loose the space access rights.
244  22 EntityReferenceTreeNode spacePreferencesNode = null;
245  22 for (EntityReferenceTreeNode child : children) {
246  37 if (isSpacePreferencesReference(child.getReference())) {
247  2 spacePreferencesNode = child;
248  2 continue;
249    }
250  35 visitDocumentAncestorStep(child, visitor);
251    }
252   
253  22 if (spacePreferencesNode != null) {
254  2 visitDocumentAncestorStep(spacePreferencesNode, visitor);
255    }
256    } finally {
257  22 this.progressManager.popLevelProgress(this);
258    }
259    }
260   
 
261  37 toggle private void visitDocumentAncestorStep(EntityReferenceTreeNode node, Visitor<DocumentReference> visitor)
262    {
263  37 this.progressManager.startStep(this);
264  37 if (!this.status.isCanceled()) {
265  37 visitDocumentNodes(node, visitor);
266    }
267    }
268    }