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

File AbstractEntityResourceReferenceResolver.java

 

Coverage histogram

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

Code metrics

24
60
4
1
232
134
20
0.33
15
4
5

Classes

Class Line # Actions
AbstractEntityResourceReferenceResolver 51 60 0% 20 3
0.9659090696.6%
 

Contributing tests

This file is covered by 6 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.url.internal.standard.entity;
21   
22    import java.util.ArrayList;
23    import java.util.Arrays;
24    import java.util.List;
25    import java.util.ListIterator;
26    import java.util.Map;
27   
28    import org.apache.commons.lang3.StringUtils;
29    import org.apache.commons.lang3.tuple.ImmutablePair;
30    import org.apache.commons.lang3.tuple.Pair;
31    import org.xwiki.model.EntityType;
32    import org.xwiki.model.reference.EntityReference;
33    import org.xwiki.model.reference.EntityReferenceResolver;
34    import org.xwiki.model.reference.WikiReference;
35    import org.xwiki.resource.CreateResourceReferenceException;
36    import org.xwiki.resource.ResourceType;
37    import org.xwiki.resource.UnsupportedResourceReferenceException;
38    import org.xwiki.resource.entity.EntityResourceAction;
39    import org.xwiki.resource.entity.EntityResourceReference;
40    import org.xwiki.resource.internal.entity.EntityResourceActionLister;
41    import org.xwiki.url.ExtendedURL;
42    import org.xwiki.url.internal.AbstractResourceReferenceResolver;
43    import org.xwiki.url.internal.standard.StandardURLConfiguration;
44   
45    /**
46    * Common code for Entity Resource Reference Resolvers.
47    *
48    * @version $Id: 62cc83834b04742d147f120cec267fa973ebbd59 $
49    * @since 6.3M1
50    */
 
51    public abstract class AbstractEntityResourceReferenceResolver extends AbstractResourceReferenceResolver
52    {
53    private static final String VIEW_ACTION = "view";
54   
55    private static final String DOWNLOAD_ACTION = "download";
56   
57    private static final String DELATTACHMENT_ACTION = "delattachment";
58   
59    private static final String VIEWATTACHREV_ACTION = "viewattachrev";
60   
61    private static final String DOWNLOADREV_ACTION = "downloadrev";
62   
63    /**
64    * @TODO: Remove when http://jira.xwiki.org/browse/XWIKI-12449 is implemented
65    */
66    private static final String SKIN_ACTION = "skin";
67   
68    /**
69    * List of Actions which use URLs of the format {@code /(actionname)/space1/space2/page/filename}.
70    */
71    private static final List<String> FILE_ACTION_LIST =
72    Arrays.asList(DOWNLOAD_ACTION, DELATTACHMENT_ACTION, VIEWATTACHREV_ACTION, DOWNLOADREV_ACTION, SKIN_ACTION);
73   
74    private StandardURLConfiguration configuration;
75   
76    private EntityResourceActionLister entityResourceActionLister;
77   
78    /**
79    * Used to resolve blanks in entity references when the URL doesn't specify all parts of an entity reference.
80    */
81    private EntityReferenceResolver<EntityReference> defaultReferenceEntityReferenceResolver;
82   
83    protected abstract WikiReference extractWikiReference(ExtendedURL url);
84   
 
85  21125 toggle @Override
86    public EntityResourceReference resolve(ExtendedURL extendedURL, ResourceType type, Map<String, Object> parameters)
87    throws CreateResourceReferenceException, UnsupportedResourceReferenceException
88    {
89  21129 EntityResourceReference reference = null;
90   
91    // Extract the wiki reference from the URL
92  21117 WikiReference wikiReference = extractWikiReference(extendedURL);
93   
94    // See BinEntityResourceReferenceResolverTest to check the various cases supported.
95   
96  21108 List<String> pathSegments = extendedURL.getSegments();
97  21114 List<String> spaceNames = null;
98  21121 String pageName = null;
99  21115 String attachmentName = null;
100  21109 String action = VIEW_ACTION;
101   
102  21109 if (pathSegments.size() != 0) {
103  21083 String firstSegment = pathSegments.get(0);
104  21091 action = firstSegment;
105    // Generic parsing
106    // Handle actions specifying an attachment.
107  21103 if (FILE_ACTION_LIST.contains(firstSegment) && pathSegments.size() >= 4) {
108    // Last segment is the attachment
109  2574 attachmentName = pathSegments.get(pathSegments.size() - 1);
110    // Last but one segment is the page name
111  2580 pageName = pathSegments.get(pathSegments.size() - 2);
112    // All segments in between are the space names
113  2581 spaceNames = extractSpaceNames(pathSegments, 1, pathSegments.size() - 3);
114    } else {
115    // Handle actions not specifying any attachment.
116  18526 Pair<String, Integer> actionAndStartPosition =
117    computeActionAndStartPosition(firstSegment, pathSegments);
118  18528 action = actionAndStartPosition.getLeft();
119  18528 int startPosition = actionAndStartPosition.getRight();
120    // Normally the last segment is always the page name but we want to handle a special case when we
121    // have "/view/something" and we wish in this case to consider that "something" is the space. This
122    // is to handle Nested Documents, so that the user can have a top level Nested Document
123    // (something.WebHome) and access it from /view/something. If we didn't handle this special case
124    // the user would get Main.something and thus wouldn't be able to access something.WebHome. He'd
125    // need to use /view/something/ which is not natural in the Nested Document mode.
126  18526 if (pathSegments.size() - startPosition == 1) {
127  6 spaceNames = Arrays.asList(pathSegments.get(startPosition));
128    } else {
129    // Last segment is the page name
130  18520 pageName = pathSegments.get(pathSegments.size() - 1);
131    // All segments in between are the space names
132  18523 spaceNames = extractSpaceNames(pathSegments, startPosition, pathSegments.size() - 2);
133    }
134    }
135    }
136   
137  21114 if (reference == null) {
138  21099 reference = new EntityResourceReference(
139    buildEntityReference(wikiReference, spaceNames, pageName, attachmentName),
140    EntityResourceAction.fromString(action));
141    }
142   
143  21103 copyParameters(extendedURL, reference);
144   
145  21104 return reference;
146    }
147   
 
148  18524 toggle private Pair<String, Integer> computeActionAndStartPosition(String firstSegment, List<String> pathSegments)
149    {
150  18523 String action;
151  18524 int startPosition;
152   
153    // - If the first segment is not an action name, then consider that the action is "view"
154    // (whether isViewActionHidden() is true or false)
155    // - If the first segment is an action name then always consider that it represents an action
156    // (whether isViewActionHidden is true or false), e.g. if the first space is called "view" then "view/view"
157    // will need to be used to produce a view URL for it.
158    //
159    // In addition we need to handle the special case of GWT resources, see AbstractExtendedURLResourceTypeResolver
160    // e.g. if we have "resources/js/xwiki/wysiwyg/xwe/MacroService.gwtrpc" as input then we need to return an
161    // action of "resources" and a document reference of "js.xwiki.wysiwyg.xwe.MacroService.gwtrpc"
162    // Note that "resources" is not a real action name which is why we ned a special handling.
163    // TODO: Remove this GWT handling and move it sto some more generic place
164   
165  18528 if (!this.entityResourceActionLister.listActions().contains(firstSegment)) {
166  1808 if (pathSegments.size() > 0 && firstSegment.equals("resources")
167    && pathSegments.get(pathSegments.size() - 1).endsWith(".gwtrpc"))
168    {
169  4 action = firstSegment;
170  4 startPosition = 1;
171    } else {
172  1804 action = VIEW_ACTION;
173  1804 startPosition = 0;
174    }
175    } else {
176  16720 action = firstSegment;
177  16719 startPosition = 1;
178    }
179   
180  18527 return new ImmutablePair<>(action, startPosition);
181    }
182   
 
183  21068 toggle private List<String> extractSpaceNames(List<String> pathSegments, int startPosition, int stopPosition)
184    {
185  21095 if (stopPosition < 0) {
186  0 return null;
187    }
188   
189  21091 List<String> spaceNames = new ArrayList<>();
190  21078 ListIterator<String> iterator = pathSegments.listIterator(startPosition);
191  21111 int total = stopPosition - startPosition + 1;
192  21115 int count = 0;
193  54134 while (count < total) {
194  33021 spaceNames.add(iterator.next());
195  33015 count++;
196    }
197  21112 return spaceNames;
198    }
199   
200    /**
201    * Normalize the extracted space/page to resolve empty/null values and replace them with default values.
202    *
203    * @param wikiReference the wiki reference as extracted from the URL
204    * @param spaceNames the space names as extracted from the URL (can be empty or null)
205    * @param pageName the page name as extracted from the URL (can be empty or null)
206    * @param attachmentName the attachment name as extracted from the URL (can be empty or null)
207    * @return the absolute Entity Reference
208    */
 
209  21046 toggle private EntityReference buildEntityReference(WikiReference wikiReference, List<String> spaceNames, String pageName,
210    String attachmentName)
211    {
212  21072 EntityReference reference = wikiReference;
213  21108 EntityType entityType = EntityType.DOCUMENT;
214  21092 if (spaceNames != null && !spaceNames.isEmpty()) {
215  21085 EntityReference parent = reference;
216  21100 for (String spaceName : spaceNames) {
217  33018 if (!StringUtils.isEmpty(spaceName)) {
218  33008 reference = new EntityReference(spaceName, EntityType.SPACE, parent);
219  33017 parent = reference;
220    }
221    }
222    }
223  21123 if (!StringUtils.isEmpty(pageName)) {
224  20453 reference = new EntityReference(pageName, EntityType.DOCUMENT, reference);
225    }
226  21133 if (!StringUtils.isEmpty(attachmentName)) {
227  2602 reference = new EntityReference(attachmentName, EntityType.ATTACHMENT, reference);
228  2602 entityType = EntityType.ATTACHMENT;
229    }
230  21131 return this.defaultReferenceEntityReferenceResolver.resolve(reference, entityType);
231    }
232    }