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

File Utils.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

30
100
23
2
455
242
43
0.43
4.35
11.5
1.87

Classes

Class Line # Actions
Utils 59 98 0% 41 16
0.8926174689.3%
Utils.EncodedElement 67 2 0% 2 4
0.00%
 

Contributing tests

This file is covered by 57 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.rest.internal;
21   
22    import java.net.URI;
23    import java.util.ArrayList;
24    import java.util.Collections;
25    import java.util.List;
26   
27    import javax.ws.rs.core.UriBuilder;
28   
29    import org.apache.commons.httpclient.URIException;
30    import org.apache.commons.httpclient.util.URIUtil;
31    import org.apache.commons.lang3.StringUtils;
32    import org.xwiki.component.manager.ComponentLookupException;
33    import org.xwiki.component.manager.ComponentManager;
34    import org.xwiki.context.Execution;
35    import org.xwiki.model.EntityType;
36    import org.xwiki.model.reference.DocumentReference;
37    import org.xwiki.model.reference.DocumentReferenceResolver;
38    import org.xwiki.model.reference.EntityReference;
39    import org.xwiki.model.reference.EntityReferenceSerializer;
40    import org.xwiki.model.reference.SpaceReference;
41    import org.xwiki.model.reference.SpaceReferenceResolver;
42    import org.xwiki.model.reference.WikiReference;
43    import org.xwiki.query.QueryFilter;
44    import org.xwiki.query.internal.NoOpQueryFilter;
45   
46    import com.xpn.xwiki.XWikiContext;
47    import com.xpn.xwiki.XWikiException;
48    import com.xpn.xwiki.api.Document;
49    import com.xpn.xwiki.doc.XWikiDocument;
50    import com.xpn.xwiki.objects.BaseObject;
51    import com.xpn.xwiki.user.api.XWikiRightService;
52    import com.xpn.xwiki.user.api.XWikiUser;
53   
54    /**
55    * A class containing utility methods used in the REST subsystem.
56    *
57    * @version $Id: ce3529ef759cbfbecc77ceae116ac1f0a326a858 $
58    */
 
59    public class Utils
60    {
61    /**
62    * Use to indicate the element is already encoded.
63    *
64    * @since 8.0
65    * @version $Id: ce3529ef759cbfbecc77ceae116ac1f0a326a858 $
66    */
 
67    public class EncodedElement
68    {
69    private String encodedElement;
70   
 
71  0 toggle public EncodedElement(String encodedElement)
72    {
73  0 this.encodedElement = encodedElement;
74    }
75   
 
76  0 toggle @Override
77    public String toString()
78    {
79  0 return this.encodedElement;
80    }
81    }
82   
83    /**
84    * Get the page id given its components.
85    *
86    * @param wikiName
87    * @param spaceName
88    * @param pageName
89    * @return The page id.
90    */
 
91  284 toggle public static String getPageId(String wikiName, List<String> spaceName, String pageName)
92    {
93  284 EntityReferenceSerializer<String> serializer =
94    com.xpn.xwiki.web.Utils.getComponent(EntityReferenceSerializer.TYPE_STRING);
95  284 return serializer.serialize(new DocumentReference(wikiName, spaceName, pageName));
96    }
97   
98    /**
99    * @param spaces the space hierarchy
100    * @param wikiName the name of the wiki
101    * @return the space reference
102    */
 
103  155 toggle public static SpaceReference getSpaceReference(List<String> spaces, String wikiName)
104    {
105  155 EntityReference parentReference = new WikiReference(wikiName);
106  155 SpaceReference spaceReference = null;
107   
108  155 for (String space : spaces) {
109  165 spaceReference = new SpaceReference(space, parentReference);
110  165 parentReference = spaceReference;
111    }
112   
113  155 return spaceReference;
114    }
115   
 
116  73 toggle public static String getLocalSpaceId(List<String> spaces)
117    {
118  73 EntityReferenceSerializer<String> serializer =
119    com.xpn.xwiki.web.Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, "local");
120    // The wiki name cannot be not empty in a space reference, but its value has no importance since the local
121    // serializer does not use it
122    // TODO: create a LocalSpaceReference class instead
123  73 return serializer.serialize(getSpaceReference(spaces, "whatever"));
124    }
125   
126    /**
127    * @param wikiName the name of the wiki that contains the space
128    * @param spaces the spaces hierarchy
129    * @return the space id
130    * @throws org.xwiki.rest.XWikiRestException
131    */
 
132  82 toggle public static String getSpaceId(String wikiName, List<String> spaces)
133    {
134  82 EntityReferenceSerializer<String> defaultEntityReferenceSerializer =
135    com.xpn.xwiki.web.Utils.getComponent(EntityReferenceSerializer.TYPE_STRING);
136  82 SpaceReference spaceReference = getSpaceReference(spaces, wikiName);
137  82 return defaultEntityReferenceSerializer.serialize(spaceReference);
138    }
139   
 
140  2291 toggle public static SpaceReference resolveLocalSpaceId(String spaceId, String wikiName)
141    {
142  2291 SpaceReferenceResolver<String> resolver =
143    com.xpn.xwiki.web.Utils.getComponent(SpaceReferenceResolver.TYPE_STRING);
144  2291 return resolver.resolve(spaceId, new WikiReference(wikiName));
145    }
146   
 
147  2291 toggle public static List<String> getSpacesFromSpaceId(String spaceId)
148    {
149  2291 return getSpacesHierarchy(resolveLocalSpaceId(spaceId, "whatever"));
150    }
151   
 
152  2296 toggle public static List<String> getSpacesHierarchy(SpaceReference spaceReference)
153    {
154  2296 List<String> spaces = new ArrayList<>();
155  4810 for(EntityReference ref = spaceReference; ref != null && ref.getType() == EntityType.SPACE;
156    ref = ref.getParent()) {
157  2514 spaces.add(ref.getName());
158    }
159  2296 Collections.reverse(spaces);
160  2296 return spaces;
161    }
162   
163    /**
164    * Get the page full name given its components.
165    *
166    * @param wikiName
167    * @param spaces
168    * @param pageName
169    * @return The page full name.
170    */
 
171  9 toggle public static String getPageFullName(String wikiName, List<String> spaces, String pageName)
172    {
173  9 XWikiDocument xwikiDocument = new XWikiDocument(new DocumentReference(wikiName, spaces, pageName));
174   
175  9 Document document = new Document(xwikiDocument, null);
176   
177  9 return document.getFullName();
178    }
179   
180    /**
181    * Get the object id given its components.
182    *
183    * @param wikiName
184    * @param spaces
185    * @param pageName
186    * @param className
187    * @param objectNumber
188    * @return The object id.
189    */
 
190  1 toggle public static String getObjectId(String wikiName, List<String> spaces, String pageName, String className,
191    int objectNumber)
192    {
193  1 XWikiDocument xwikiDocument = new XWikiDocument(new DocumentReference(wikiName, spaces, pageName));
194   
195  1 Document document = new Document(xwikiDocument, null);
196   
197  1 return String.format("%s:%s[%d]", document.getPrefixedFullName(), className, objectNumber);
198    }
199   
200    /**
201    * Get the page id given its components.
202    *
203    * @return The page id.
204    */
 
205  3 toggle public static String getPageId(String wikiName, String pageFullName)
206    {
207  3 DocumentReferenceResolver<String> defaultDocumentReferenceResolver =
208    com.xpn.xwiki.web.Utils.getComponent(DocumentReferenceResolver.TYPE_STRING);
209   
210  3 DocumentReference documentReference =
211    defaultDocumentReferenceResolver.resolve(pageFullName, new WikiReference(wikiName));
212  3 XWikiDocument xwikiDocument = new XWikiDocument(documentReference);
213   
214  3 Document document = new Document(xwikiDocument, null);
215   
216  3 return document.getPrefixedFullName();
217    }
218   
219    /**
220    * Get parent document for a given document.
221    *
222    * @param doc document to get the parent from.
223    * @param xwikiApi the xwiki api.
224    * @return parent of the given document, null if none is specified.
225    * @throws XWikiException if getting the parent document has failed.
226    */
 
227  134 toggle public static Document getParentDocument(Document doc, com.xpn.xwiki.api.XWiki xwikiApi) throws XWikiException
228    {
229  134 if (StringUtils.isEmpty(doc.getParent())) {
230  124 return null;
231    }
232    /*
233    * This is ugly but we have to mimic the behavior of link generation: if the parent does not specify its space,
234    * use the current document space.
235    */
236  10 String parentName = doc.getParent();
237  10 if (!parentName.contains(".")) {
238  0 parentName = doc.getSpace() + "." + parentName;
239    }
240  10 return xwikiApi.getDocument(parentName);
241    }
242   
243    /**
244    * Retrieve the XWiki context from the current execution context.
245    *
246    * @param componentManager The component manager to be used to retrieve the execution context.
247    * @return The XWiki context.
248    * @throws RuntimeException If there was an error retrieving the context.
249    */
 
250  11458 toggle public static XWikiContext getXWikiContext(ComponentManager componentManager)
251    {
252  11458 Execution execution;
253  11458 XWikiContext xwikiContext;
254  11458 try {
255  11458 execution = componentManager.getInstance(Execution.class);
256  11458 xwikiContext = (XWikiContext) execution.getContext().getProperty("xwikicontext");
257  11458 return xwikiContext;
258    } catch (Exception e) {
259  0 throw new RuntimeException("Unable to get XWiki context", e);
260    }
261    }
262   
263    /**
264    * Retrieve the XWiki private API object.
265    *
266    * @param componentManager The component manager to be used to retrieve the execution context.
267    * @return The XWiki private API object.
268    */
 
269  4014 toggle public static com.xpn.xwiki.XWiki getXWiki(ComponentManager componentManager)
270    {
271  4014 return getXWikiContext(componentManager).getWiki();
272    }
273   
274    /**
275    * Retrieve the XWiki public API object.
276    *
277    * @param componentManager The component manager to be used to retrieve the execution context.
278    * @return The XWiki public API object.
279    * @throws RuntimeException If there was an error while initializing the XWiki public API object.
280    */
 
281  2045 toggle public static com.xpn.xwiki.api.XWiki getXWikiApi(ComponentManager componentManager)
282    {
283  2045 return new com.xpn.xwiki.api.XWiki(getXWiki(componentManager), getXWikiContext(componentManager));
284    }
285   
286    /**
287    * Retrieve the XWiki user associated to the current XWiki context.
288    *
289    * @param componentManager The component manager to be used to retrieve the execution context.
290    * @return The user associated to the current XWiki context.
291    */
 
292  1703 toggle public static String getXWikiUser(ComponentManager componentManager)
293    {
294  1703 XWikiUser user = getXWikiContext(componentManager).getXWikiUser();
295  1703 if (user == null) {
296  840 return XWikiRightService.GUEST_USER_FULLNAME;
297    }
298   
299  863 return user.getUser();
300    }
301   
302    /**
303    * Retrieve the XWiki private API object.
304    *
305    * @param componentManager The component manager to be used to retrieve the execution context.
306    * @return The XWiki private API object.
307    */
 
308  0 toggle public static String getAuthorName(DocumentReference authorReference, ComponentManager componentManager)
309    {
310  0 return getXWikiContext(componentManager).getWiki().getPlainUserName(authorReference,
311    getXWikiContext(componentManager));
312    }
313   
314    /**
315    * Retrieve the BaseObject from the Document.
316    *
317    * @param doc Public API document
318    * @param className Classname
319    * @param objectNumber Object Number
320    * @return The BaseObject field
321    * @throws XWikiException
322    */
 
323  0 toggle public static BaseObject getBaseObject(Document doc, String className, int objectNumber,
324    ComponentManager componentManager) throws XWikiException
325    {
326  0 XWikiDocument xwikiDocument =
327    Utils.getXWiki(componentManager).getDocument(doc.getPrefixedFullName(),
328    Utils.getXWikiContext(componentManager));
329   
330  0 return xwikiDocument.getObject(className, objectNumber);
331    }
332   
333    /**
334    * Creates an URI to access the specified resource. The given path elements are encoded before being inserted into
335    * the resource path.
336    * <p>
337    * NOTE: We added this method because {@link UriBuilder#build(Object...)} doesn't encode all special characters. See
338    * https://github.com/restlet/restlet-framework-java/issues/601 .
339    *
340    * @param baseURI the base URI
341    * @param resourceClass the resource class, used to get the URI path
342    * @param pathElements the path elements to insert in the resource path
343    * @return an URI that can be used to access the specified resource
344    */
 
345  14603 toggle public static URI createURI(URI baseURI, java.lang.Class< ? > resourceClass, java.lang.Object... pathElements)
346    {
347  14603 UriBuilder uriBuilder = UriBuilder.fromUri(baseURI).path(resourceClass);
348   
349  14603 List<String> pathVariableNames = null;
350  14603 if (pathElements.length > 0) {
351    // uriBuilder.toString() returns the path (see AbstractUriBuilder#toString())
352    // but it means UriBuilder must use AbstractUriBuilder from restlet.
353    // TODO: find a more generic way to not depend heavily on restlet.
354  13815 pathVariableNames = getVariableNamesFromPathTemplate(uriBuilder.toString());
355    }
356   
357  14603 Object[] encodedPathElements = new String[pathElements.length];
358  52083 for (int i = 0; i < pathElements.length; i++) {
359  37480 Object pathElement = pathElements[i];
360  37480 if (pathElement != null) {
361  37480 try {
362    // see generateEncodedSpacesURISegment() to understand why we manually handle "spaceName"
363  37480 if (i < pathVariableNames.size() && "spaceName".equals(pathVariableNames.get(i))) {
364  3469 if (!(pathElement instanceof List)) {
365  0 throw new RuntimeException("The 'spaceName' parameter must be a list!");
366    }
367  3469 encodedPathElements[i] = generateEncodedSpacesURISegment((List) pathElements[i]);
368  34011 } else if (pathElement instanceof EncodedElement) {
369  0 encodedPathElements[i] = pathElement.toString();
370    } else {
371  34011 encodedPathElements[i] = URIUtil.encodePath(pathElement.toString());
372    }
373    } catch (URIException e) {
374  0 throw new RuntimeException("Failed to encode path element: " + pathElements[i], e);
375    }
376    } else {
377  0 encodedPathElements[i] = null;
378    }
379    }
380  14603 return uriBuilder.buildFromEncoded(encodedPathElements);
381    }
382   
383    /**
384    * Parse a path template to find variables:
385    * e.g. with "/wikis/{wikiName}/spaces/{spaceName}/" it returns ['wikiName', 'spaceName'].
386    * @param pathTemplate the path template (from the resource)
387    * @return the list of variable names
388    */
 
389  13815 toggle private static List<String> getVariableNamesFromPathTemplate(String pathTemplate)
390    {
391  13815 List<String> variables = new ArrayList<>();
392   
393  13815 boolean inVariable = false;
394  13815 StringBuilder varName = new StringBuilder();
395   
396    // Parse the whole string
397  1222393 for (int i = 0; i < pathTemplate.length(); ++i) {
398  1208578 char c = pathTemplate.charAt(i);
399  1208578 if (inVariable) {
400  382364 if (c == '}') {
401  37478 variables.add(varName.toString());
402    // we clear the varName buffer
403  37478 varName.delete(0, varName.length());
404  37478 inVariable = false;
405    } else {
406  344886 varName.append(c);
407    }
408  826214 } else if (c == '{') {
409  37478 inVariable = true;
410    }
411    }
412   
413  13815 return variables;
414    }
415   
416    /**
417    * Generate an encoded segment for the 'spaceName' parameter of a resource URL.
418    *
419    * Using UriBuilder is an elegant way to generate a REST URL for a jax-rs resource. It takes the path from the
420    * resource (described with the @Path annotation) and fill the variable parts. However, we have introduced a special
421    * syntax for nested spaces (with /spaces/A/spaces/B, etc...) that is not supported by jax-rs. So we manually handle
422    * the spaceName part of the URL.
423    *
424    * @param spaces the list of spaces of the resource
425    * @return the encoded spaces segment of the URL
426    * @throws URIException if problems occur
427    */
 
428  3469 toggle private static String generateEncodedSpacesURISegment(List<Object> spaces) throws URIException
429    {
430  3469 StringBuilder spaceSegment = new StringBuilder();
431  3469 for (Object space : spaces) {
432  3992 if (spaceSegment.length() > 0) {
433  523 spaceSegment.append("/spaces/");
434    }
435  3992 spaceSegment.append(URIUtil.encodePath(space.toString()));
436    }
437  3469 return spaceSegment.toString();
438    }
439   
440    /**
441    * @param componentManager the component manager to be used to retrieve the hidden query filter
442    * @return the hidden query filter or a NoOp filter if the hidden filter isn't found
443    */
 
444  7 toggle public static QueryFilter getHiddenQueryFilter(ComponentManager componentManager)
445    {
446  7 QueryFilter filter;
447  7 try {
448  7 filter = componentManager.getInstance(QueryFilter.class, "hidden");
449    } catch (ComponentLookupException e) {
450    // They hidden filter is not available at runtime, don't use it
451  0 filter = new NoOpQueryFilter();
452    }
453  7 return filter;
454    }
455    }