1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.search.solr.script

File SolrIndexScriptService.java

 

Coverage histogram

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

Code metrics

6
50
13
1
327
149
23
0.46
3.85
13
1.77

Classes

Class Line # Actions
SolrIndexScriptService 57 50 0% 23 6
0.913043591.3%
 

Contributing tests

This file is covered by 10 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.search.solr.script;
21   
22    import java.util.HashSet;
23    import java.util.List;
24    import java.util.Set;
25   
26    import javax.inject.Inject;
27    import javax.inject.Named;
28    import javax.inject.Provider;
29    import javax.inject.Singleton;
30   
31    import org.apache.solr.common.SolrDocument;
32    import org.slf4j.Logger;
33    import org.xwiki.component.annotation.Component;
34    import org.xwiki.model.EntityType;
35    import org.xwiki.model.reference.DocumentReference;
36    import org.xwiki.model.reference.DocumentReferenceResolver;
37    import org.xwiki.model.reference.EntityReference;
38    import org.xwiki.model.reference.EntityReferenceResolver;
39    import org.xwiki.script.service.ScriptService;
40    import org.xwiki.search.solr.internal.api.FieldUtils;
41    import org.xwiki.search.solr.internal.api.SolrIndexer;
42    import org.xwiki.security.authorization.AuthorizationManager;
43    import org.xwiki.security.authorization.Right;
44   
45    import com.xpn.xwiki.XWikiContext;
46   
47    /**
48    * Script service exposing interaction with the {@link SolrIndexer}. Queries on the index are performed using XWiki's <a
49    * href="http://extensions.xwiki.org/xwiki/bin/view/Extension/Query+Module">Query Module API</a> with query type "solr".
50    *
51    * @version $Id: 6b53e96a9e24a0523b63e4d85154337562acdcf7 $
52    * @since 4.3M2
53    */
54    @Component
55    @Named("solr")
56    @Singleton
 
57    public class SolrIndexScriptService implements ScriptService
58    {
59    /**
60    * Field name of the last API exception inserted in context.
61    */
62    public static final String CONTEXT_LASTEXCEPTION = "lastexception";
63   
64    /**
65    * Logging framework.
66    */
67    @Inject
68    private Logger logger;
69   
70    /**
71    * Wrapped {@link SolrIndex} component.
72    */
73    @Inject
74    private SolrIndexer solrIndexer;
75   
76    /**
77    * Used to check rights.
78    */
79    @Inject
80    private AuthorizationManager authorization;
81   
82    /**
83    * Used to access the current {@link XWikiContext}.
84    */
85    @Inject
86    private Provider<XWikiContext> xcontextProvider;
87   
88    /**
89    * Used to extract a {@link DocumentReference} from a {@link SolrDocument}.
90    */
91    @Inject
92    private DocumentReferenceResolver<SolrDocument> solrDocumentReferenceResolver;
93   
94    /**
95    * Used to extract an {@link EntityReference} from a {@link SolrDocument}.
96    */
97    @Inject
98    private EntityReferenceResolver<SolrDocument> solrEntityReferenceResolver;
99   
100    /**
101    * Index an entity and all it's contained entities recursively.
102    * <p>
103    * Null reference means the whole farm.
104    *
105    * @param reference the reference to index.
106    */
 
107  4 toggle public void index(EntityReference reference)
108    {
109  4 clearException();
110   
111  4 try {
112  4 checkAccessToWikiIndex(reference);
113   
114  2 this.solrIndexer.index(reference, true);
115    } catch (Exception e) {
116  2 error(e);
117    }
118    }
119   
120    /**
121    * Index multiple entities and all their contained entities recursively. This is a batch operation.
122    * <p>
123    * Null reference means the whole farm.
124    *
125    * @param references the references to index.
126    */
 
127  3 toggle public void index(List<EntityReference> references)
128    {
129  3 clearException();
130   
131  3 try {
132  3 checkAccessToWikiIndex(references);
133   
134  3 for (EntityReference reference : references) {
135  10 this.solrIndexer.index(reference, true);
136    }
137    } catch (Exception e) {
138  0 error(e);
139    }
140    }
141   
142    /**
143    * Delete an indexed entity and all its contained entities recursively.
144    * <p>
145    * Null reference means the whole farm.
146    *
147    * @param reference the reference to delete from the index.
148    */
 
149  1 toggle public void delete(EntityReference reference)
150    {
151  1 clearException();
152   
153  1 try {
154  1 checkAccessToWikiIndex(reference);
155   
156  1 this.solrIndexer.delete(reference, true);
157    } catch (Exception e) {
158  0 error(e);
159    }
160    }
161   
162    /**
163    * Delete multiple entities and all their contained entities recursively. This is a batch operation.
164    * <p>
165    * Null reference means the whole farm.
166    *
167    * @param references the references to delete from the index.
168    */
 
169  1 toggle public void delete(List<EntityReference> references)
170    {
171  1 clearException();
172   
173  1 try {
174  1 checkAccessToWikiIndex(references);
175   
176  1 for (EntityReference reference : references) {
177  1 this.solrIndexer.delete(reference, true);
178    }
179    } catch (Exception e) {
180  0 error(e);
181    }
182    }
183   
184    /**
185    * @return the size of the index/delete queue
186    * @since 5.1RC1
187    */
 
188  4821 toggle public int getQueueSize()
189    {
190  4821 return this.solrIndexer.getQueueSize();
191    }
192   
193    /**
194    * Extract a {@link DocumentReference} from the given {@link SolrDocument} (e.g. search result).
195    *
196    * @param document the {@link SolrDocument} to extract the {@link DocumentReference} from
197    * @param parameters the parameters to pass to the reference resolver (e.g. in case some reference components are
198    * missing)
199    * @return the reference to the document associated with the given {@link SolrDocument}
200    * @since 7.2RC1
201    */
 
202  0 toggle public DocumentReference resolveDocument(SolrDocument document, Object... parameters)
203    {
204  0 return this.solrDocumentReferenceResolver.resolve(document, parameters);
205    }
206   
207    /**
208    * Extract an {@link EntityReference} from the given {@link SolrDocument} (e.g. search result). The entity type is
209    * inferred from the "type" field which must be specified and must have a valid value (that corresponds to an
210    * existing {@link EntityType}).
211    *
212    * @param document a {@link SolrDocument} to extract the {@link EntityReference} from (the "type" field must be
213    * specified)
214    * @param parameters the parameters to pass to the reference resolver (e.g. in case some reference components are
215    * missing)
216    * @return the reference to the entity associated with the given {@link SolrDocument}
217    * @since 7.2RC1
218    */
 
219  3 toggle public EntityReference resolve(SolrDocument document, Object... parameters)
220    {
221  3 EntityType type;
222  3 try {
223  3 type = EntityType.valueOf((String) document.get(FieldUtils.TYPE));
224    } catch (IllegalArgumentException e) {
225  1 return null;
226    } catch (NullPointerException e) {
227  1 return null;
228    }
229   
230  1 return resolve(document, type, parameters);
231    }
232   
233    /**
234    * Extract an {@link EntityReference} of the specified type from the given {@link SolrDocument} (e.g. search
235    * result).
236    *
237    * @param document a {@link SolrDocument} to extract the {@link EntityReference} from
238    * @param type the entity type
239    * @param parameters the parameters to pass to the reference resolver (e.g. in case some reference components are
240    * missing)
241    * @return the reference to the entity associated with the given {@link SolrDocument}
242    * @since 7.2RC1
243    */
 
244  1 toggle public EntityReference resolve(SolrDocument document, EntityType type, Object... parameters)
245    {
246  1 return this.solrEntityReferenceResolver.resolve(document, type, parameters);
247    }
248   
249    /**
250    * Log exception and store the exception in the context.
251    *
252    * @param errorMessage the error message to log.
253    * @param e the caught exception.
254    * @see #CONTEXT_LASTEXCEPTION
255    */
 
256  2 toggle private void error(String errorMessage, Exception e)
257    {
258  2 String errorMessageToLog = errorMessage;
259  2 if (errorMessageToLog == null) {
260  2 errorMessageToLog = e.getMessage();
261    }
262   
263  2 this.logger.error(errorMessageToLog, e);
264   
265  2 this.xcontextProvider.get().put(CONTEXT_LASTEXCEPTION, e);
266    }
267   
268    /**
269    * Log exception and store it in the context. The logged message is the exception's message. This allows the
270    * underlying component to define it's messages and removes duplication.
271    *
272    * @param e the caught exception
273    */
 
274  2 toggle private void error(Exception e)
275    {
276  2 error(null, e);
277    }
278   
279    /**
280    * Clear the last exception from the context.
281    */
 
282  9 toggle private void clearException()
283    {
284  9 this.xcontextProvider.get().remove(CONTEXT_LASTEXCEPTION);
285    }
286   
287    /**
288    * Check the current user's access to alter the index of the wiki owning the given referenced entity.
289    *
290    * @param reference the reference whose owning wiki to check.
291    * @throws IllegalAccessException if the user is not allowed or if problems occur.
292    */
 
293  11 toggle private void checkAccessToWikiIndex(EntityReference reference) throws IllegalAccessException
294    {
295  11 EntityReference wikiReference = reference.extractReference(EntityType.WIKI);
296   
297  11 XWikiContext xcontext = this.xcontextProvider.get();
298   
299  11 DocumentReference userReference = xcontext.getUserReference();
300  11 DocumentReference programmingUserReference = xcontext.getDoc().getContentAuthorReference();
301   
302  11 if (!this.authorization.hasAccess(Right.ADMIN, userReference, wikiReference)
303    || !this.authorization.hasAccess(Right.PROGRAM, programmingUserReference, wikiReference)) {
304  2 throw new IllegalAccessException(String.format(
305    "The user '%s' is not allowed to alter the index for the entity '%s'", userReference, reference));
306    }
307    }
308   
309    /**
310    * Check the current user's access to alter the index of the wikis owning the given referenced entities.
311    *
312    * @param references the references whose owning wikis to check.
313    * @throws IllegalAccessException if the user is not allowed for at least one of the passed references or if
314    * problems occur.
315    */
 
316  4 toggle private void checkAccessToWikiIndex(List<EntityReference> references) throws IllegalAccessException
317    {
318  4 Set<EntityReference> representatives = new HashSet<EntityReference>();
319  4 for (EntityReference reference : references) {
320  11 EntityReference wikiReference = reference.extractReference(EntityType.WIKI);
321  11 if (!representatives.contains(wikiReference)) {
322  6 checkAccessToWikiIndex(wikiReference);
323  6 representatives.add(wikiReference);
324    }
325    }
326    }
327    }