1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.web

File CreateActionRequestHandler.java

 

Coverage histogram

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

Code metrics

62
150
22
1
739
357
63
0.42
6.82
22
2.86

Classes

Class Line # Actions
CreateActionRequestHandler 57 150 0% 63 15
0.935897493.6%
 

Contributing tests

This file is covered by 39 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 com.xpn.xwiki.web;
21   
22    import java.lang.reflect.Type;
23    import java.util.ArrayList;
24    import java.util.List;
25    import java.util.Map;
26   
27    import javax.script.ScriptContext;
28   
29    import org.apache.commons.lang3.StringUtils;
30    import org.apache.velocity.VelocityContext;
31    import org.slf4j.Logger;
32    import org.slf4j.LoggerFactory;
33    import org.xwiki.model.EntityType;
34    import org.xwiki.model.reference.DocumentReference;
35    import org.xwiki.model.reference.DocumentReferenceResolver;
36    import org.xwiki.model.reference.EntityReference;
37    import org.xwiki.model.reference.EntityReferenceResolver;
38    import org.xwiki.model.reference.EntityReferenceSerializer;
39    import org.xwiki.model.reference.SpaceReference;
40    import org.xwiki.query.Query;
41    import org.xwiki.query.QueryManager;
42    import org.xwiki.script.ScriptContextManager;
43    import org.xwiki.velocity.VelocityManager;
44   
45    import com.xpn.xwiki.XWiki;
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   
52    /**
53    * Helper class used to handle one individual create action request.
54    *
55    * @version $Id: 476990d74ba9cc793ae3e4dfa8fbe09ab96cbe1a $
56    */
 
57    public class CreateActionRequestHandler
58    {
59    /**
60    * Log used to report exceptions.
61    */
62    private static final Logger LOGGER = LoggerFactory.getLogger(CreateActionRequestHandler.class);
63   
64    /**
65    * The name of the space reference parameter.
66    */
67    private static final String SPACE_REFERENCE = "spaceReference";
68   
69    /**
70    * The name parameter.
71    */
72    private static final String NAME = "name";
73   
74    /**
75    * The name of the deprecated space parameter. <br>
76    * Note: if you change the value of this variable, change the value of {{@link #TOCREATE_SPACE} to the previous
77    * value.
78    *
79    * @deprecated Use {@value #SPACE_REFERENCE} as parameter name instead.
80    */
81    @Deprecated
82    private static final String SPACE = "space";
83   
84    /**
85    * The name of the page parameter.
86    *
87    * @deprecated Use {@value #NAME} as parameter name instead.
88    */
89    @Deprecated
90    private static final String PAGE = "page";
91   
92    /**
93    * The value of the tocreate parameter when a space is to be created. <br>
94    * TODO: find a way to give this constant the same value as the constant above without violating checkstyle.
95    */
96    private static final String TOCREATE_SPACE = SPACE;
97   
98    /**
99    * The name of the "type" parameter.
100    */
101    private static final String TYPE = "type";
102   
103    /**
104    * The value of the tocreate parameter when a terminal/regular document is to be created.
105    */
106    private static final String TOCREATE_TERMINAL = "terminal";
107   
108    /**
109    * The value of the tocreate parameter when a non-terminal document is to be created.
110    */
111    private static final String TOCREATE_NONTERMINAL = "nonterminal";
112   
113    /**
114    * The name of the template field inside the template provider, or the template parameter which can be sent
115    * directly, without passing through the template provider.
116    */
117    private static final String TEMPLATE = "template";
118   
119    /**
120    * The name of the template provider parameter.
121    */
122    private static final String TEMPLATE_PROVIDER = "templateprovider";
123   
124    /**
125    * The template provider class, to create documents from templates.
126    */
127    private static final EntityReference TEMPLATE_PROVIDER_CLASS = new EntityReference("TemplateProviderClass",
128    EntityType.DOCUMENT, new EntityReference(XWiki.SYSTEM_SPACE, EntityType.SPACE));
129   
130    /**
131    * The redirect class, used to mark pages that are redirect place-holders, i.e. hidden pages that serve only for
132    * redirecting the user to a different page (e.g. when a page has been moved).
133    */
134    private static final EntityReference REDIRECT_CLASS = new EntityReference("RedirectClass", EntityType.DOCUMENT,
135    new EntityReference(XWiki.SYSTEM_SPACE, EntityType.SPACE));
136   
137    /**
138    * The property name for the spaces in the template provider object.
139    *
140    * @deprecated since 8.3M2. Use {@link #TP_CREATION_RESTRICTIONS_PROPERTY} or
141    * {@value #TP_VISIBILITY_RESTRICTIONS_PROPERTY} instead for the explicit restriction you need to add.
142    */
143    @Deprecated
144    private static final String SPACES_PROPERTY = "spaces";
145   
146    /**
147    * The key used to add exceptions on the context, to be read by the template.
148    */
149    private static final String EXCEPTION = "createException";
150   
151    /**
152    * Current entity reference resolver hint.
153    */
154    private static final String CURRENT_RESOLVER_HINT = "current";
155   
156    /**
157    * Current entity reference resolver hint.
158    */
159    private static final String CURRENT_MIXED_RESOLVER_HINT = "currentmixed";
160   
161    /**
162    * Local entity reference serializer hint.
163    */
164    private static final String LOCAL_SERIALIZER_HINT = "local";
165   
166    private static final String TP_TERMINAL_PROPERTY = TOCREATE_TERMINAL;
167   
168    private static final String TP_TYPE_PROPERTY = TYPE;
169   
170    private static final String TP_TYPE_PROPERTY_SPACE_VALUE = SPACE;
171   
172    private static final String TP_CREATION_RESTRICTIONS_PROPERTY = "creationRestrictions";
173   
174    private static final String TP_VISIBILITY_RESTRICTIONS_PROPERTY = "visibilityRestrictions";
175   
176    private static final String TP_CREATION_RESTRICTIONS_ARE_SUGGESTIONS_PROPERTY =
177    "creationRestrictionsAreSuggestions";
178   
179    /**
180    * Space homepage document name.
181    */
182    private static final String WEBHOME = "WebHome";
183   
184    private ScriptContextManager scriptContextManager;
185   
186    private SpaceReference spaceReference;
187   
188    private String name;
189   
190    private boolean isSpace;
191   
192    private XWikiContext context;
193   
194    private XWikiDocument document;
195   
196    private XWikiRequest request;
197   
198    private BaseObject templateProvider;
199   
200    private List<Document> availableTemplateProviders;
201   
202    private String type;
203   
204    /**
205    * @param context the XWikiContext for which to handle the request.
206    */
 
207  98 toggle public CreateActionRequestHandler(XWikiContext context)
208    {
209  98 this.context = context;
210  98 this.document = context.getDoc();
211  98 this.request = context.getRequest();
212    }
213   
214    /**
215    * Process the request and extract from the given parameters the data needed to create the new document.
216    *
217    * @throws XWikiException if problems occur
218    */
 
219  98 toggle public void processRequest() throws XWikiException
220    {
221    // Get the template provider for creating this document, if any template provider is specified
222  98 DocumentReferenceResolver<EntityReference> referenceResolver =
223    Utils.getComponent(DocumentReferenceResolver.TYPE_REFERENCE, CURRENT_RESOLVER_HINT);
224  98 DocumentReference templateProviderClassReference = referenceResolver.resolve(TEMPLATE_PROVIDER_CLASS);
225  98 templateProvider = getTemplateProvider(templateProviderClassReference);
226   
227    // Get the available templates, in the current space, to check if all conditions to create a new document are
228    // met
229  98 availableTemplateProviders =
230    loadAvailableTemplateProviders(document.getDocumentReference().getLastSpaceReference(),
231    templateProviderClassReference, context);
232   
233    // Get the type of document to create
234  98 type = request.get(TYPE);
235   
236    // Since this template can be used for creating a Page or a Space, check the passed "tocreate" parameter
237    // which can be either "page" or "space". If no parameter is passed then we default to creating a Page.
238  98 String toCreate = request.getParameter("tocreate");
239   
240  98 if (document.isNew()) {
241  34 processNewDocument(toCreate);
242    } else {
243    // We are on an existing document...
244   
245  64 if (request.getParameter(SPACE) != null || request.getParameter(PAGE) != null) {
246    // We are in Backwards Compatibility mode and we are using the deprecated parameter names.
247  7 processDeprecatedParameters(toCreate);
248    } else {
249    // Determine the new document values from the request.
250   
251  57 String spaceReferenceParameter = request.getParameter(SPACE_REFERENCE);
252    // We can have an empty spaceReference parameter symbolizing that we are creating a top level space or
253    // non-terminal document.
254  57 if (StringUtils.isNotEmpty(spaceReferenceParameter)) {
255  34 EntityReferenceResolver<String> genericResolver =
256    Utils.getComponent(EntityReferenceResolver.TYPE_STRING, CURRENT_RESOLVER_HINT);
257   
258  34 EntityReference resolvedEntityReference =
259    genericResolver.resolve(spaceReferenceParameter, EntityType.SPACE);
260  34 spaceReference = new SpaceReference(resolvedEntityReference);
261    }
262   
263    // Note: We leave the spaceReference variable intentionally null to symbolize a top level space or
264    // non-terminal document.
265   
266  57 name = request.getParameter(NAME);
267   
268    // Determine the type of document we are creating (terminal vs non-terminal).
269   
270  57 if (TOCREATE_TERMINAL.equals(toCreate) || TOCREATE_NONTERMINAL.equals(toCreate)) {
271    // Look at the request to see what the user wanted to create (terminal or non-terminal).
272   
273  26 isSpace = !TOCREATE_TERMINAL.equals(toCreate);
274  31 } else if (templateProvider != null) {
275    // A template provider is specified. Use it and extract the type of document.
276   
277  7 boolean providerTerminal = getTemplateProviderTerminalValue();
278  7 isSpace = !providerTerminal;
279    } else {
280    // Default to creating non-terminal documents.
281  24 isSpace = true;
282    }
283    }
284    }
285    }
286   
287    /**
288    * @param toCreate the value of the "tocreate" request parameter
289    */
 
290  34 toggle private void processNewDocument(String toCreate)
291    {
292    // Current space and page name.
293  34 spaceReference = document.getDocumentReference().getLastSpaceReference();
294  34 name = document.getDocumentReference().getName();
295   
296    // Determine if the current document is in a top-level space.
297  34 EntityReference parentSpaceReference = spaceReference.getParent();
298  34 boolean isTopLevelSpace = parentSpaceReference.extractReference(EntityType.SPACE) == null;
299   
300    // Remember this since we might update it below.
301  34 String originalName = name;
302   
303    // Since WebHome is a convention, determine the real name and parent of our document.
304  34 if (WEBHOME.equals(name)) {
305    // Determine its name from the space name.
306  24 name = spaceReference.getName();
307   
308    // Determine its space reference by looking at the space's parent.
309  24 if (!isTopLevelSpace) {
310    // The parent reference is a space reference. Use it.
311  19 spaceReference = new SpaceReference(parentSpaceReference);
312    } else {
313    // Top level document, i.e. the parent reference is a wiki reference. Clear the spaceReference variable
314    // so that this case is properly handled later on (as if an empty value was passed as parameter in the
315    // request).
316  5 spaceReference = null;
317    }
318    }
319   
320    // Determine the type of document we are creating (terminal vs non-terminal).
321   
322  34 if (TOCREATE_TERMINAL.equals(toCreate) || TOCREATE_NONTERMINAL.equals(toCreate)) {
323    // Look at the request to see what the user wanted to create (terminal or non-terminal).
324   
325  14 isSpace = !TOCREATE_TERMINAL.equals(toCreate);
326  20 } else if (templateProvider != null) {
327    // A template provider is specified. Use it and extract the type of document.
328   
329  5 boolean providerTerminal = getTemplateProviderTerminalValue();
330  5 isSpace = !providerTerminal;
331    } else {
332    // Last option is to check the document's original name and see if it was "WebHome".
333  15 isSpace = WEBHOME.equals(originalName);
334    }
335    }
336   
337    /**
338    * @return
339    */
 
340  12 toggle private boolean getTemplateProviderTerminalValue()
341    {
342  12 boolean providerTerminal;
343  12 int providerTerminalValue = templateProvider.getIntValue(TP_TERMINAL_PROPERTY, -1);
344  12 if (providerTerminalValue == -1) {
345    // Backwards compatibility with providers that did not have the "terminal" property. We are deducing it
346    // from the value of the "type" property.
347  2 String providerType = templateProvider.getStringValue(TP_TYPE_PROPERTY);
348  2 if (TP_TYPE_PROPERTY_SPACE_VALUE.equals(providerType)) {
349  1 providerTerminal = false;
350    } else {
351    // 'page' or NULL both resolve to true, for backwards compatibility reasons.
352  1 providerTerminal = true;
353    }
354    } else {
355    // Use the "terminal" value from the template provider.
356  10 providerTerminal = (1 == providerTerminalValue);
357    }
358  12 return providerTerminal;
359    }
360   
361    /**
362    * @param toCreate the value of the "tocreate" request parameter
363    */
 
364  7 toggle private void processDeprecatedParameters(String toCreate)
365    {
366    // Note: The most important details is that the deprecated "space" parameter stores unescaped space
367    // names, not references!
368  7 String spaceParameter = request.getParameter(SPACE);
369   
370  7 isSpace = TOCREATE_SPACE.equals(toCreate);
371  7 if (isSpace) {
372    // Always creating top level spaces in this mode. Adapt to the new implementation.
373  4 spaceReference = null;
374  4 name = spaceParameter;
375    } else {
376  3 if (StringUtils.isNotEmpty(spaceParameter)) {
377    // Always creating documents in top level spaces in this mode.
378  3 spaceReference = new SpaceReference(spaceParameter, document.getDocumentReference().getWikiReference());
379    }
380   
381  3 name = request.getParameter(PAGE);
382    }
383    }
384   
385    /**
386    * @param templateProviderClass the class of the template provider object
387    * @return the object which holds the template provider to be used for creation
388    * @throws XWikiException in case anything goes wrong manipulating documents
389    */
 
390  98 toggle private BaseObject getTemplateProvider(DocumentReference templateProviderClass) throws XWikiException
391    {
392  98 BaseObject result = null;
393   
394    // resolver to use to resolve references received in request parameters
395  98 DocumentReferenceResolver<String> referenceResolver =
396    Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, CURRENT_MIXED_RESOLVER_HINT);
397   
398    // set the template, from the template provider param
399  98 String templateProviderDocReferenceString = request.getParameter(TEMPLATE_PROVIDER);
400   
401  98 if (!StringUtils.isEmpty(templateProviderDocReferenceString)) {
402    // parse this document reference
403  22 DocumentReference templateProviderRef = referenceResolver.resolve(templateProviderDocReferenceString);
404    // get the document of the template provider and the object
405  22 XWikiDocument templateProviderDoc = context.getWiki().getDocument(templateProviderRef, context);
406  22 result = templateProviderDoc.getXObject(templateProviderClass);
407    }
408   
409  98 return result;
410    }
411   
412    /**
413    * @param spaceReference the space to check if there are available templates for
414    * @param context the context of the current request
415    * @param templateClassReference the reference to the template provider class
416    * @return the available template providers for the passed space, as {@link Document}s
417    */
 
418  98 toggle private List<Document> loadAvailableTemplateProviders(SpaceReference spaceReference,
419    DocumentReference templateClassReference, XWikiContext context)
420    {
421  98 XWiki wiki = context.getWiki();
422  98 List<Document> templates = new ArrayList<Document>();
423  98 try {
424    // resolver to use to resolve references received in request parameters
425  98 DocumentReferenceResolver<String> resolver =
426    Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, CURRENT_MIXED_RESOLVER_HINT);
427   
428  98 QueryManager queryManager = Utils.getComponent((Type) QueryManager.class, "secure");
429  98 Query query =
430    queryManager.createQuery("from doc.object(XWiki.TemplateProviderClass) as template "
431    + "where doc.fullName not like 'XWiki.TemplateProviderTemplate' " + "order by template.name",
432    Query.XWQL);
433   
434    // TODO: Extend the above query to include a filter on the type and allowed spaces properties so we can
435    // remove the java code below, thus improving performance by not loading all the documents, but only the
436    // documents we need.
437   
438  98 List<String> templateProviderDocNames = query.execute();
439  98 for (String templateProviderName : templateProviderDocNames) {
440    // get the document and template provider object
441  36 DocumentReference reference = resolver.resolve(templateProviderName);
442  36 XWikiDocument templateDoc = wiki.getDocument(reference, context);
443  36 BaseObject templateObject = templateDoc.getXObject(templateClassReference);
444   
445    // Check the template provider's visibility restrictions.
446  36 if (isTemplateProviderAllowedInSpace(templateObject, spaceReference,
447    TP_VISIBILITY_RESTRICTIONS_PROPERTY)) {
448    // create a Document and put it in the list
449  35 templates.add(new Document(templateDoc, context));
450    }
451    }
452    } catch (Exception e) {
453  0 LOGGER.warn("There was an error getting the available templates for space {0}", spaceReference, e);
454    }
455   
456  98 return templates;
457    }
458   
 
459  58 toggle private boolean isTemplateProviderAllowedInSpace(BaseObject templateObject, SpaceReference spaceReference,
460    String restrictionsProperty)
461    {
462    // Handle the special case for creation restrictions when they are only suggestions and can be ignored.
463  58 if (TP_CREATION_RESTRICTIONS_PROPERTY.equals(restrictionsProperty)
464    && templateObject.getIntValue(TP_CREATION_RESTRICTIONS_ARE_SUGGESTIONS_PROPERTY, 0) == 1) {
465  0 return true;
466    }
467   
468    // Check the allowed spaces list.
469  58 List<String> restrictions = getTemplateProviderRestrictions(templateObject, restrictionsProperty);
470  58 if (restrictions.size() > 0) {
471  7 EntityReferenceSerializer<String> localSerializer =
472    Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, LOCAL_SERIALIZER_HINT);
473  7 String spaceStringReference = localSerializer.serialize(spaceReference);
474   
475  7 for (String allowedSpace : restrictions) {
476    // Exact match or parent space (i.e. prefix) match.
477  7 if (allowedSpace.equals(spaceStringReference)
478    || StringUtils.startsWith(spaceStringReference, String.format("%s.", allowedSpace))) {
479  3 return true;
480    }
481    }
482   
483    // No match, not allowed.
484  4 return false;
485    }
486   
487    // No creation restrictions exist, allowed by default.
488  51 return true;
489    }
490   
 
491  61 toggle private List<String> getTemplateProviderRestrictions(BaseObject templateObject, String restrictionsProperty)
492    {
493  61 List<String> creationRestrictions = templateObject.getListValue(restrictionsProperty);
494  61 if (creationRestrictions.size() == 0) {
495    // Backwards compatibility for template providers created before 8.3M2, where the "spaces" property handled
496    // both visibility and creation.
497  51 creationRestrictions = templateObject.getListValue(SPACES_PROPERTY);
498    }
499  61 return creationRestrictions;
500    }
501   
502    /**
503    * @return the document reference of the new document to be created, {@code null} if a no document can be created
504    * (because the conditions are not met)
505    */
 
506  98 toggle public DocumentReference getNewDocumentReference()
507    {
508  98 DocumentReference result = null;
509   
510  98 if (StringUtils.isEmpty(name)) {
511    // Can`t do anything without a name.
512  18 return null;
513    }
514   
515    // The new values, after the processing needed for ND below, to be used when creating the document reference.
516  80 SpaceReference newSpaceReference = spaceReference;
517  80 String newName = name;
518   
519    // Special handling for old spaces or new Nested Documents.
520  80 if (isSpace) {
521  56 EntityReference parentSpaceReference = spaceReference;
522  56 if (parentSpaceReference == null) {
523  13 parentSpaceReference = context.getDoc().getDocumentReference().getWikiReference();
524    }
525   
526    // The new space's reference.
527  56 newSpaceReference = new SpaceReference(name, parentSpaceReference);
528   
529    // The new document's name set to the new space's homepage. In Nested Documents, this leads to the new ND's
530    // reference name.
531  56 newName = WEBHOME;
532    }
533   
534    // Proceed with creating the document...
535   
536  80 if (newSpaceReference == null) {
537    // No space specified, nothing to do. This can be the case for terminal documents, since non-terminal
538    // documents can be top-level.
539  1 return null;
540    }
541   
542    // Check whether there is a template parameter set, be it an empty one. If a page should be created and there is
543    // no template parameter, it means the create action is not supposed to be executed, but only display the
544    // available templates and let the user choose
545    // If there's no passed template, check if there are any available templates. If none available, then the fact
546    // that there is no template is ok.
547  79 if (hasTemplate() || availableTemplateProviders.isEmpty()) {
548  76 result = new DocumentReference(newName, newSpaceReference);
549    }
550   
551  79 return result;
552    }
553   
554    /**
555    * @return if a template or a template provider have been set (it can be empty however)
556    */
 
557  94 toggle public boolean hasTemplate()
558    {
559  94 return request.getParameter(TEMPLATE_PROVIDER) != null || request.getParameter(TEMPLATE) != null;
560    }
561   
562    /**
563    * Verifies if the creation inside the specified spaceReference is allowed by the current template provider. If the
564    * creation is not allowed, an exception will be set on the context.
565    *
566    * @return {@code true} if the creation is allowed, {@code false} otherwise
567    */
 
568  76 toggle public boolean isTemplateProviderAllowedToCreateInCurrentSpace()
569    {
570    // Check that the chosen space is allowed with the given template, if not:
571    // - Cancel the redirect
572    // - Set an error on the context, to be read by the create.vm
573  76 if (templateProvider != null) {
574    // Check using the template provider's creation restrictions.
575  22 if (!isTemplateProviderAllowedInSpace(templateProvider, spaceReference,
576    TP_CREATION_RESTRICTIONS_PROPERTY)) {
577    // put an exception on the context, for create.vm to know to display an error
578  3 Object[] args = {templateProvider.getStringValue(TEMPLATE), spaceReference, name};
579  3 XWikiException exception =
580    new XWikiException(XWikiException.MODULE_XWIKI_STORE,
581    XWikiException.ERROR_XWIKI_APP_TEMPLATE_NOT_AVAILABLE,
582    "Template {0} cannot be used in space {1} when creating page {2}", null, args);
583   
584  3 ScriptContext scontext = getCurrentScriptContext();
585  3 scontext.setAttribute(EXCEPTION, exception, ScriptContext.ENGINE_SCOPE);
586  3 scontext.setAttribute("createAllowedSpaces",
587    getTemplateProviderRestrictions(templateProvider, TP_CREATION_RESTRICTIONS_PROPERTY),
588    ScriptContext.ENGINE_SCOPE);
589   
590  3 return false;
591    }
592    }
593   
594    // For all other cases, creation is allowed.
595  73 return true;
596    }
597   
598    /**
599    * @param newDocument the new document to check if it already exists
600    * @return true if the document already exists (i.e. is not usable) and set an exception in the velocity context;
601    * false otherwise.
602    */
 
603  73 toggle public boolean isDocumentAlreadyExisting(XWikiDocument newDocument)
604    {
605    // if the document exists don't create it, put the exception on the context so that the template gets it and
606    // re-requests the page and space, else create the document and redirect to edit
607  73 if (!isEmptyDocument(newDocument)) {
608  4 ScriptContext scontext = getCurrentScriptContext();
609   
610    // Expose to the template reference of the document that already exist so that it can propose to view or
611    // edit it.
612  4 scontext.setAttribute("existingDocumentReference", newDocument.getDocumentReference(),
613    ScriptContext.ENGINE_SCOPE);
614   
615    // Throw an exception.
616  4 Object[] args = {newDocument.getDocumentReference()};
617  4 XWikiException documentAlreadyExists =
618    new XWikiException(XWikiException.MODULE_XWIKI_STORE,
619    XWikiException.ERROR_XWIKI_APP_DOCUMENT_NOT_EMPTY,
620    "Cannot create document {0} because it already has content", null, args);
621  4 scontext.setAttribute(EXCEPTION, documentAlreadyExists, ScriptContext.ENGINE_SCOPE);
622   
623  4 return true;
624    }
625   
626  69 return false;
627    }
628   
629    /**
630    * Checks if a document is empty, that is, if a document with that name could be created from a template. <br>
631    * TODO: move this function to a more accessible place, to be used by the readFromTemplate method as well, so that
632    * we have consistency.
633    *
634    * @param document the document to check
635    * @return {@code true} if the document is empty (i.e. a document with the same name can be created (from
636    * template)), {@code false} otherwise
637    */
 
638  73 toggle private boolean isEmptyDocument(XWikiDocument document)
639    {
640    // If it's a new document or a redirect placeholder, it's fine.
641  73 if (document.isNew() || document.getXObject(REDIRECT_CLASS) != null) {
642  69 return true;
643    }
644   
645    // FIXME: the code below is not really what users might expect. Overriding an existing document (even if no
646    // content or objects) is not really nice to do. Should be removed.
647   
648    // otherwise, check content and objects (only empty newline content allowed and no objects)
649  4 String content = document.getContent();
650  4 if (!content.equals("\n") && !content.equals("") && !content.equals("\\\\")) {
651  4 return false;
652    }
653   
654    // go through all the objects and when finding the first one which is not null (because of the remove gaps),
655    // return false, we cannot re-create this doc
656  0 for (Map.Entry<DocumentReference, List<BaseObject>> objList : document.getXObjects().entrySet()) {
657  0 for (BaseObject obj : objList.getValue()) {
658  0 if (obj != null) {
659  0 return false;
660    }
661    }
662    }
663   
664  0 return true;
665    }
666   
667    /**
668    * @return the {@link VelocityContext} for the context we are handling
669    * @deprecated since 8.3M1, use {@link #getCurrentScriptContext()} instead
670    */
 
671  0 toggle @Deprecated
672    public VelocityContext getVelocityContext()
673    {
674  0 return Utils.getComponent(VelocityManager.class).getVelocityContext();
675    }
676   
677    /**
678    * @return the current script context
679    * @since 8.3M1
680    */
 
681  7 toggle protected ScriptContext getCurrentScriptContext()
682    {
683  7 if (this.scriptContextManager == null) {
684  7 this.scriptContextManager = Utils.getComponent(ScriptContextManager.class);
685    }
686   
687  7 return this.scriptContextManager.getCurrentScriptContext();
688    }
689   
690    /**
691    * @return the space reference where the new document will be created
692    */
 
693  98 toggle public SpaceReference getSpaceReference()
694    {
695  98 return spaceReference;
696    }
697   
698    /**
699    * @return the name of the new document. See {@link #isSpace()}
700    */
 
701  98 toggle public String getName()
702    {
703  98 return name;
704    }
705   
706    /**
707    * @return true if the new document is a space (i.e. Nested Document and the name means space name) or false if it's
708    * a terminal regular document (i.e. Nested Spaces document and the name means document name)
709    */
 
710  156 toggle public boolean isSpace()
711    {
712  156 return isSpace;
713    }
714   
715    /**
716    * @return the available template providers for the space from where we are creating the new document
717    */
 
718  98 toggle public List<Document> getAvailableTemplateProviders()
719    {
720  98 return availableTemplateProviders;
721    }
722   
723    /**
724    * @return the currently used template provider read from the request, or {@code null} if none was set
725    */
 
726  58 toggle public BaseObject getTemplateProvider()
727    {
728  58 return templateProvider;
729    }
730   
731    /**
732    * @return the type of document to create, read from the request, or {@code null} if none was set
733    * @since 7.2
734    */
 
735  69 toggle public String getType()
736    {
737  69 return type;
738    }
739    }