1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package com.xpn.xwiki

File XWiki.java

Code metrics

878
2,329
410
1
7,447
4,907
1,002
0.43
5.68
410
2.44
Syntax error detected in source file:
/home/hudsonagent/jenkins_root/workspace/Clover/xwiki-platform/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java
Comparison method violates its general contract!
<
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;
21  
22   import java.io.ByteArrayInputStream;
23   import java.io.File;
24   import java.io.FileInputStream;
25   import java.io.FileNotFoundException;
26   import java.io.IOException;
27   import java.io.InputStream;
28   import java.io.PrintWriter;
29   import java.io.StringWriter;
30   import java.lang.reflect.Field;
31   import java.lang.reflect.InvocationTargetException;
32   import java.lang.reflect.Method;
33   import java.lang.reflect.Type;
34   import java.net.MalformedURLException;
35   import java.net.URL;
36   import java.text.DateFormatSymbols;
37   import java.text.SimpleDateFormat;
38   import java.util.ArrayList;
39   import java.util.Arrays;
40   import java.util.Collections;
41   import java.util.Comparator;
42   import java.util.Date;
43   import java.util.Enumeration;
44   import java.util.HashMap;
45   import java.util.HashSet;
46   import java.util.List;
47   import java.util.Locale;
48   import java.util.Map;
49   import java.util.Set;
50   import java.util.TimeZone;
51   import java.util.Vector;
52   import java.util.concurrent.ConcurrentHashMap;
53   import java.util.zip.ZipOutputStream;
54  
55   import javax.annotation.Priority;
56   import javax.inject.Provider;
57   import javax.mail.Message;
58   import javax.mail.Session;
59   import javax.mail.internet.InternetAddress;
60   import javax.mail.internet.MimeMessage;
61   import javax.naming.NamingException;
62   import javax.script.ScriptContext;
63   import javax.servlet.http.Cookie;
64   import javax.servlet.http.HttpServletRequest;
65   import javax.servlet.http.HttpServletResponse;
66  
67   import org.apache.commons.httpclient.Credentials;
68   import org.apache.commons.httpclient.HttpClient;
69   import org.apache.commons.httpclient.URIException;
70   import org.apache.commons.httpclient.UsernamePasswordCredentials;
71   import org.apache.commons.httpclient.auth.AuthScope;
72   import org.apache.commons.httpclient.methods.GetMethod;
73   import org.apache.commons.httpclient.util.URIUtil;
74   import org.apache.commons.io.FileUtils;
75   import org.apache.commons.io.IOUtils;
76   import org.apache.commons.lang3.ArrayUtils;
77   import org.apache.commons.lang3.LocaleUtils;
78   import org.apache.commons.lang3.RandomStringUtils;
79   import org.apache.commons.lang3.StringUtils;
80   import org.apache.commons.lang3.exception.ExceptionUtils;
81   import org.apache.commons.lang3.math.NumberUtils;
82   import org.apache.commons.lang3.reflect.FieldUtils;
83   import org.apache.velocity.VelocityContext;
84   import org.hibernate.HibernateException;
85   import org.slf4j.Logger;
86   import org.slf4j.LoggerFactory;
87   import org.xwiki.bridge.event.DocumentCreatedEvent;
88   import org.xwiki.bridge.event.DocumentCreatingEvent;
89   import org.xwiki.bridge.event.DocumentDeletedEvent;
90   import org.xwiki.bridge.event.DocumentDeletingEvent;
91   import org.xwiki.bridge.event.DocumentRolledBackEvent;
92   import org.xwiki.bridge.event.DocumentRollingBackEvent;
93   import org.xwiki.bridge.event.DocumentUpdatedEvent;
94   import org.xwiki.bridge.event.DocumentUpdatingEvent;
95   import org.xwiki.bridge.event.WikiCopiedEvent;
96   import org.xwiki.bridge.event.WikiDeletedEvent;
97   import org.xwiki.cache.Cache;
98   import org.xwiki.classloader.ClassLoaderManager;
99   import org.xwiki.component.event.ComponentDescriptorAddedEvent;
100   import org.xwiki.component.manager.ComponentLookupException;
101   import org.xwiki.component.manager.ComponentManager;
102   import org.xwiki.component.manager.NamespacedComponentManager;
103   import org.xwiki.component.util.DefaultParameterizedType;
104   import org.xwiki.configuration.ConfigurationSource;
105   import org.xwiki.container.servlet.HttpServletUtils;
106   import org.xwiki.context.Execution;
107   import org.xwiki.edit.EditConfiguration;
108   import org.xwiki.job.Job;
109   import org.xwiki.job.JobException;
110   import org.xwiki.job.JobExecutor;
111   import org.xwiki.job.annotation.Serializable;
112   import org.xwiki.job.event.status.JobProgressManager;
113   import org.xwiki.job.event.status.JobStatus.State;
114   import org.xwiki.localization.ContextualLocalizationManager;
115   import org.xwiki.mail.MailListener;
116   import org.xwiki.mail.MailSender;
117   import org.xwiki.mail.MailSenderConfiguration;
118   import org.xwiki.mail.MailStatusResultSerializer;
119   import org.xwiki.mail.XWikiAuthenticator;
120   import org.xwiki.model.EntityType;
121   import org.xwiki.model.reference.AttachmentReference;
122   import org.xwiki.model.reference.AttachmentReferenceResolver;
123   import org.xwiki.model.reference.DocumentReference;
124   import org.xwiki.model.reference.DocumentReferenceResolver;
125   import org.xwiki.model.reference.EntityReference;
126   import org.xwiki.model.reference.EntityReferenceResolver;
127   import org.xwiki.model.reference.EntityReferenceSerializer;
128   import org.xwiki.model.reference.LocalDocumentReference;
129   import org.xwiki.model.reference.ObjectReference;
130   import org.xwiki.model.reference.PageReference;
131   import org.xwiki.model.reference.PageReferenceResolver;
132   import org.xwiki.model.reference.RegexEntityReference;
133   import org.xwiki.model.reference.SpaceReference;
134   import org.xwiki.model.reference.WikiReference;
135   import org.xwiki.observation.EventListener;
136   import org.xwiki.observation.ObservationManager;
137   import org.xwiki.observation.event.CancelableEvent;
138   import org.xwiki.observation.event.Event;
139   import org.xwiki.query.QueryException;
140   import org.xwiki.query.QueryFilter;
141   import org.xwiki.refactoring.batch.BatchOperationExecutor;
142   import org.xwiki.rendering.async.AsyncContext;
143   import org.xwiki.rendering.block.Block;
144   import org.xwiki.rendering.block.Block.Axes;
145   import org.xwiki.rendering.block.MetaDataBlock;
146   import org.xwiki.rendering.block.match.MetadataBlockMatcher;
147   import org.xwiki.rendering.internal.transformation.MutableRenderingContext;
148   import org.xwiki.rendering.listener.MetaData;
149   import org.xwiki.rendering.parser.ParseException;
150   import org.xwiki.rendering.syntax.Syntax;
151   import org.xwiki.rendering.syntax.SyntaxContent;
152   import org.xwiki.rendering.transformation.RenderingContext;
153   import org.xwiki.resource.ResourceReference;
154   import org.xwiki.resource.ResourceReferenceManager;
155   import org.xwiki.resource.ResourceReferenceResolver;
156   import org.xwiki.resource.ResourceType;
157   import org.xwiki.resource.ResourceTypeResolver;
158   import org.xwiki.resource.entity.EntityResourceReference;
159   import org.xwiki.script.ScriptContextManager;
160   import org.xwiki.skin.Resource;
161   import org.xwiki.skin.Skin;
162   import org.xwiki.skin.SkinManager;
163   import org.xwiki.stability.Unstable;
164   import org.xwiki.template.TemplateManager;
165   import org.xwiki.url.ExtendedURL;
166   import org.xwiki.velocity.VelocityManager;
167   import org.xwiki.wiki.descriptor.WikiDescriptor;
168   import org.xwiki.wiki.descriptor.WikiDescriptorManager;
169   import org.xwiki.wiki.manager.WikiManager;
170   import org.xwiki.wiki.manager.WikiManagerException;
171   import org.xwiki.xml.XMLUtils;
172  
173   import com.xpn.xwiki.api.Api;
174   import com.xpn.xwiki.api.Document;
175   import com.xpn.xwiki.api.User;
176   import com.xpn.xwiki.criteria.api.XWikiCriteriaService;
177   import com.xpn.xwiki.doc.DeletedAttachment;
178   import com.xpn.xwiki.doc.DocumentRevisionProvider;
179   import com.xpn.xwiki.doc.MandatoryDocumentInitializer;
180   import com.xpn.xwiki.doc.XWikiAttachment;
181   import com.xpn.xwiki.doc.XWikiDeletedDocument;
182   import com.xpn.xwiki.doc.XWikiDocument;
183   import com.xpn.xwiki.doc.XWikiDocument.XWikiAttachmentToRemove;
184   import com.xpn.xwiki.doc.XWikiDocumentArchive;
185   import com.xpn.xwiki.internal.WikiInitializerJob;
186   import com.xpn.xwiki.internal.WikiInitializerRequest;
187   import com.xpn.xwiki.internal.XWikiCfgConfigurationSource;
188   import com.xpn.xwiki.internal.XWikiConfigDelegate;
189   import com.xpn.xwiki.internal.XWikiInitializerJob;
190   import com.xpn.xwiki.internal.event.XObjectPropertyAddedEvent;
191   import com.xpn.xwiki.internal.event.XObjectPropertyDeletedEvent;
192   import com.xpn.xwiki.internal.event.XObjectPropertyEvent;
193   import com.xpn.xwiki.internal.event.XObjectPropertyUpdatedEvent;
194   import com.xpn.xwiki.internal.mandatory.XWikiPreferencesDocumentInitializer;
195   import com.xpn.xwiki.internal.render.OldRendering;
196   import com.xpn.xwiki.internal.render.groovy.ParseGroovyFromString;
197   import com.xpn.xwiki.internal.skin.InternalSkinConfiguration;
198   import com.xpn.xwiki.internal.skin.InternalSkinManager;
199   import com.xpn.xwiki.internal.skin.WikiSkin;
200   import com.xpn.xwiki.internal.skin.WikiSkinUtils;
201   import com.xpn.xwiki.internal.store.StoreConfiguration;
202   import com.xpn.xwiki.internal.velocity.VelocityEvaluator;
203   import com.xpn.xwiki.job.JobRequestContext;
204   import com.xpn.xwiki.objects.BaseObject;
205   import com.xpn.xwiki.objects.PropertyInterface;
206   import com.xpn.xwiki.objects.classes.BaseClass;
207   import com.xpn.xwiki.objects.classes.PasswordClass;
208   import com.xpn.xwiki.objects.classes.PropertyClass;
209   import com.xpn.xwiki.objects.meta.MetaClass;
210   import com.xpn.xwiki.plugin.XWikiPluginInterface;
211   import com.xpn.xwiki.plugin.XWikiPluginManager;
212   import com.xpn.xwiki.render.groovy.XWikiPageClassLoader;
213   import com.xpn.xwiki.stats.api.XWikiStatsService;
214   import com.xpn.xwiki.stats.impl.SearchEngineRule;
215   import com.xpn.xwiki.stats.impl.XWikiStatsServiceImpl;
216   import com.xpn.xwiki.store.AttachmentRecycleBinStore;
217   import com.xpn.xwiki.store.AttachmentVersioningStore;
218   import com.xpn.xwiki.store.XWikiAttachmentStoreInterface;
219   import com.xpn.xwiki.store.XWikiCacheStoreInterface;
220   import com.xpn.xwiki.store.XWikiHibernateStore;
221   import com.xpn.xwiki.store.XWikiRecycleBinStoreInterface;
222   import com.xpn.xwiki.store.XWikiStoreInterface;
223   import com.xpn.xwiki.store.XWikiVersioningStoreInterface;
224   import com.xpn.xwiki.user.api.XWikiAuthService;
225   import com.xpn.xwiki.user.api.XWikiGroupService;
226   import com.xpn.xwiki.user.api.XWikiRightService;
227   import com.xpn.xwiki.user.api.XWikiUser;
228   import com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl;
229   import com.xpn.xwiki.user.impl.xwiki.XWikiGroupServiceImpl;
230   import com.xpn.xwiki.user.impl.xwiki.XWikiRightServiceImpl;
231   import com.xpn.xwiki.util.Util;
232   import com.xpn.xwiki.util.XWikiStubContextProvider;
233   import com.xpn.xwiki.web.Utils;
234   import com.xpn.xwiki.web.XWikiEngineContext;
235   import com.xpn.xwiki.web.XWikiMessageTool;
236   import com.xpn.xwiki.web.XWikiRequest;
237   import com.xpn.xwiki.web.XWikiServletRequestStub;
238   import com.xpn.xwiki.web.XWikiURLFactory;
239   import com.xpn.xwiki.web.XWikiURLFactoryService;
240   import com.xpn.xwiki.web.XWikiURLFactoryServiceImpl;
241   import com.xpn.xwiki.web.includeservletasstring.IncludeServletAsString;
242  
243   @Serializable(false)
244   public class XWiki implements EventListener
245   {
246   /** Name of the default wiki. */
247   public static final String DEFAULT_MAIN_WIKI = "xwiki";
248  
249   /** Name of the default home space. */
250   public static final String DEFAULT_HOME_SPACE = "Main";
251  
252   /** Name of the default system space. */
253   public static final String SYSTEM_SPACE = "XWiki";
254  
255   /** Name of the default space homepage. */
256   public static final String DEFAULT_SPACE_HOMEPAGE = "WebHome";
257  
258   public static final String CKEY_SKIN = InternalSkinManager.CKEY_SKIN;
259  
260   public static final String CKEY_BASESKIN = InternalSkinManager.CKEY_PARENTSKIN;
261  
262   public static final String DEFAULT_SKIN = InternalSkinConfiguration.DEFAULT_SKIN;
263  
264   /** Logging helper object. */
265   protected static final Logger LOGGER = LoggerFactory.getLogger(XWiki.class);
266  
267   /** Frequently used Document reference, the class which holds virtual wiki definitions. */
268   private static final DocumentReference VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE =
269   new DocumentReference(DEFAULT_MAIN_WIKI, SYSTEM_SPACE, "XWikiServerClass");
270  
271   /** The default encoding, and the internally used encoding when dealing with byte representation of strings. */
272   public static final String DEFAULT_ENCODING = "UTF-8";
273  
274   /** Represents no value (ie the default value will be used) in xproperties */
275   private static final String NO_VALUE = "---";
276  
277   /**
278   * List of top level space names that can be used in the fake context document created when accessing a resource
279   * with the 'skin' action.
280   */
281   private static final List SKIN_RESOURCE_SPACE_NAMES = Arrays.asList("skins", "resources");
282  
283   /** The main document storage. */
284   private XWikiStoreInterface store;
285  
286   /** The attachment content storage. */
287   private XWikiAttachmentStoreInterface defaultAttachmentContentStore;
288  
289   /** The attachment archive storage. */
290   private AttachmentVersioningStore defaultAttachmentArchiveStore;
291  
292   /** Document versioning storage. */
293   private XWikiVersioningStoreInterface versioningStore;
294  
295   /** Deleted documents storage. */
296   private XWikiRecycleBinStoreInterface recycleBinStore;
297  
298   private AttachmentRecycleBinStore attachmentRecycleBinStore;
299  
300   private XWikiPluginManager pluginManager;
301  
302   private XWikiAuthService authService;
303  
304   private XWikiRightService rightService;
305  
306   private XWikiGroupService groupService;
307  
308   private XWikiStatsService statsService;
309  
310   private XWikiURLFactoryService urlFactoryService;
311  
312   private XWikiCriteriaService criteriaService;
313  
314   /** Lock object used for the lazy initialization of the authentication service. */
315   private final Object AUTH_SERVICE_LOCK = new Object();
316  
317   /** Lock object used for the lazy initialization of the authorization service. */
318   private final Object RIGHT_SERVICE_LOCK = new Object();
319  
320   /** Lock object used for the lazy initialization of the group management service. */
321   private final Object GROUP_SERVICE_LOCK = new Object();
322  
323   /** Lock object used for the lazy initialization of the statistics service. */
324   private final Object STATS_SERVICE_LOCK = new Object();
325  
326   /** Lock object used for the lazy initialization of the URL Factory service. */
327   private final Object URLFACTORY_SERVICE_LOCK = new Object();
328  
329   private MetaClass metaclass;
330  
331   private String version;
332  
333   private XWikiEngineContext engine_context;
334  
335   private String database;
336  
337   private String fullNameSQL;
338  
339   /**
340   * The list of initialized wikis.
341   */
342   private Map initializedWikis = new ConcurrentHashMap<>();
343  
344   private boolean isReadOnly = false;
345  
346   /**
347   * @deprecated since 6.1M2, use {@link XWikiCfgConfigurationSource#CFG_ENV_NAME} instead
348   */
349   @Deprecated
350   public static final String CFG_ENV_NAME = XWikiCfgConfigurationSource.CFG_ENV_NAME;
351  
352   public static final String MACROS_FILE = "/templates/macros.txt";
353  
354   /**
355   * File containing XWiki's version, in the format: ..
356   */
357   private static final String VERSION_FILE = "/WEB-INF/version.properties";
358  
359   /**
360   * Property containing the version value in the {@link #VERSION_FILE} file.
361   */
362   private static final String VERSION_FILE_PROPERTY = "version";
363  
364   private static XWikiInitializerJob job;
365  
366   /** List of configured syntax ids. */
367   private List configuredSyntaxes;
368  
369   /** Used to convert a proper Document Reference to string (standard form). */
370   private EntityReferenceSerializer defaultEntityReferenceSerializer;
371  
372   /**
373   * Used to resolve a string into a proper Document Reference using the current document's reference to fill the
374   * blanks, except for the page name for which the default page name is used instead.
375   */
376   private DocumentReferenceResolver currentMixedDocumentReferenceResolver;
377  
378   private DocumentReferenceResolver currentReferenceDocumentReferenceResolver;
379  
380   private EntityReferenceResolver currentMixedEntityReferenceResolver;
381  
382   private EntityReferenceResolver relativeEntityReferenceResolver;
383  
384   private EntityReferenceSerializer localStringEntityReferenceSerializer;
385  
386   private ResourceReferenceManager resourceReferenceManager;
387  
388   private JobExecutor jobExecutor;
389  
390   private InternalSkinManager internalSkinManager;
391  
392   private TemplateManager templateManager;
393  
394   private RenderingContext renderingContext;
395  
396   private VelocityEvaluator velocityEvaluator;
397  
398   /**
399   * Whether backlinks are enabled or not (cached for performance).
400   *
401   * @since 3.2M2
402   */
403   private Boolean hasBacklinks;
404  
405   private ConfigurationSource xwikicfg;
406  
407   private ConfigurationSource wikiConfiguration;
408  
409   private ConfigurationSource userConfiguration;
410  
411   private ConfigurationSource spaceConfiguration;
412  
413   private EditConfiguration editConfiguration;
414  
415   private StoreConfiguration storeConfiguration;
416  
417   private ObservationManager observationManager;
418  
419   private Provider xcontextProvider;
420  
421   private ContextualLocalizationManager localization;
422  
423   private Provider oldRenderingProvider;
424  
425   private ParseGroovyFromString parseGroovyFromString;
426  
427   private JobProgressManager progress;
428  
429   private Provider defaultDocumentReferenceProvider;
430  
431   private DocumentReferenceResolver currentgetdocumentResolver;
432  
433   private PageReferenceResolver currentgetpageResolver;
434  
435   private AttachmentReferenceResolver currentAttachmentReferenceResolver;
436  
437   private WikiSkinUtils wikiSkinUtils;
438  
439   private DocumentRevisionProvider documentRevisionProvider;
440  
441   private WikiDescriptorManager wikiDescriptorManager;
442  
443   private AsyncContext asyncContext;
444  
445   private ConfigurationSource getConfiguration()
446   {
447   if (this.xwikicfg == null) {
448   this.xwikicfg = Utils.getComponent(ConfigurationSource.class, XWikiCfgConfigurationSource.ROLEHINT);
449   }
450  
451   return this.xwikicfg;
452   }
453  
454   private ConfigurationSource getWikiConfiguration()
455   {
456   if (this.wikiConfiguration == null) {
457   this.wikiConfiguration = Utils.getComponent(ConfigurationSource.class, "wiki");
458   }
459  
460   return this.wikiConfiguration;
461   }
462  
463   private ConfigurationSource getSpaceConfiguration()
464   {
465   if (this.spaceConfiguration == null) {
466   this.spaceConfiguration = Utils.getComponent(ConfigurationSource.class, "space");
467   }
468  
469   return this.spaceConfiguration;
470   }
471  
472   private ConfigurationSource getUserConfiguration()
473   {
474   if (this.userConfiguration == null) {
475   this.userConfiguration = Utils.getComponent(ConfigurationSource.class, "user");
476   }
477  
478   return this.userConfiguration;
479   }
480  
481   private EditConfiguration getEditConfiguration()
482   {
483   if (this.editConfiguration == null) {
484   this.editConfiguration = Utils.getComponent(EditConfiguration.class);
485   }
486  
487   return this.editConfiguration;
488   }
489  
490   private StoreConfiguration getStoreConfiguration()
491   {
492   if (this.storeConfiguration == null) {
493   this.storeConfiguration = Utils.getComponent(StoreConfiguration.class);
494   }
495  
496   return this.storeConfiguration;
497   }
498  
499   private InternalSkinManager getInternalSkinManager()
500   {
501   if (this.internalSkinManager == null) {
502   this.internalSkinManager = Utils.getComponent(InternalSkinManager.class);
503   }
504  
505   return this.internalSkinManager;
506   }
507  
508   private TemplateManager getTemplateManager()
509   {
510   if (this.templateManager == null) {
511   this.templateManager = Utils.getComponent(TemplateManager.class);
512   }
513  
514   return this.templateManager;
515   }
516  
517   private RenderingContext getRenderingContext()
518   {
519   if (this.renderingContext == null) {
520   this.renderingContext = Utils.getComponent(RenderingContext.class);
521   }
522  
523   return this.renderingContext;
524   }
525  
526   private MutableRenderingContext getMutableRenderingContext()
527   {
528   return getRenderingContext() instanceof MutableRenderingContext
529   ? (MutableRenderingContext) getRenderingContext() : null;
530   }
531  
532   private VelocityEvaluator getVelocityEvaluator()
533   {
534   if (this.velocityEvaluator == null) {
535   this.velocityEvaluator = Utils.getComponent(VelocityEvaluator.class);
536   }
537  
538   return this.velocityEvaluator;
539   }
540  
541   private ObservationManager getObservationManager()
542   {
543   if (this.observationManager == null) {
544   this.observationManager = Utils.getComponent(ObservationManager.class);
545   }
546  
547   return this.observationManager;
548   }
549  
550   private XWikiContext getXWikiContext()
551   {
552   if (this.xcontextProvider == null) {
553   this.xcontextProvider = Utils.getComponent(XWikiContext.TYPE_PROVIDER);
554   }
555  
556   return this.xcontextProvider.get();
557   }
558  
559   private ContextualLocalizationManager getLocalization()
560   {
561   if (this.localization == null) {
562   this.localization = Utils.getComponent(ContextualLocalizationManager.class);
563   }
564  
565   return this.localization;
566   }
567  
568   private OldRendering getOldRendering()
569   {
570   if (this.oldRenderingProvider == null) {
571   this.oldRenderingProvider = Utils.getComponent(OldRendering.TYPE_PROVIDER);
572   }
573  
574   return this.oldRenderingProvider.get();
575   }
576  
577   private ParseGroovyFromString getParseGroovyFromString()
578   {
579   if (this.parseGroovyFromString == null) {
580   this.parseGroovyFromString = Utils.getComponent(ParseGroovyFromString.class);
581   }
582  
583   return this.parseGroovyFromString;
584   }
585  
586   private JobProgressManager getProgress()
587   {
588   if (this.progress == null) {
589   this.progress = Utils.getComponent(JobProgressManager.class);
590   }
591  
592   return this.progress;
593   }
594  
595   private Provider getDefaultDocumentReferenceProvider()
596   {
597   if (this.defaultDocumentReferenceProvider == null) {
598   this.defaultDocumentReferenceProvider = Utils.getComponent(DocumentReference.TYPE_PROVIDER);
599   }
600  
601   return this.defaultDocumentReferenceProvider;
602   }
603  
604   private DocumentReferenceResolver getCurrentGetDocumentResolver()
605   {
606   if (this.currentgetdocumentResolver == null) {
607   this.currentgetdocumentResolver =
608   Utils.getComponent(DocumentReferenceResolver.TYPE_REFERENCE, "currentgetdocument");
609   }
610  
611   return this.currentgetdocumentResolver;
612   }
613  
614   private PageReferenceResolver getCurrentGetPageResolver()
615   {
616   if (this.currentgetpageResolver == null) {
617   this.currentgetpageResolver = Utils.getComponent(PageReferenceResolver.TYPE_REFERENCE, "currentgetpage");
618   }
619  
620   return this.currentgetpageResolver;
621   }
622  
623   private AttachmentReferenceResolver getCurrentAttachmentResolver()
624   {
625   if (this.currentAttachmentReferenceResolver == null) {
626   this.currentAttachmentReferenceResolver =
627   Utils.getComponent(AttachmentReferenceResolver.TYPE_REFERENCE, "current");
628   }
629  
630   return this.currentAttachmentReferenceResolver;
631   }
632  
633   private EntityReferenceSerializer getDefaultEntityReferenceSerializer()
634   {
635   if (this.defaultEntityReferenceSerializer == null) {
636   this.defaultEntityReferenceSerializer = Utils.getComponent(EntityReferenceSerializer.TYPE_STRING);
637   }
638  
639   return this.defaultEntityReferenceSerializer;
640   }
641  
642   private DocumentReferenceResolver getCurrentMixedDocumentReferenceResolver()
643   {
644   if (this.currentMixedDocumentReferenceResolver == null) {
645   this.currentMixedDocumentReferenceResolver =
646   Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, "currentmixed");
647   }
648  
649   return this.currentMixedDocumentReferenceResolver;
650   }
651  
652   private DocumentReferenceResolver getCurrentReferenceDocumentReferenceResolver()
653   {
654   if (this.currentReferenceDocumentReferenceResolver == null) {
655   this.currentReferenceDocumentReferenceResolver =
656   Utils.getComponent(DocumentReferenceResolver.TYPE_REFERENCE, "current");
657   }
658  
659   return this.currentReferenceDocumentReferenceResolver;
660   }
661  
662   private EntityReferenceResolver getCurrentMixedEntityReferenceResolver()
663   {
664   if (this.currentMixedEntityReferenceResolver == null) {
665   this.currentMixedEntityReferenceResolver =
666   Utils.getComponent(EntityReferenceResolver.TYPE_STRING, "currentmixed");
667   }
668  
669   return this.currentMixedEntityReferenceResolver;
670   }
671  
672   private EntityReferenceResolver getRelativeEntityReferenceResolver()
673   {
674   if (this.relativeEntityReferenceResolver == null) {
675   this.relativeEntityReferenceResolver = Utils.getComponent(EntityReferenceResolver.TYPE_STRING, "relative");
676   }
677  
678   return this.relativeEntityReferenceResolver;
679   }
680  
681   private EntityReferenceSerializer getLocalStringEntityReferenceSerializer()
682   {
683   if (this.localStringEntityReferenceSerializer == null) {
684   this.localStringEntityReferenceSerializer =
685   Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, "local");
686   }
687  
688   return this.localStringEntityReferenceSerializer;
689   }
690  
691   private ResourceReferenceManager getResourceReferenceManager()
692   {
693   if (this.resourceReferenceManager == null) {
694   this.resourceReferenceManager = Utils.getComponent(ResourceReferenceManager.class);
695   }
696  
697   return this.resourceReferenceManager;
698   }
699  
700   private JobExecutor getJobExecutor()
701   {
702   if (this.jobExecutor == null) {
703   this.jobExecutor = Utils.getComponent(JobExecutor.class);
704   }
705  
706   return this.jobExecutor;
707   }
708  
709   private DocumentReference getDefaultDocumentReference()
710   {
711   return getDefaultDocumentReferenceProvider().get();
712   }
713  
714   private WikiSkinUtils getWikiSkinUtils()
715   {
716   if (this.wikiSkinUtils == null) {
717   this.wikiSkinUtils = Utils.getComponent(WikiSkinUtils.class);
718   }
719  
720   return this.wikiSkinUtils;
721   }
722  
723   private DocumentRevisionProvider getDocumentRevisionProvider()
724   {
725   if (this.documentRevisionProvider == null) {
726   this.documentRevisionProvider = Utils.getComponent(DocumentRevisionProvider.class);
727   }
728  
729   return this.documentRevisionProvider;
730   }
731  
732   private WikiDescriptorManager getWikiDescriptorManager()
733   {
734   if (this.wikiDescriptorManager == null) {
735   this.wikiDescriptorManager = Utils.getComponent(WikiDescriptorManager.class);
736   }
737  
738   return this.wikiDescriptorManager;
739   }
740  
741   private AsyncContext getAsyncContext()
742   {
743   if (this.asyncContext == null) {
744   this.asyncContext = Utils.getComponent(AsyncContext.class);
745   }
746  
747   return this.asyncContext;
748   }
749  
750   private String localizePlainOrKey(String key, Object... parameters)
751   {
752   return StringUtils.defaultString(getLocalization().getTranslationPlain(key, parameters), key);
753   }
754  
755   /**
756   * @param context see {@link XWikiContext}
757   */
758   public static XWiki getMainXWiki(XWikiContext context) throws XWikiException
759   {
760   return getMainXWiki(true, context);
761   }
762  
763   /**
764   * @param wait true if the method should way for {@link XWiki} instance to be initialized
765   * @param context see {@link XWikiContext}
766   */
767   public static XWiki getMainXWiki(boolean wait, XWikiContext context) throws XWikiException
768   {
769   String xwikiname = DEFAULT_MAIN_WIKI;
770  
771   context.setMainXWiki(xwikiname);
772  
773   XWiki xwiki;
774  
775   try {
776   XWikiEngineContext econtext = context.getEngineContext();
777  
778   xwiki = (XWiki) econtext.getAttribute(xwikiname);
779   if (xwiki == null) {
780   // Start XWiki initialization
781   synchronized (XWiki.class) {
782   xwiki = (XWiki) econtext.getAttribute(xwikiname);
783   if (xwiki == null && job == null) {
784   job = Utils.getComponent((Type) Job.class, XWikiInitializerJob.JOBTYPE);
785  
786   if (job.getStatus() == null) {
787   // "Pre-initialize" XWikiStubContextProvider so that XWiki initializer can find one
788   Utils.getComponent(XWikiStubContextProvider.class)
789   .initialize(context);
790  
791   job.startAsync();
792   }
793   }
794   }
795  
796   // Wait until XWiki is initialized
797   if (wait) {
798   job.join();
799   xwiki = (XWiki) econtext.getAttribute(xwikiname);
800   }
801   }
802  
803   context.setWiki(xwiki);
804  
805   return xwiki;
806   } catch (Exception e) {
807   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
808   "Could not initialize main XWiki instance", e);
809   }
810   }
811  
812   public static boolean isInitializing(XWikiContext xcontext)
813   {
814   return Boolean.TRUE.equals(xcontext.getEngineContext().getAttribute("xwiki.init"));
815   }
816  
817   /**
818   * Return the XWiki object (as in "the Wiki API") corresponding to the requested wiki.
819   *
820   * @param context see {@link XWikiContext}
821   * @return an XWiki object configured for the wiki corresponding to the current request
822   * @throws XWikiException if the requested URL does not correspond to a real wiki, or if there's an error in the
823   * storage
824   */
825   public static XWiki getXWiki(XWikiContext context) throws XWikiException
826   {
827   return getXWiki(true, context);
828   }
829  
830   /**
831   * Return the XWiki object (as in "the Wiki API") corresponding to the requested wiki.
832   *

833   * Unless wait is false the method return right away null if XWiki is not yet initialized.
834   *
835   * @param wait wait until XWiki is initialized
836   * @param xcontext see {@link XWikiContext}
837   * @return an XWiki object configured for the wiki corresponding to the current request
838   * @throws XWikiException if the requested URL does not correspond to a real wiki, or if there's an error in the
839   * storage
840   */
841   public static XWiki getXWiki(boolean wait, XWikiContext xcontext) throws XWikiException
842   {
843   XWiki xwiki = getMainXWiki(wait, xcontext);
844  
845   if (xwiki == null) {
846   return null;
847   }
848  
849   // Extract Entity Resource from URL and put it in the Execution Context
850   EntityResourceReference entityResourceReference = initializeResourceFromURL(xcontext);
851  
852   // If not an entity resource reference assume main wiki
853   if (entityResourceReference == null) {
854   return xwiki;
855   }
856  
857   // Get the wiki id
858   String wikiId = entityResourceReference.getEntityReference().extractReference(EntityType.WIKI).getName();
859   if (wikiId.equals(xcontext.getMainXWiki())) {
860   // The main wiki was requested.
861   return xwiki;
862   }
863  
864   // Check if the wiki exists by checking if a descriptor exists for the wiki id.
865   WikiDescriptorManager wikiDescriptorManager = Utils.getComponent(WikiDescriptorManager.class);
866   WikiDescriptor descriptor;
867   try {
868   descriptor = wikiDescriptorManager.getById(wikiId);
869   } catch (WikiManagerException e) {
870   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_STORE_MISC,
871   String.format("Failed find wiki descriptor for wiki id [%s]", wikiId), e);
872   }
873   if (descriptor == null) {
874   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_DOES_NOT_EXIST,
875   String.format("The wiki [%s] does not exist", wikiId));
876   }
877  
878   // Initialize wiki
879  
880   xcontext.setWikiId(wikiId);
881   xcontext.setOriginalWikiId(wikiId);
882  
883   if (!xwiki.initializeWiki(wikiId, wait, xcontext)) {
884   // The wiki is still initializing
885   return null;
886   }
887  
888   return xwiki;
889   }
890  
891   /**
892   * @param wikiId the identifier of the wiki
893   * @return the current {@link WikiInitializerJob} associated to the passed wiki or null if there is none
894   */
895   public Job getWikiInitializerJob(String wikiId)
896   {
897   return this.initializedWikis.get(wikiId);
898   }
899  
900   /**
901   * Make sure the wiki is initializing or wait for it.
902   *
903   * @param wikiId the identifier of the wiki to initialize
904   * @param wait true if the method should return only when the wiki is fully initialized
905   * @return true if the wiki is fully initialized
906   * @param xcontext the XWiki context
907   * @throws XWikiException when the initialization failed
908   * @since 8.4RC1
909   */
910   public boolean initializeWiki(String wikiId, boolean wait, XWikiContext xcontext) throws XWikiException
911   {
912   Job wikiJob = this.initializedWikis.get(wikiId);
913  
914   // Create and start the job if it does not exist
915   if (wikiJob == null) {
916   try {
917   wikiJob = initializeWiki(wikiId, xcontext);
918   } catch (JobException e) {
919   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
920   "Could not start [" + wikiId + "] wiki initialization", e);
921   }
922   }
923  
924   // Check if the job is done
925   if (wikiJob.getStatus().getState() == State.FINISHED) {
926   return true;
927   }
928  
929   // Wait until the job is finished if asked to
930   if (wait) {
931   try {
932   wikiJob.join();
933   } catch (InterruptedException e) {
934   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
935   "Wiki [" + wikiId + "] initialization was interrupted unexpectedly", e);
936   }
937  
938   if (wikiJob.getStatus().getError() != null) {
939   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_INIT_FAILED,
940   "Wiki [" + wikiId + "] initialization failed", wikiJob.getStatus().getError());
941   }
942  
943   return true;
944   }
945  
946   // Still initializing
947   return false;
948   }
949  
950   private Job initializeWiki(String wikiId, XWikiContext xcontext) throws JobException
951   {
952   synchronized (this.initializedWikis) {
953   WikiInitializerJob wikiJob = this.initializedWikis.get(wikiId);
954  
955   if (wikiJob == null) {
956   WikiInitializerRequest request = new WikiInitializerRequest(wikiId);
957  
958   JobRequestContext.set(request, xcontext);
959  
960   wikiJob = (WikiInitializerJob) getJobExecutor().execute(WikiInitializerJob.JOBTYPE, request);
961   this.initializedWikis.put(wikiId, wikiJob);
962   }
963  
964   return wikiJob;
965   }
966   }
967  
968   private static EntityResourceReference initializeResourceFromURL(XWikiContext context) throws XWikiException
969   {
970   // Extract the Entity Resource from the URL
971   // TODO: This code should be put in an ExecutionContextInitializer but we couldn't do yet since this code
972   // requires that the XWiki object be initialized first (the line above). Thus we'll be able to to move it only
973   // after the XWiki init is done also in an ExecutionContextInitializer (and with priorities).
974   @SuppressWarnings("deprecation")
975   EntityResourceReference entityResourceReference;
976   URL url = context.getURL();
977   try {
978   ExtendedURL extendedURL = new ExtendedURL(url, context.getRequest().getContextPath());
979   ResourceTypeResolver typeResolver =
980   Utils.getComponent(new DefaultParameterizedType(null, ResourceTypeResolver.class, ExtendedURL.class));
981   ResourceType type = typeResolver.resolve(extendedURL, Collections.emptyMap());
982   ResourceReferenceResolver resourceResolver = Utils
983   .getComponent(new DefaultParameterizedType(null, ResourceReferenceResolver.class, ExtendedURL.class));
984   ResourceReference reference =
985   resourceResolver.resolve(extendedURL, type, Collections.emptyMap());
986   entityResourceReference =
987   reference instanceof EntityResourceReference ? (EntityResourceReference) reference : null;
988   } catch (Exception e) {
989   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_APP_URL_EXCEPTION,
990   String.format("Failed to extract Entity Resource Reference from URL [%s]", url), e);
991   }
992   Utils.getComponent(Execution.class).getContext().setProperty(ResourceReferenceManager.RESOURCE_CONTEXT_PROPERTY,
993   entityResourceReference);
994  
995   return entityResourceReference;
996   }
997  
998   public static URL getRequestURL(XWikiRequest request) throws XWikiException
999   {
1000   try {
1001   StringBuffer requestURL = request.getRequestURL();
1002   String qs = request.getQueryString();
1003   if ((qs != null) && (!qs.equals(""))) {
1004   return new URL(requestURL.toString() + "?" + qs);
1005   } else {
1006   return new URL(requestURL.toString());
1007   }
1008   } catch (Exception e) {
1009   throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_URL_EXCEPTION,
1010   "Exception while getting URL from request", e);
1011   }
1012   }
1013  
1014   public static Object callPrivateMethod(Object obj, String methodName)
1015   {
1016   return callPrivateMethod(obj, methodName, null, null);
1017   }
1018  
1019   public static Object callPrivateMethod(Object obj, String methodName, Class[] classes, Object[] args)
1020   {
1021   try {
1022   Method method = obj.getClass().getDeclaredMethod(methodName, classes);
1023   method.setAccessible(true);
1024   return method.invoke(obj, args);
1025   } catch (IllegalAccessException e) {
1026   LOGGER.error("Failed to call private method [{}]: [{}]", methodName, e);
1027  
1028   return null;
1029   } catch (NoSuchMethodException e) {
1030   return null;
1031   } catch (InvocationTargetException e) {
1032   LOGGER.error("Private method [{}] failed: [{}]", methodName, e);
1033  
1034   return null;
1035   }
1036   }
1037  
1038   public static HttpClient getHttpClient(int timeout, String userAgent)
1039   {
1040   HttpClient client = new HttpClient();
1041  
1042   if (timeout != 0) {
1043   client.getParams().setSoTimeout(timeout);
1044   client.getParams().setParameter("http.connection.timeout", Integer.valueOf(timeout));
1045   }
1046  
1047   client.getParams().setParameter("http.useragent", userAgent);
1048  
1049   String proxyHost = System.getProperty("http.proxyHost");
1050   String proxyPort = System.getProperty("http.proxyPort");
1051   if ((proxyHost != null) && (!proxyHost.equals(""))) {
1052   int port = 3128;
1053   if ((proxyPort != null) && (!proxyPort.equals(""))) {
1054   port = Integer.parseInt(proxyPort);
1055   }
1056   client.getHostConfiguration().setProxy(proxyHost, port);
1057   }
1058  
1059   String proxyUser = System.getProperty("http.proxyUser");
1060   if ((proxyUser != null) && (!proxyUser.equals(""))) {
1061   String proxyPassword = System.getProperty("http.proxyPassword");
1062   Credentials defaultcreds = new UsernamePasswordCredentials(proxyUser, proxyPassword);
1063   client.getState().setProxyCredentials(AuthScope.ANY, defaultcreds);
1064   }
1065  
1066   return client;
1067   }
1068  
1069   /**
1070   * Using reflection, read the private value of the passed field name for the passed object.
1071   *
1072   * @param obj the java object on which to read the private field value
1073   * @param fieldName the object member field for which to read the value
1074   * @return the private value for the field
1075   * @deprecated use {@link FieldUtils#readDeclaredField(Object, String, boolean)} instead
1076   */
1077   @Deprecated
1078   public static Object getPrivateField(Object obj, String fieldName)
1079   {
1080   try {
1081   Field field = obj.getClass().getDeclaredField(fieldName);
1082   field.setAccessible(true);
1083   return field.get(obj);
1084   } catch (NoSuchFieldException e) {
1085   return null;
1086   } catch (IllegalAccessException e) {
1087   LOGGER.error("Failed to get private field with name [{}]: [{}]", fieldName, e);
1088  
1089   return null;
1090   } finally {
1091   }
1092   }
1093  
1094   public static String getServerWikiPage(String servername)
1095   {
1096   return "XWiki.XWikiServer" + StringUtils.capitalize(servername);
1097   }
1098  
1099   /**
1100   * @param content the content of the text area
1101   * @param context see {@link XWikiContext}
1102   */
1103   public static String getTextArea(String content, XWikiContext context)
1104   {
1105   StringBuilder result = new StringBuilder();
1106  
1107   // Forcing a new line after the ");
1113  
1114   return result.toString();
1115   }
1116  
1117   /**
1118   * This provide a way to create an XWiki object without initializing the whole XWiki (including plugins, storage,
1119   * etc.).
1120   *

1121   * Needed for tools or tests which need XWiki because it is used everywhere in the API.
1122   */
1123   public XWiki()
1124   {
1125   // Empty voluntarily
1126   }
1127  
1128   /**
1129   * Initialize all xwiki subsystems.
1130   *
1131   * @param context see {@link XWikiContext}
1132   * @param engineContext the XWiki object wrapping the {@link javax.servlet.ServletContext} and which allows to set
1133   * data that live on as long as the XWiki webapp is not stopped in the Servlet Container
1134   * @param noupdate true if the whole initialization should be done (create mandatory xlcasses, initialize stats
1135   * service), i.e. if this is not an update, and false otherwise
1136   * @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
1137   */
1138   public XWiki(XWikiContext context, XWikiEngineContext engineContext, boolean noupdate) throws XWikiException
1139   {
1140   initXWiki(context, engineContext, noupdate);
1141   }
1142  
1143   /**
1144   * Initialize all xwiki subsystems.
1145   *
1146   * @param context see {@link XWikiContext}
1147   * @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
1148   */
1149   public XWiki(XWikiContext context) throws XWikiException
1150   {
1151   this(context, null, false);
1152   }
1153  
1154   /**
1155   * Initialize all xwiki subsystems.
1156   *
1157   * @param context see {@link XWikiContext}
1158   * @param engineContext the XWiki object wrapping the {@link javax.servlet.ServletContext} and which allows to set
1159   * data that live on as long as the XWiki webapp is not stopped in the Servlet Container
1160   * @param noupdate true if the whole initialization should be done (create mandatory xlcasses, initialize stats
1161   * service), i.e. if this is not an update, and false otherwise
1162   * @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
1163   */
1164   public void initXWiki(XWikiContext context, XWikiEngineContext engineContext, boolean noupdate)
1165   throws XWikiException
1166   {
1167   initXWiki(null, context, engineContext, noupdate);
1168   }
1169  
1170   /**
1171   * Initialize all xwiki subsystems.
1172   *
1173   * @param config the object holding the XWiki configuration read from {@code xwiki.cfg}
1174   * @param context see {@link XWikiContext}
1175   * @param engineContext the XWiki object wrapping the {@link javax.servlet.ServletContext} and which allows to set
1176   * data that live on as long as the XWiki webapp is not stopped in the Servlet Container
1177   * @param noupdate true if the whole initialization should be done (create mandatory xlcasses, initialize stats
1178   * service), i.e. if this is not an update, and false otherwise
1179   * @throws XWikiException if an error happened during initialization (failure to initialize some cache for example)
1180   * @deprecated since 6.1M2, use {@link #initXWiki(XWikiContext, XWikiEngineContext, boolean)} instead
1181   */
1182   @Deprecated
1183   public void initXWiki(XWikiConfig config, XWikiContext context, XWikiEngineContext engineContext, boolean noupdate)
1184   throws XWikiException
1185   {
1186   getProgress().pushLevelProgress(4, this);
1187  
1188   try {
1189   getProgress().startStep(this);
1190  
1191   setDatabase(context.getMainXWiki());
1192  
1193   setEngineContext(engineContext);
1194   context.setWiki(this);
1195  
1196   // "Pre-initialize" XWikiStubContextProvider with a XWikiContext containing a XWiki instance as soon as
1197   // possible
1198   Utils.getComponent(XWikiStubContextProvider.class).initialize(context);
1199  
1200   // Prepare the store
1201   if (config != null) {
1202   setConfig(config);
1203   }
1204  
1205   try {
1206   initializeStores();
1207   } catch (ComponentLookupException e) {
1208   throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_UNKNOWN,
1209   "Failed to initialize stores", e);
1210   }
1211  
1212   setCriteriaService((XWikiCriteriaService) createClassFromConfig("xwiki.criteria.class",
1213   "com.xpn.xwiki.criteria.impl.XWikiCriteriaServiceImpl", context));
1214  
1215   // "Pre-initialize" XWikiStubContextProvider so that rendering engine, plugins or listeners reacting to
1216   // potential document changes can use it
1217   Utils.getComponent(XWikiStubContextProvider.class).initialize(context);
1218  
1219   getProgress().endStep(this);
1220  
1221   getProgress().startStep(this);
1222  
1223   // Make sure these classes exists
1224   if (noupdate) {
1225   initializeMandatoryDocuments(context);
1226   getStatsService(context);
1227   }
1228  
1229   getProgress().endStep(this);
1230  
1231   getProgress().startStep(this);
1232  
1233   // Prepare the Plugin Engine
1234   preparePlugins(context);
1235  
1236   getProgress().endStep(this);
1237  
1238   getProgress().startStep(this);
1239  
1240   String ro = getConfiguration().getProperty("xwiki.readonly", "no");
1241   this.isReadOnly = ("yes".equalsIgnoreCase(ro) || "true".equalsIgnoreCase(ro) || "1".equalsIgnoreCase(ro));
1242  
1243   // Save the configured syntaxes
1244   String syntaxes = getConfiguration().getProperty("xwiki.rendering.syntaxes", "xwiki/1.0");
1245   this.configuredSyntaxes = Arrays.asList(StringUtils.split(syntaxes, " ,"));
1246  
1247   getObservationManager().addListener(this);
1248   } finally {
1249   getProgress().popLevelProgress(this);
1250   }
1251   }
1252  
1253   private void initializeStores() throws ComponentLookupException
1254   {
1255   XWikiStoreInterface mainStore = getStoreConfiguration().getXWikiStore();
1256  
1257   // Check if we need to use the cache store..
1258   if (getStoreConfiguration().isStoreCacheEnabled()) {
1259   XWikiCacheStoreInterface cachestore =
1260   (XWikiCacheStoreInterface) Utils.getComponent(XWikiStoreInterface.class, "cache");
1261   cachestore.setStore(mainStore);
1262   setStore(cachestore);
1263   } else {
1264   setStore(mainStore);
1265   }
1266  
1267   setDefaultAttachmentContentStore(getStoreConfiguration().getXWikiAttachmentStore());
1268   setVersioningStore(getStoreConfiguration().getXWikiVersioningStore());
1269   setDefaultAttachmentArchiveStore(getStoreConfiguration().getAttachmentVersioningStore());
1270   setRecycleBinStore(getStoreConfiguration().getXWikiRecycleBinStore());
1271   setAttachmentRecycleBinStore(getStoreConfiguration().getAttachmentRecycleBinStore());
1272   }
1273  
1274   /**
1275   * Ensure that mandatory classes (ie classes XWiki needs to work properly) exist and create them if they don't
1276   * exist.
1277   *
1278   * @param context see {@link XWikiContext}
1279   */
1280   public void initializeMandatoryDocuments(XWikiContext context)
1281   {
1282   if (context.get("initdone") == null) {
1283   @SuppressWarnings("deprecation")
1284   List initializers =
1285   Utils.getComponentList(MandatoryDocumentInitializer.class);
1286  
1287   // Sort the initializers based on priority. Lower priority values are first.
1288   Collections.sort(initializers, new Comparator()
1289   {
1290   @Override
1291   public int compare(MandatoryDocumentInitializer left, MandatoryDocumentInitializer right)
1292   {
1293   Priority leftPriority = left.getClass().getAnnotation(Priority.class);
1294   int leftPriorityValue =
1295   leftPriority != null ? leftPriority.value() : MandatoryDocumentInitializer.DEFAULT_PRIORITY;
1296  
1297   Priority rightPriority = right.getClass().getAnnotation(Priority.class);
1298   int rightPriorityValue =
1299   rightPriority != null ? rightPriority.value() : MandatoryDocumentInitializer.DEFAULT_PRIORITY;
1300  
1301   // Compare the two.
1302   return leftPriorityValue - rightPriorityValue;
1303   }
1304   });
1305  
1306   for (MandatoryDocumentInitializer initializer : initializers) {
1307   initializeMandatoryDocument(initializer, context);
1308   }
1309   }
1310   }
1311  
1312   private void initializeMandatoryDocument(String wiki, MandatoryDocumentInitializer initializer,
1313   XWikiContext context)
1314   {
1315   String currentWiki = context.getWikiId();
1316  
1317   try {
1318   context.setWikiId(wiki);
1319  
1320   initializeMandatoryDocument(initializer, context);
1321   } finally {
1322   context.setWikiId(currentWiki);
1323   }
1324   }
1325  
1326   private void initializeMandatoryDocument(MandatoryDocumentInitializer initializer, XWikiContext context)
1327   {
1328   try {
1329   DocumentReference documentReference =
1330   getCurrentReferenceDocumentReferenceResolver().resolve(initializer.getDocumentReference());
1331  
1332   if (documentReference.getWikiReference().getName().equals(context.getWikiId())) {
1333   XWikiDocument document = context.getWiki().getDocument(documentReference, context);
1334  
1335   if (initializer.updateDocument(document)) {
1336   saveDocument(document,
1337   localizePlainOrKey("core.model.xclass.mandatoryUpdateProperty.versionSummary"), context);
1338   }
1339   }
1340   } catch (XWikiException e) {
1341   LOGGER.error("Failed to initialize mandatory document", e);
1342   }
1343   }
1344  
1345   public XWikiStoreInterface getNotCacheStore()
1346   {
1347   XWikiStoreInterface store = getStore();
1348   if (store instanceof XWikiCacheStoreInterface) {
1349   store = ((XWikiCacheStoreInterface) store).getStore();
1350   }
1351   return store;
1352   }
1353  
1354   public XWikiHibernateStore getHibernateStore()
1355   {
1356   XWikiStoreInterface store = getStore();
1357   if (store instanceof XWikiHibernateStore) {
1358   return (XWikiHibernateStore) store;
1359   } else if (store instanceof XWikiCacheStoreInterface) {
1360   store = ((XWikiCacheStoreInterface) store).getStore();
1361   if (store instanceof XWikiHibernateStore) {
1362   return (XWikiHibernateStore) store;
1363   } else {
1364   return null;
1365   }
1366   } else {
1367   return null;
1368   }
1369   }
1370  
1371   /**
1372   * @param wikiId the id of the wiki
1373   * @param context see {@link XWikiContext}
1374   * @deprecated since 8.4RC1, use {@link #initializeWiki(String, boolean, XWikiContext)} instead
1375   */
1376   @Deprecated
1377   public void updateDatabase(String wikiId, XWikiContext context) throws HibernateException, XWikiException
1378   {
1379   updateDatabase(wikiId, false, context);
1380   }
1381  
1382   /**
1383   * @param wikiId the id of the wiki
1384   * @param context see {@link XWikiContext}
1385   * @deprecated since 8.4RC1, use {@link #initializeWiki(String, boolean, XWikiContext)} instead
1386   */
1387   @Deprecated
1388   public void updateDatabase(String wikiId, boolean force, XWikiContext context)
1389   throws HibernateException, XWikiException
1390   {
1391   updateDatabase(wikiId, force, true, context);
1392   }
1393  
1394   /**
1395   * @param wikiId the id of the wiki
1396   * @param force if the update of the databse should be forced
1397   * @param initDocuments if mandatory document and plugin should be initialized for passed wiki
1398   * @param context see {@link XWikiContext}
1399   * @deprecated since 8.4RC1, use {@link #initializeWiki(String, boolean, XWikiContext)} instead
1400   */
1401   @Deprecated
1402   public void updateDatabase(String wikiId, boolean force, boolean initDocuments, XWikiContext context)
1403   throws HibernateException, XWikiException
1404   {
1405   initializeWiki(wikiId, true, context);
1406   }
1407  
1408   /**
1409   * @return a cached list of all active virtual wikis (i.e. wikis who have been hit by a user request). To get a full
1410   * list of all virtual wikis database names use {@link WikiDescriptorManager#getAllIds()}.
1411   * @deprecated
1412   */
1413   @Deprecated
1414   public List getVirtualWikiList()
1415   {
1416   return new ArrayList<>(this.initializedWikis.keySet());
1417   }
1418  
1419   /**
1420   * @param context see {@link XWikiContext}
1421   * @return the full list of all wiki names of all defined wikis. The wiki names are computed from the names of
1422   * documents having a {@code XWiki.XWikiServerClass} object attached to them by removing the
1423   * {@code XWiki.XWikiServer} prefix and making it lower case. For example a page named
1424   * {@code XWiki.XWikiServerMyDatabase} would return {@code mydatabase} as the wiki name. This list will also
1425   * contain the main wiki.
1426   *

1427   * Note: the wiki name is commonly also the name of the database where the wiki's data is stored. However,
1428   * if configured accordingly, the database can be diferent from the wiki name, like for example when setting
1429   * a wiki database prefix.
1430   * @deprecated since 5.3, use {@link WikiDescriptorManager#getAllIds()} instead
1431   */
1432   @Deprecated
1433   public List getVirtualWikisDatabaseNames(XWikiContext context) throws XWikiException
1434   {
1435   WikiDescriptorManager descriptorManager = Utils.getComponent(WikiDescriptorManager.class);
1436  
1437   try {
1438   return new ArrayList(descriptorManager.getAllIds());
1439   } catch (WikiManagerException e) {
1440   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_UNKNOWN,
1441   "Failed to get the list of wikis", e);
1442   }
1443   }
1444  
1445   /**
1446   * @return the cache containing the names of the wikis already initialized.
1447   * @since 1.5M2.
1448   * @deprecated
1449   */
1450   @Deprecated
1451   public Cache getVirtualWikiCache()
1452   {
1453   return null;
1454   }
1455  
1456   /**
1457   * Get the reference of the owner for the provider wiki.
1458   *
1459   * @param wikiName the technical name of the wiki
1460   * @param context see {@link XWikiContext}
1461   * @return the wiki owner or null if none is set
1462   * @throws XWikiException failed to get wiki descriptor document
1463   */
1464   public String getWikiOwner(String wikiName, XWikiContext context) throws XWikiException
1465   {
1466   String wikiOwner;
1467  
1468   String currentdatabase = context.getWikiId();
1469   try {
1470   context.setWikiId(context.getMainXWiki());
1471  
1472   String serverwikipage = getServerWikiPage(wikiName);
1473   XWikiDocument doc = getDocument(serverwikipage, context);
1474  
1475   if (doc.isNew()) {
1476   if (!context.isMainWiki(wikiName)) {
1477   throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_DOES_NOT_EXIST,
1478   "The wiki " + wikiName + " does not exist");
1479   } else {
1480   wikiOwner = null;
1481   }
1482   } else {
1483   wikiOwner = doc.getStringValue(VIRTUAL_WIKI_DEFINITION_CLASS_REFERENCE, "owner");
1484   if (wikiOwner.indexOf(':') == -1) {
1485   wikiOwner = context.getMainXWiki() + ":" + wikiOwner;
1486   }
1487   }
1488   } finally {
1489   context.setWikiId(currentdatabase);
1490   }
1491  
1492   return wikiOwner;
1493   }
1494  
1495   /**
1496   * @param context see {@link XWikiContext}
1497   */
1498   protected Object createClassFromConfig(String param, String defClass, XWikiContext context) throws XWikiException
1499   {
1500   String storeclass = getConfiguration().getProperty(param, defClass);
1501   try {
1502   Class[] classes = new Class[] { XWikiContext.class };
1503   Object[] args = new Object[] { context };
1504   Object result = Class.forName(storeclass).getConstructor(classes).newInstance(args);
1505   return result;
1506   } catch (Exception e) {
1507   Throwable ecause = e;
1508   if (e instanceof InvocationTargetException) {
1509   ecause = ((InvocationTargetException) e).getTargetException();
1510   }
1511   Object[] args = { param, storeclass };
1512   throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
1513   XWikiException.ERROR_XWIKI_STORE_CLASSINVOCATIONERROR, "Cannot load class {1} from param {0}", ecause,
1514   args);
1515   }
1516   }
1517  
1518   private void preparePlugins(XWikiContext context)
1519   {
1520   setPluginManager(new XWikiPluginManager(getXWikiPreference("plugins", context), context));
1521   String plugins = getConfiguration().getProperty("xwiki.plugins", "");
1522   if (!plugins.equals("")) {
1523   getPluginManager().addPlugins(StringUtils.split(plugins, " ,"), context);
1524   }
1525   }
1526  
1527   /**
1528   * @return the XWiki core version as specified in the {@link #VERSION_FILE} file
1529   */
1530   @SuppressWarnings("deprecation")
1531   public String getVersion()
1532   {
1533   if (this.version == null) {
1534   try {
1535   InputStream is = getResourceAsStream(VERSION_FILE);
1536   try {
1537   XWikiConfig properties = new XWikiConfig(is);
1538   this.version = properties.getProperty(VERSION_FILE_PROPERTY);
1539   } finally {
1540   IOUtils.closeQuietly(is);
1541   }
1542   } catch (Exception e) {
1543   // Failed to retrieve the version, log a warning and default to "Unknown"
1544   LOGGER.warn("Failed to retrieve XWiki's version from [" + VERSION_FILE + "], using the ["
1545   + VERSION_FILE_PROPERTY + "] property.", e);
1546   this.version = "Unknown version";
1547   }
1548   }
1549   return this.version;
1550   }
1551  
1552   public URL getResource(String s) throws MalformedURLException
1553   {
1554   return getEngineContext().getResource(s);
1555   }
1556  
1557   public InputStream getResourceAsStream(String s) throws MalformedURLException
1558   {
1559   InputStream is = getEngineContext().getResourceAsStream(s);
1560   if (is == null) {
1561   is = getEngineContext().getResourceAsStream("/" + s);
1562   }
1563   return is;
1564   }
1565  
1566   public String getResourceContent(String name) throws IOException
1567   {
1568   if (getEngineContext() != null) {
1569   try (InputStream is = getResourceAsStream(name)) {
1570   if (is != null) {
1571   return IOUtils.toString(is, DEFAULT_ENCODING);
1572   }
1573   }
1574   }
1575   // Resources should always be encoded as UTF-8, to reduce the dependency on the system encoding
1576   return FileUtils.readFileToString(new File(name), DEFAULT_ENCODING);
1577   }
1578  
1579   public Date getResourceLastModificationDate(String name)
1580   {
1581   try {
1582   if (getEngineContext() != null) {
1583   return Util.getFileLastModificationDate(getEngineContext().getRealPath(name));
1584   }
1585   } catch (Exception ex) {
1586   // Probably a SecurityException or the file is not accessible (inside a war)
1587   LOGGER.info("Failed to get file modification date: " + ex.getMessage());
1588   }
1589   return new Date();
1590   }
1591  
1592   public byte[] getResourceContentAsBytes(String name) throws IOException
1593   {
1594   if (getEngineContext() != null) {
1595   try (InputStream is = getResourceAsStream(name)) {
1596   if (is != null) {
1597   return IOUtils.toByteArray(is);
1598   }
1599   } catch (Exception e) {
1600   }
1601   }
1602   return FileUtils.readFileToByteArray(new File(name));
1603   }
1604  
1605   public boolean resourceExists(String name)
1606   {
1607   if (getEngineContext() != null) {
1608   try {
1609   if (getResource(name) != null) {
1610   return true;
1611   }
1612   } catch (IOException e) {
1613   }
1614   }
1615   try {
1616   File file = new File(name);
1617   return file.exists();
1618   } catch (Exception e) {
1619   // Could be running under -security, which prevents calling file.exists().
1620   }
1621   return false;
1622   }
1623  
1624   public String getRealPath(String path)
1625   {
1626   return getEngineContext().getRealPath(path);
1627   }
1628  
1629   public String ParamAsRealPath(String key)
1630   {
1631   String param = getConfiguration().getProperty(key);
1632   try {
1633   return getRealPath(param);
1634   } catch (Exception e) {
1635   return param;
1636   }
1637   }
1638  
1639   /**
1640   * @param context see {@link XWikiContext}
1641   */
1642   public String ParamAsRealPath(String key, XWikiContext context)
1643   {
1644   return ParamAsRealPath(key);
1645   }
1646  
1647   public String ParamAsRealPathVerified(String param)
1648   {
1649   String path;
1650   File fpath;
1651  
1652   path = getConfiguration().getProperty(param);
1653   if (path == null) {
1654   return null;
1655   }
1656  
1657   fpath = new File(path);
1658   if (fpath.exists()) {
1659   return path;
1660   }
1661  
1662   path = getRealPath(path);
1663   if (path == null) {
1664   return null;
1665   }
1666  
1667   fpath = new File(path);
1668   if (fpath.exists()) {
1669   return path;
1670   } else {
1671   }
1672   return null;
1673   }
1674  
1675   public XWikiStoreInterface getStore()
1676   {
1677   return this.store;
1678   }
1679  
1680   /**
1681   * @deprecated since 9.9RC1, use {@link #getDefaultAttachmentContentStore()} instead
1682   */
1683   @Deprecated
1684   public XWikiAttachmentStoreInterface getAttachmentStore()
1685   {
1686   return getDefaultAttachmentContentStore();
1687   }
1688  
1689   /**
1690   * @return the store to use by default when saving a new attachment content
1691   * @since 9.10RC1
1692   */
1693   public XWikiAttachmentStoreInterface getDefaultAttachmentContentStore()
1694   {
1695   return this.defaultAttachmentContentStore;
1696   }
1697  
1698   /**
1699   * @return the store to use by default when saving a new attachment archive
1700   * @since 9.10RC1
1701   */
1702   public AttachmentVersioningStore getDefaultAttachmentArchiveStore()
1703   {
1704   return this.defaultAttachmentArchiveStore;
1705   }
1706  
1707   /**
1708   * @deprecated since 9.9RC1, use {@link #getDefaultAttachmentArchiveStore()} instead
1709   */
1710   @Deprecated
1711   public AttachmentVersioningStore getAttachmentVersioningStore()
1712   {
1713   return getDefaultAttachmentArchiveStore();
1714   }
1715  
1716   public XWikiVersioningStoreInterface getVersioningStore()
1717   {
1718   return this.versioningStore;
1719   }
1720  
1721   public XWikiRecycleBinStoreInterface getRecycleBinStore()
1722   {
1723   return this.recycleBinStore;
1724   }
1725  
1726   public AttachmentRecycleBinStore getAttachmentRecycleBinStore()
1727   {
1728   return this.attachmentRecycleBinStore;
1729   }
1730  
1731   /**
1732   * @param doc the document to save
1733   * @param context see {@link XWikiContext}
1734   */
1735   public void saveDocument(XWikiDocument doc, XWikiContext context) throws XWikiException
1736   {
1737   // If no comment is provided we should use an empty comment
1738   saveDocument(doc, "", context);
1739   }
1740  
1741   /**
1742   * @param doc the document to save
1743   * @param comment the comment to associated to the new version of the saved document
1744   * @param context see {@link XWikiContext}
1745   */
1746   public void saveDocument(XWikiDocument doc, String comment, XWikiContext context) throws XWikiException
1747   {
1748   saveDocument(doc, comment, false, context);
1749   }
1750  
1751   /**
1752   * @param document the document to save
1753   * @param comment the comment to associated to the new version of the saved document
1754   * @param isMinorEdit true if the new version is a minor version
1755   * @param context see {@link XWikiContext}
1756   */
1757   public void saveDocument(XWikiDocument document, String comment, boolean isMinorEdit, XWikiContext context)
1758   throws XWikiException
1759   {
1760   String currentWiki = context.getWikiId();
1761  
1762   try {
1763   // Switch to document wiki
1764   context.setWikiId(document.getDocumentReference().getWikiReference().getName());
1765  
1766   // Setting comment & minor edit before saving
1767   document.setComment(StringUtils.defaultString(comment));
1768   document.setMinorEdit(isMinorEdit);
1769  
1770   // We need to save the original document since saveXWikiDoc() will reset it and we
1771   // need that original document for the notification below.
1772   XWikiDocument originalDocument = document.getOriginalDocument();
1773  
1774   // Make sure to always have an original document for listeners that need to compare with it.
1775   // The only case where we have a null original document is supposedly when the document
1776   // instance has been crafted and passed #saveDocument without using #getDocument
1777   // (which is not a good practice)
1778   if (originalDocument == null) {
1779   originalDocument =
1780   getDocument(new DocumentReference(document.getDocumentReference(), document.getLocale()), context);
1781   document.setOriginalDocument(originalDocument);
1782   }
1783  
1784   ObservationManager om = getObservationManager();
1785  
1786   // Notify listeners about the document about to be created or updated
1787  
1788   // Note that for the moment the event being send is a bridge event, as we are still passing around
1789   // an XWikiDocument as source and an XWikiContext as data.
1790  
1791   if (om != null) {
1792   CancelableEvent documentEvent;
1793   if (originalDocument.isNew()) {
1794   documentEvent = new DocumentCreatingEvent(document.getDocumentReference());
1795   } else {
1796   documentEvent = new DocumentUpdatingEvent(document.getDocumentReference());
1797   }
1798   om.notify(documentEvent, document, context);
1799  
1800   // If the action has been canceled by the user then don't perform any save and throw an exception
1801   if (documentEvent.isCanceled()) {
1802   throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
1803   XWikiException.ERROR_XWIKI_STORE_HIBERNATE_SAVING_DOC,
1804   String.format("An Event Listener has cancelled the document save for [%s]. Reason: [%s]",
1805   document.getDocumentReference(), documentEvent.getReason()));
1806   }
1807   }
1808  
1809   // Put attachments to remove in recycle bin
1810   if (hasAttachmentRecycleBin(context)) {
1811   for (XWikiAttachmentToRemove attachment : document.getAttachmentsToRemove()) {
1812   if (attachment.isToRecycleBin()) {
1813   getAttachmentRecycleBinStore().saveToRecycleBin(attachment.getAttachment(), context.getUser(),
1814   new Date(), context, true);
1815   }
1816   }
1817   }
1818  
1819   // Actually save the document.
1820   getStore().saveXWikiDoc(document, context);
1821  
1822   // Since the store#saveXWikiDoc resets originalDocument, we need to temporarily put it
1823   // back to send notifications.
1824   XWikiDocument newOriginal = document.getOriginalDocument();
1825  
1826   try {
1827   document.setOriginalDocument(originalDocument);
1828  
1829   // Notify listeners about the document having been created or updated
1830  
1831   // First the legacy notification mechanism
1832  
1833   // Then the new observation module
1834   // Note that for the moment the event being send is a bridge event, as we are still passing around
1835   // an XWikiDocument as source and an XWikiContext as data.
1836   // The old version is made available using doc.getOriginalDocument()
1837  
1838   if (om != null) {
1839   if (originalDocument.isNew()) {
1840   om.notify(new DocumentCreatedEvent(document.getDocumentReference()), document, context);
1841   } else {
1842   om.notify(new DocumentUpdatedEvent(document.getDocumentReference()), document, context);
1843   }
1844   }
1845   } catch (Exception ex) {
1846   LOGGER.error("Failed to send document save notification for document ["
1847   + getDefaultEntityReferenceSerializer().serialize(document.getDocumentReference()) + "]", ex);
1848   } finally {
1849   document.setOriginalDocument(newOriginal);
1850   }
1851   } finally {
1852   context.setWikiId(currentWiki);
1853   }
1854   }
1855  
1856   /**
1857   * Loads a XWikiDocument from the store.
1858   *

1859   * Before 7.2M1 the reference is assumed to be a complete or incomplete document reference.
1860   *

1861   * Since 7.2M1, the passed reference can be anything. If if a document child, the document reference will be
1862   * extracted from it. If it's a document parent it will be completed with the necessary default references (for
1863   * example if it's a space reference it will load the space home page).
1864   *
1865   * @param reference the reference of teh document
1866   * @param context see {@link XWikiContext}
1867   * @since 5.0M1
1868   */
1869   public XWikiDocument getDocument(EntityReference reference, XWikiContext context) throws XWikiException
1870   {
1871   XWikiDocument document;
1872  
1873   if (reference.getType() == EntityType.PAGE || reference.getType().isAllowedAncestor(EntityType.PAGE)) {
1874   document = getDocument(getCurrentGetPageResolver().resolve(reference), context);
1875   } else {
1876   document = getDocument(getCurrentGetDocumentResolver().resolve(reference), context);
1877   }
1878  
1879   return document;
1880   }
1881  
1882   /**
1883   * Loads a XWikiDocument from the store.
1884   *
1885   * @param reference the reference of the document to be loaded
1886   * @param type the type of the reference
1887   * @return a Document object (if the document couldn't be found a new one is created in memory - but not saved, you
1888   * can check whether it's a new document or not by using {@link com.xpn.xwiki.api.Document#isNew()}
1889   * @throws XWikiException
1890   * @since 10.6RC1
1891   */
1892   @Unstable
1893   public XWikiDocument getDocument(String reference, EntityType type, XWikiContext xcontext) throws XWikiException
1894   {
1895   return getDocument(getRelativeEntityReferenceResolver().resolve(reference, type), xcontext);
1896   }
1897  
1898   /**
1899   * @param doc the document
1900   * @param context see {@link XWikiContext}
1901   */
1902   public XWikiDocument getDocument(XWikiDocument doc, XWikiContext context) throws XWikiException
1903   {
1904   String currentWiki = context.getWikiId();
1905   try {
1906   context.setWikiId(doc.getDocumentReference().getWikiReference().getName());
1907  
1908   try {
1909   // Indicate the the async context manipulated documents
1910   getAsyncContext().useEntity(doc.getDocumentReferenceWithLocale());
1911   } catch (Exception e) {
1912   // If the AsyncContext component does not work then we are not in an asynchronous context anyway
1913   LOGGER.debug("Failed to register the document in the asynchronous context", e);
1914   }
1915  
1916   return getStore().loadXWikiDoc(doc, context);
1917   } finally {
1918   context.setWikiId(currentWiki);
1919   }
1920   }
1921  
1922   /**
1923   * @param reference the reference of the document to load
1924   * @param revision the revision of the document to load
1925   * @param context the XWiki context
1926   * @return the document corresponding to the passed revision or a new XWikiDocument instance if none can be found
1927   * @throws XWikiException when failing to load the document revision
1928   * @since 9.4RC1
1929   * @deprecated sine 9.10RC1, use {@link DocumentRevisionProvider#getRevision(DocumentReference, String)} instead
1930   */
1931   @Deprecated
1932   public XWikiDocument getDocument(DocumentReference reference, String revision, XWikiContext context)
1933   throws XWikiException
1934   {
1935   XWikiDocument revisionDocument = getDocumentRevisionProvider().getRevision(reference, revision);
1936  
1937   if (revisionDocument == null && (revision.equals("1.1") || revision.equals("1.0"))) {
1938   revisionDocument = new XWikiDocument(reference);
1939   }
1940  
1941   return revisionDocument;
1942   }
1943  
1944   /**
1945   * @param document the reference document
1946   * @param revision the revision of the document to load
1947   * @param context the XWiki context
1948   * @return the document corresponding to the passed revision or a new XWikiDocument instance if none can be found
1949   * @throws XWikiException when failing to load the document revision
1950   * @deprecated sine 9.10RC1, use {@link DocumentRevisionProvider#getRevision(XWikiDocument, String)} instead
1951   */
1952   @Deprecated
1953   public XWikiDocument getDocument(XWikiDocument document, String revision, XWikiContext context)
1954   throws XWikiException
1955   {
1956   XWikiDocument revisionDocument = getDocumentRevisionProvider().getRevision(document, revision);
1957  
1958   if (revisionDocument == null && (revision.equals("1.1") || revision.equals("1.0"))) {
1959   revisionDocument = new XWikiDocument(document.getDocumentReference());
1960   }
1961  
1962   return revisionDocument;
1963   }
1964  
1965   /**
1966   * @param reference the reference of the document
1967   * @param context see {@link XWikiContext}
1968   * @since 2.2M1
1969   */
1970   public XWikiDocument getDocument(DocumentReference reference, XWikiContext context) throws XWikiException
1971   {
1972   XWikiDocument doc = new XWikiDocument(
1973   reference.getLocale() != null ? new DocumentReference(reference, (Locale) null) : reference,
1974   reference.getLocale());
1975  
1976   doc.setContentDirty(true);
1977  
1978   return getDocument(doc, context);
1979   }
1980  
1981   /**
1982   * @param reference the reference of the page
1983   * @param context see {@link XWikiContext}
1984   * @since 10.6RC1
1985   */
1986   @Unstable
1987   public XWikiDocument getDocument(PageReference reference, XWikiContext context) throws XWikiException
1988   {
1989   DocumentReference documentReference = getCurrentReferenceDocumentReferenceResolver().resolve(reference);
1990  
1991   XWikiDocument document = getDocument(documentReference, context);
1992  
1993   if (document.isNew() && documentReference.getParent().getParent().getType() == EntityType.SPACE) {
1994   // Try final page
1995   XWikiDocument finalDocument = getDocument(new DocumentReference(documentReference.getParent().getName(),
1996   documentReference.getParent().getParent(), documentReference.getParameters()), context);
1997  
1998   if (!finalDocument.isNew()) {
1999   document = finalDocument;
2000   }
2001   }
2002  
2003   return document;
2004   }
2005  
2006   /**
2007   * Find the document reference corresponding to the entity reference based on what exist in the database (page
2008   * reference can means two different documents for example).
2009   *
2010   * @param reference the reference to resolve
2011   * @param context the XWiki context
2012   * @return the document reference
2013   * @since 10.6RC1
2014   */
2015   @Unstable
2016   public DocumentReference getDocumentReference(EntityReference reference, XWikiContext context)
2017   {
2018   DocumentReference documentReference = getCurrentGetDocumentResolver().resolve(reference);
2019  
2020   // If the document has been found or it's top level space, return the reference
2021   if (documentReference.getParent().getParent().getType() != EntityType.SPACE
2022   || exists(documentReference, context)) {
2023   return documentReference;
2024   }
2025  
2026   // Try final page
2027   DocumentReference finalPageReference = new DocumentReference(documentReference.getParent().getName(),
2028   documentReference.getParent().getParent(), documentReference.getParameters());
2029  
2030   return exists(finalPageReference, context) ? finalPageReference : documentReference;
2031   }
2032  
2033   /**
2034   * @param fullname the reference of the document as String
2035   * @param context see {@link XWikiContext}
2036   * @deprecated since 2.2M1 use {@link #getDocument(DocumentReference, XWikiContext)} instead
2037   */
2038   @Deprecated
2039   public XWikiDocument getDocument(String fullname, XWikiContext context) throws XWikiException
2040   {
2041   XWikiDocument doc = new XWikiDocument();
2042   doc.setFullName(fullname, context);
2043   return getDocument(doc, context);
2044   }
2045  
2046   /**
2047   * @param spaces the reference of the space as String
2048   * @param fullname the reference of the document as String
2049   * @param context see {@link XWikiContext}
2050   * @deprecated since 2.2M1 use {@link #getDocument(DocumentReference, XWikiContext)} instead
2051   */
2052   @Deprecated
2053   public XWikiDocument getDocument(String spaces, String fullname, XWikiContext context) throws XWikiException
2054   {
2055   int dotPosition = fullname.lastIndexOf('.');
2056   if (dotPosition != -1) {
2057   String spaceFromFullname = fullname.substring(0, dotPosition);
2058   String name = fullname.substring(dotPosition + 1);
2059   if (name.equals("")) {
2060   name = getDefaultPage(context);
2061   }
2062   return getDocument(spaceFromFullname + "." + name, context);
2063   } else {
2064   return getDocument(spaces + "." + fullname, context);
2065   }
2066   }
2067  
2068   /**
2069   * @see com.xpn.xwiki.api.XWiki#getDeletedDocuments(String, String)
2070   */
2071   public XWikiDeletedDocument[] getDeletedDocuments(String fullname, String locale, XWikiContext context)
2072   throws XWikiException
2073   {
2074   if (hasRecycleBin(context)) {
2075   XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(fullname));
2076   doc.setLanguage(locale);
2077   return getRecycleBinStore().getAllDeletedDocuments(doc, context, true);
2078   } else {
2079   return null;
2080   }
2081   }
2082  
2083   /**
2084   * @see com.xpn.xwiki.api.XWiki#getDeletedDocuments(String)
2085   * @since 9.4RC1
2086   */
2087   public XWikiDeletedDocument[] getDeletedDocuments(String batchId, XWikiContext context) throws XWikiException
2088   {
2089   if (hasRecycleBin(context)) {
2090   return getRecycleBinStore().getAllDeletedDocuments(batchId, context, true);
2091   } else {
2092   return null;
2093   }
2094   }
2095  
2096   /**
2097   * @see com.xpn.xwiki.api.XWiki#getDeletedDocument(String, String, String)
2098   * @deprecated since 9.4RC1. Use {@link #getDeletedDocument(long, XWikiContext)} instead.
2099   */
2100   @Deprecated
2101   public XWikiDeletedDocument getDeletedDocument(String fullname, String locale, int index, XWikiContext context)
2102   throws XWikiException
2103   {
2104   return getDeletedDocument(index, context);
2105   }
2106  
2107   /**
2108   * @see com.xpn.xwiki.api.XWiki#getDeletedDocument(String)
2109   * @since 9.4RC1
2110   */
2111   public XWikiDeletedDocument getDeletedDocument(long index, XWikiContext context) throws XWikiException
2112   {
2113   if (hasRecycleBin(context)) {
2114   return getRecycleBinStore().getDeletedDocument(index, context, true);
2115   } else {
2116   return null;
2117   }
2118   }
2119  
2120   /**
2121   * Retrieve all the deleted attachments that belonged to a certain document. Note that this does not distinguish
2122   * between different incarnations of a document name, and it does not require that the document still exists, it
2123   * returns all the attachments that at the time of their deletion had a document with the specified name as their
2124   * owner.
2125   *
2126   * @param docName the {@link XWikiDocument#getFullName() name} of the owner document
2127   * @param context see {@link XWikiContext}
2128   * @return A list with all the deleted attachments which belonged to the specified document. If no such attachments
2129   * are found in the trash, an empty list is returned.
2130   * @throws XWikiException if an error occurs while loading the attachments
2131   */
2132   public List getDeletedAttachments(String docName, XWikiContext context) throws XWikiException
2133   {
2134   if (hasAttachmentRecycleBin(context)) {
2135   XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(docName));
2136   return getAttachmentRecycleBinStore().getAllDeletedAttachments(doc, context, true);
2137   }
2138   return null;
2139   }
2140  
2141   /**
2142   * Retrieve all the deleted attachments that belonged to a certain document and had the specified name. Multiple
2143   * versions can be returned since the same file can be uploaded and deleted several times, creating different
2144   * instances in the trash. Note that this does not distinguish between different incarnations of a document name,
2145   * and it does not require that the document still exists, it returns all the attachments that at the time of their
2146   * deletion had a document with the specified name as their owner.
2147   *
2148   * @param docName the {@link DeletedAttachment#getDocName() name of the document} the attachment belonged to
2149   * @param filename the {@link DeletedAttachment#getFilename() name} of the attachment to search for
2150   * @param context see {@link XWikiContext}
2151   * @return A list with all the deleted attachments which belonged to the specified document and had the specified
2152   * filename. If no such attachments are found in the trash, an empty list is returned.
2153   * @throws XWikiException if an error occurs while loading the attachments
2154   */
2155   public List getDeletedAttachments(String docName, String filename, XWikiContext context)
2156   throws XWikiException
2157   {
2158   if (hasAttachmentRecycleBin(context)) {
2159   XWikiDocument doc = new XWikiDocument(getCurrentMixedDocumentReferenceResolver().resolve(docName));
2160   XWikiAttachment attachment = new XWikiAttachment(doc, filename);
2161   return getAttachmentRecycleBinStore().getAllDeletedAttachments(attachment, context, true);
2162   }
2163   return null;
2164   }
2165  
2166   /**
2167   * Retrieve a specific attachment from the trash.
2168   *
2169   * @param id the unique identifier of the entry in the trash
2170   * @param context the XWiki context
2171   * @return specified attachment from the trash, {@code null} if not found
2172   * @throws XWikiException if an error occurs while loading the attachments
2173   */
2174   public DeletedAttachment getDeletedAttachment(String id, XWikiContext context) throws XWikiException
2175   {
2176   if (hasAttachmentRecycleBin(context)) {
2177   return getAttachmentRecycleBinStore().getDeletedAttachment(NumberUtils.toLong(id), context, true);
2178   }
2179   return null;
2180   }
2181  
2182   public MetaClass getMetaclass()
2183   {
2184   if (this.metaclass == null) {
2185   this.metaclass = MetaClass.getMetaClass();
2186   }
2187   return this.metaclass;
2188   }
2189  
2190   public void setMetaclass(MetaClass metaclass)
2191   {
2192   this.metaclass = metaclass;
2193   }
2194  
2195   /**
2196   * @param context see {@link XWikiContext}
2197   */
2198   public List getClassList(XWikiContext context) throws XWikiException
2199   {
2200   List result = getStore().getClassList(context);
2201   Collections.sort(result);
2202   return result;
2203   }
2204  
2205   /**
2206   * @param sql the sql query to execute
2207   * @param context see {@link XWikiContext}
2208   */
2209   public List search(String sql, XWikiContext context) throws XWikiException
2210   {
2211   return getStore().search(sql, 0, 0, context);
2212   }
2213  
2214   /**
2215   * @param sql the sql query to execute
2216   * @param nb limit the number of results to return
2217   * @param start the offset from which to start return results
2218   * @param context see {@link XWikiContext}
2219   */
2220   public List search(String sql, int nb, int start, XWikiContext context) throws XWikiException
2221   {
2222   return getStore().search(sql, nb, start, context);
2223   }
2224  
2225   /**
2226   * @param sql the sql query to execute
2227   * @param context see {@link XWikiContext}
2228   */
2229   public List search(String sql, Object[][] whereParams, XWikiContext context) throws XWikiException
2230   {
2231   return getStore().search(sql, 0, 0, whereParams, context);
2232   }
2233  
2234   /**
2235   * @param sql the sql query to execute
2236   * @param nb limit the number of results to return
2237   * @param start the offset from which to start return results
2238   * @param context see {@link XWikiContext}
2239   */
2240   public List search(String sql, int nb, int start, Object[][] whereParams, XWikiContext context)
2241   throws XWikiException
2242   {
2243   return getStore().search(sql, nb, start, whereParams, context);
2244   }
2245  
2246   /**
2247   * @param content the content to parse
2248   * @param context see {@link XWikiContext}
2249   * @deprecated Since 7.2M1. Use specific rendering/parsing options for the content type you want to parse/render.
2250   */
2251   @Deprecated
2252   public String parseContent(String content, XWikiContext context)
2253   {
2254   return getOldRendering().parseContent(content, context);
2255   }
2256  
2257   /**
2258   * @param template the name of the template
2259   * @param context see {@link XWikiContext}
2260   * @deprecated use {@link #evaluateTemplate(String, XWikiContext)} instead
2261   */
2262   @Deprecated
2263   public String parseTemplate(String template, XWikiContext context)
2264   {
2265   String result = "";
2266  
2267   try {
2268   result = evaluateTemplate(template, context);
2269   } catch (Exception e) {
2270   LOGGER.debug("Exception while parsing template [{}] from /templates/", template, e);
2271   }
2272  
2273   return result;
2274   }
2275  
2276   /**
2277   * Evaluate provided template content using velocity engine.
2278   *
2279   * @param template the template to evaluate
2280   * @param context see {@link XWikiContext}
2281   * @return the return of the velocity script
2282   * @throws IOException failed to get the template content
2283   * @since 2.2.2
2284   * @deprecated since 7.0M1, use {@link TemplateManager#render(String)} instead
2285   */
2286   @Deprecated
2287   public String evaluateTemplate(String template, XWikiContext context) throws IOException
2288   {
2289   try {
2290   return getTemplateManager().render(template);
2291   } catch (Exception e) {
2292   LOGGER.error("Error while evaluating velocity template [{}]", template, e);
2293  
2294   Object[] args = { template };
2295   XWikiException xe = new XWikiException(XWikiException.MODULE_XWIKI_RENDERING,
2296   XWikiException.ERROR_XWIKI_RENDERING_VELOCITY_EXCEPTION, "Error while evaluating velocity template {0}",
2297   e, args);
2298  
2299   return Util.getHTMLExceptionMessage(xe, context);
2300   }
2301   }
2302  
2303   /**
2304   * @param template the name of the template
2305   * @param skinId the id of the skin from which to load the template
2306   * @param context see {@link XWikiContext}
2307   * @deprecated since 7.0M1, use {@link TemplateManager#renderFromSkin} instead
2308   */
2309   @Deprecated
2310   public String parseTemplate(String template, String skinId, XWikiContext context)
2311   {
2312   MutableRenderingContext mutableRenderingContext = getMutableRenderingContext();
2313  
2314   Syntax currentTargetSyntax = mutableRenderingContext.getTargetSyntax();
2315   try {
2316   // Force rendering with XHTML 1.0 syntax for retro-compatibility
2317   mutableRenderingContext.setTargetSyntax(Syntax.XHTML_1_0);
2318  
2319   Skin skin = getInternalSkinManager().getSkin(skinId);
2320   return getTemplateManager().renderFromSkin(template, skin);
2321   } catch (Exception e) {
2322   LOGGER.error("Error while evaluating velocity template [{}] skin [{}]", template, skinId, e);
2323  
2324   Object[] args = { template, skinId };
2325   XWikiException xe = new XWikiException(XWikiException.MODULE_XWIKI_RENDERING,
2326   XWikiException.ERROR_XWIKI_RENDERING_VELOCITY_EXCEPTION,
2327   "Error while evaluating velocity template [{0}] from skin [{1}]", e, args);
2328  
2329   return Util.getHTMLExceptionMessage(xe, context);
2330   } finally {
2331   mutableRenderingContext.setTargetSyntax(currentTargetSyntax);
2332   }
2333   }
2334  
2335   /**
2336   * @param template the name of the template
2337   * @param skin the id of the skin from which to load the template
2338   * @param context see {@link XWikiContext}
2339   */
2340   public String renderTemplate(String template, String skin, XWikiContext context)
2341   {
2342   try {
2343   return getOldRendering().renderTemplate(template, skin, context);
2344   } catch (Exception ex) {
2345   LOGGER.error("Failed to render template [" + template + "] for skin [" + skin + "]", ex);
2346   return parseTemplate(template, skin, context);
2347   }
2348   }
2349  
2350   /**
2351   * @param template the name of the template
2352   * @param context see {@link XWikiContext}
2353   */
2354   public String renderTemplate(String template, XWikiContext context)
2355   {
2356   try {
2357   return getOldRendering().renderTemplate(template, context);
2358   } catch (Exception ex) {
2359   LOGGER.error("Failed to render template [" + template + "]", ex);
2360   return parseTemplate(template, context);
2361   }
2362   }
2363  
2364   /**
2365   * Designed to include dynamic content, such as Servlets or JSPs, inside Velocity templates; works by creating a
2366   * RequestDispatcher, buffering the output, then returning it as a string.
2367   */
2368   public String invokeServletAndReturnAsString(String url, XWikiContext xwikiContext)
2369   {
2370  
2371   HttpServletRequest servletRequest = xwikiContext.getRequest();
2372   HttpServletResponse servletResponse = xwikiContext.getResponse();
2373  
2374   try {
2375   return IncludeServletAsString.invokeServletAndReturnAsString(url, servletRequest, servletResponse);
2376   } catch (Exception e) {
2377   LOGGER.warn("Exception including url: " + url, e);
2378   return "Exception including \"" + url + "\", see logs for details.";
2379   }
2380  
2381   }
2382  
2383   /**
2384   * @param iconName the standard name of an icon (it's not the name of the file on the filesystem, it's a generic
2385   * name, for example "success" for a success icon
2386   * @param context see {@link XWikiContext}
2387   * @return the URL to the icon resource
2388   * @since 2.6M1
2389   */
2390   public String getIconURL(String iconName, XWikiContext context)
2391   {
2392   // TODO: Do a better mapping between generic icon name and physical resource name, especially to be independent
2393   // of the underlying icon library. Right now we assume it's the Silk icon library.
2394   return getSkinFile("icons/silk/" + iconName + ".png", context);
2395   }
2396  
2397   public String getSkinFile(String filename, XWikiContext context)
2398   {
2399   return getSkinFile(filename, false, context);
2400   }
2401  
2402   public String getSkinFile(String filename, boolean forceSkinAction, XWikiContext context)
2403   {
2404   XWikiURLFactory urlf = context.getURLFactory();
2405  
2406   try {
2407   // Try in the specified skin
2408   Skin skin = getInternalSkinManager().getCurrentSkin(true);
2409   if (skin != null) {
2410   Resource resource = skin.getResource(filename);
2411   if (resource != null) {
2412   return resource.getURL(forceSkinAction);
2413   }
2414   } else {
2415   // Try in the current parent skin
2416   Skin parentSkin = getInternalSkinManager().getCurrentParentSkin(true);
2417   if (parentSkin != null) {
2418   Resource resource = parentSkin.getResource(filename);
2419   if (resource != null) {
2420   return resource.getURL(forceSkinAction);
2421   }
2422   }
2423   }
2424  
2425   // Look for a resource file
2426   if (resourceExists("/resources/" + filename)) {
2427   URL url = urlf.createResourceURL(filename, forceSkinAction, context);
2428   return urlf.getURL(url, context);
2429   }
2430   } catch (Exception e) {
2431   if (LOGGER.isDebugEnabled()) {
2432   LOGGER.debug("Exception while getting skin file [" + filename + "]", e);
2433   }
2434   }
2435  
2436   // If all else fails, use the default base skin, even if the URLs could be invalid.
2437   URL url;
2438   if (forceSkinAction) {
2439   url = urlf.createSkinURL(filename, "skins", getDefaultBaseSkin(context), context);
2440   } else {
2441   url = urlf.createSkinURL(filename, getDefaultBaseSkin(context), context);
2442   }
2443   return urlf.getURL(url, context);
2444   }
2445  
2446   public String getSkinFile(String filename, String skin, XWikiContext context)
2447   {
2448   return getSkinFile(filename, skin, false, context);
2449   }
2450  
2451   public String getSkinFile(String filename, String skinId, boolean forceSkinAction, XWikiContext context)
2452   {
2453   try {
2454   Skin skin = getInternalSkinManager().getSkin(skinId);
2455  
2456   Resource resource = skin.getLocalResource(filename);
2457  
2458   if (resource != null) {
2459   return resource.getURL(forceSkinAction);
2460   }
2461  
2462   // Look for a resource file
2463   if (resourceExists("/resources/" + filename)) {
2464   XWikiURLFactory urlf = context.getURLFactory();
2465  
2466   URL url = urlf.createResourceURL(filename, forceSkinAction, context);
2467   return urlf.getURL(url, context);
2468   }
2469   } catch (Exception e) {
2470   if (LOGGER.isDebugEnabled()) {
2471   LOGGER.debug("Exception while getting skin file [{}] from skin [{}]", filename, skinId, e);
2472   }
2473   }
2474  
2475   return null;
2476   }
2477  
2478   /**
2479   * @deprecated since 7.0M1, use {@link SkinManager#getCurrentSkin(boolean)} instead
2480   */
2481   @Deprecated
2482   public String getSkin(XWikiContext context)
2483   {
2484   String skin;
2485  
2486   try {
2487   skin = getInternalSkinManager().getCurrentSkinId(true);
2488   } catch (Exception e) {
2489   LOGGER.debug("Exception while determining current skin", e);
2490   skin = getDefaultBaseSkin(context);
2491   }
2492  
2493   return skin;
2494   }
2495  
2496   public String getSkinPreference(String prefname, XWikiContext context)
2497   {
2498   return getSkinPreference(prefname, "", context);
2499   }
2500  
2501   public String getSkinPreference(String prefname, String defaultValue, XWikiContext context)
2502   {
2503   for (Skin skin = getInternalSkinManager().getCurrentSkin(true); skin != null; skin = skin.getParent()) {
2504   if (skin instanceof WikiSkin) {
2505   String value = getWikiSkinUtils().getSkinProperty(skin.getId(), prefname);
2506  
2507   // TODO: remove the NO_VALUE test when XWIKI-10853 is fixed
2508   if (!StringUtils.isEmpty(value) && !NO_VALUE.equals(value)) {
2509   return value;
2510   }
2511   }
2512   }
2513  
2514   return defaultValue;
2515   }
2516  
2517   /**
2518   * @deprecated since 7.0M1, use {@link SkinManager#getDefaultParentSkin()} instead
2519   */
2520   @Deprecated
2521   public String getDefaultBaseSkin(XWikiContext context)
2522   {
2523   return getInternalSkinManager().getDefaultParentSkinId();
2524   }
2525  
2526   /**
2527   * @deprecated since 7.0M1
2528   */
2529   @Deprecated
2530   public String getBaseSkin(XWikiContext context)
2531   {
2532   return getBaseSkin(context, false);
2533   }
2534  
2535   /**
2536   * @deprecated since 7.0M1
2537   */
2538   @Deprecated
2539   public String getBaseSkin(XWikiContext context, boolean fromRenderSkin)
2540   {
2541   String baseskin = "";
2542   try {
2543   return getInternalSkinManager().getCurrentParentSkinId(false);
2544   } catch (Exception e) {
2545   baseskin = getDefaultBaseSkin(context);
2546  
2547   LOGGER.debug("Exception while determining base skin", e);
2548   }
2549  
2550   return baseskin;
2551   }
2552  
2553   /**
2554   * @param skin the name of the skin for which to return the base skin. For example : XWiki.DefaultSkin
2555   * @param context see {@link XWikiContext}
2556   * @return if found, the name of the base skin the asked skin inherits from. If not found, returns an empty string.
2557   * @since 2.0.2
2558   * @since 2.1M1
2559   * @deprecated since 7.0M1, use {@link SkinManager#getCurrentSkin(boolean)} and {@link Skin#getParent()} instead
2560   */
2561   @Deprecated
2562   public String getBaseSkin(String skin, XWikiContext context)
2563   {
2564   String baseSkin = getInternalSkinManager().getParentSkin(skin);
2565  
2566   return baseSkin != null ? baseSkin : "";
2567   }
2568  
2569   public String getSpaceCopyright(XWikiContext context)
2570   {
2571   return getSpacePreference("webcopyright", "", context);
2572   }
2573  
2574   public String getXWikiPreference(String prefname, XWikiContext context)
2575   {
2576   return getXWikiPreference(prefname, "", context);
2577   }
2578  
2579   /**
2580   * Obtain a preference value for the wiki, looking up first in the XWiki.XWikiPreferences document, then fallbacking
2581   * on a config parameter when the first lookup gives an empty string, then returning the default value if the config
2582   * parameter returned itself an empty string.
2583   *
2584   * @param prefname the parameter to look for in the XWiki.XWikiPreferences object in the XWiki.XWikiPreferences
2585   * document of the wiki.
2586   * @param fallbackParam the parameter in xwiki.cfg to fallback on, in case the XWiki.XWikiPreferences object gave no
2587   * result
2588   * @param defaultValue the default value to fallback on, in case both XWiki.XWikiPreferences and the fallback
2589   * xwiki.cfg parameter gave no result
2590   */
2591   public String getXWikiPreference(String prefname, String fallbackParam, String defaultValue, XWikiContext context)
2592   {
2593   String result = getWikiConfiguration().getProperty(prefname, String.class);
2594  
2595   if (StringUtils.isEmpty(result)) {
2596   result = getConfiguration().getProperty(fallbackParam, defaultValue);
2597   }
2598  
2599   return result != null ? result : "";
2600   }
2601  
2602   /**
2603   * Obtain a preference value for the wiki, looking up first in the XWiki.XWikiPreferences document, then fallbacking
2604   * on a config parameter when the first lookup gives an empty string, then returning the default value if the config
2605   * parameter returned itself an empty string.
2606   *
2607   * @param prefname the parameter to look for in the XWiki.XWikiPreferences object in the XWiki.XWikiPreferences
2608   * document of the wiki.
2609   * @param wiki the wiki to get preference from
2610   * @param fallbackParam the parameter in xwiki.cfg to fallback on, in case the XWiki.XWikiPreferences object gave no
2611   * result
2612   * @param defaultValue the default value to fallback on, in case both XWiki.XWikiPreferences and the fallback
2613   * xwiki.cfg parameter gave no result
2614   * @since 7.4M1
2615   */
2616   public String getXWikiPreference(String prefname, String wiki, String fallbackParam, String defaultValue,
2617   XWikiContext xcontext)
2618   {
2619   String currentWiki = xcontext.getWikiId();
2620  
2621   try {
2622   xcontext.setWikiId(wiki);
2623  
2624   return getXWikiPreference(prefname, fallbackParam, defaultValue, xcontext);
2625   } finally {
2626   xcontext.setWikiId(currentWiki);
2627   }
2628   }
2629  
2630   public String getXWikiPreference(String prefname, String defaultValue, XWikiContext context)
2631   {
2632   return getXWikiPreference(prefname, "", defaultValue, context);
2633   }
2634  
2635   public String getSpacePreference(String preference, XWikiContext context)
2636   {
2637   return getSpacePreference(preference, "", context);
2638   }
2639  
2640   public String getSpacePreference(String preference, String defaultValue, XWikiContext context)
2641   {
2642   return getSpacePreference(preference, (SpaceReference) null, defaultValue, context);
2643   }
2644  
2645   /**
2646   * @deprecated since 7.4M1, use {@link #getSpacePreference(String, SpaceReference, String, XWikiContext)} instead
2647   */
2648   @Deprecated
2649   public String getSpacePreference(String preference, String space, String defaultValue, XWikiContext context)
2650   {
2651   return getSpacePreference(preference, new SpaceReference(space, context.getWikiReference()), defaultValue,
2652   context);
2653   }
2654  
2655   /**
2656   * Get the reference of the space and fallback on parent space or wiki in case nothing is found.
2657   *

2658   * If the property is not set on any level then empty String is returned.
2659   *
2660   * @param preferenceKey the name of the preference key
2661   * @param spaceReference the reference of the space
2662   * @param context see {@link XWikiContext}
2663   * @return the value of the preference or empty String if it could not be found
2664   * @since 7.4M1
2665   */
2666   public String getSpacePreference(String preferenceKey, SpaceReference spaceReference, XWikiContext context)
2667   {
2668   return getSpacePreference(preferenceKey, spaceReference, "", context);
2669   }
2670  
2671   /**
2672   * Get the reference of the space and fallback on parent space or wiki in case nothing is found.
2673   *

2674   * If the property is not set on any level then defaultValue is returned.
2675   *
2676   * @param preferenceKey the name of the preference key
2677   * @param spaceReference the reference of the space
2678   * @param defaultValue the value to return if the preference can't be found
2679   * @param context see {@link XWikiContext}
2680   * @return the value of the preference or defaultValue if it could not be found
2681   * @since 7.4M1
2682   */
2683   public String getSpacePreference(String preferenceKey, SpaceReference spaceReference, String defaultValue,
2684   XWikiContext context)
2685   {
2686   XWikiDocument currentDocument = context.getDoc();
2687  
2688   try {
2689   if (spaceReference != null) {
2690   context.setDoc(new XWikiDocument(new DocumentReference("WebPreferences", spaceReference)));
2691   } else if (currentDocument != null) {
2692   spaceReference = currentDocument.getDocumentReference().getLastSpaceReference();
2693   }
2694  
2695   String result = getSpaceConfiguration().getProperty(preferenceKey, String.class);
2696  
2697   if (StringUtils.isEmpty(result)) {
2698   if (spaceReference == null) {
2699   result = getXWikiPreference(preferenceKey, defaultValue, context);
2700   } else if (spaceReference.getParent() instanceof SpaceReference) {
2701   result = getSpacePreference(preferenceKey, (SpaceReference) spaceReference.getParent(),
2702   defaultValue, context);
2703   } else if (spaceReference.getParent() instanceof WikiReference) {
2704   result =
2705   getXWikiPreference(preferenceKey, spaceReference.getParent().getName(), defaultValue, context);
2706   }
2707   }
2708  
2709   return result != null ? result : defaultValue;
2710   } finally {
2711   context.setDoc(currentDocument);
2712   }
2713   }
2714  
2715   public String getUserPreference(String prefname, XWikiContext context)
2716   {
2717   String result = getUserConfiguration().getProperty(prefname, String.class);
2718  
2719   if (StringUtils.isEmpty(result)) {
2720   result = getSpacePreference(prefname, context);
2721   }
2722  
2723   return result != null ? result : "";
2724   }
2725  
2726   public String getUserPreferenceFromCookie(String prefname, XWikiContext context)
2727   {
2728   Cookie[] cookies = context.getRequest().getCookies();
2729   if (cookies == null) {
2730   return null;
2731   }
2732   for (Cookie cookie : cookies) {
2733   String name = cookie.getName();
2734   if (name.equals(prefname)) {
2735   String value = cookie.getValue();
2736   if (!value.trim().equals("")) {
2737   return value;
2738   } else {
2739   break;
2740   }
2741   }
2742   }
2743   return null;
2744   }
2745  
2746   public String getUserPreference(String prefname, boolean useCookie, XWikiContext context)
2747   {
2748   // First we look in the cookies
2749   if (useCookie) {
2750   String result = Util.normalizeLanguage(getUserPreferenceFromCookie(prefname, context));
2751   if (result != null) {
2752   return result;
2753   }
2754   }
2755   return getUserPreference(prefname, context);
2756   }
2757  
2758   /**
2759   * First try to find the current locale in use from the XWiki context. If none is used and if the wiki is not
2760   * multilingual use the default locale defined in the XWiki preferences. If the wiki is multilingual try to get the
2761   * locale passed in the request. If none was passed try to get it from a cookie. If no locale cookie exists then use
2762   * the user default locale and barring that use the browser's "Accept-Language" header sent in HTTP request. If none
2763   * is defined use the default locale.
2764   *
2765   * @return the locale to use
2766   * @since 8.0M1
2767   */
2768   public Locale getLocalePreference(XWikiContext context)
2769   {
2770   String language = getLanguagePreference(context);
2771  
2772   return LocaleUtils.toLocale(language);
2773   }
2774  
2775   /**
2776   * First try to find the current locale in use from the XWiki context. If none is used and if the wiki is not
2777   * multilingual use the default locale defined in the XWiki preferences. If the wiki is multilingual try to get the
2778   * locale passed in the request. If none was passed try to get it from a cookie. If no locale cookie exists then use
2779   * the user default locale and barring that use the browser's "Accept-Language" header sent in HTTP request. If none
2780   * is defined use the default locale.
2781   *
2782   * @return the locale to use
2783   * @deprecated since 8.0M1, use {@link #getLocalePreference(XWikiContext)} instead
2784   */
2785   @Deprecated
2786   // TODO: move implementation to #getLocalePreference
2787   public String getLanguagePreference(XWikiContext context)
2788   {
2789   // First we try to get the language from the XWiki Context. This is the current language
2790   // being used.
2791   String language = context.getLanguage();
2792   if (language != null) {
2793   return language;
2794   }
2795  
2796   String defaultLanguage = getDefaultLanguage(context);
2797  
2798   // If the wiki is non multilingual then the language is the default language.
2799   if (!context.getWiki().isMultiLingual(context)) {
2800   language = defaultLanguage;
2801   context.setLanguage(language);
2802   return language;
2803   }
2804  
2805   // As the wiki is multilingual try to find the language to use from the request by looking
2806   // for a language parameter. If the language value is "default" use the default language
2807   // from the XWiki preferences settings. Otherwise set a cookie to remember the language
2808   // in use.
2809   try {
2810   language = Util.normalizeLanguage(context.getRequest().getParameter("language"));
2811   if ((language != null) && (!language.equals(""))) {
2812   if (language.equals("default")) {
2813   // forgetting language cookie
2814   Cookie cookie = new Cookie("language", "");
2815   cookie.setMaxAge(0);
2816   cookie.setPath("/");
2817   context.getResponse().addCookie(cookie);
2818   language = defaultLanguage;
2819   } else {
2820   // setting language cookie
2821   Cookie cookie = new Cookie("language", language);
2822   cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
2823   cookie.setPath("/");
2824   context.getResponse().addCookie(cookie);
2825   }
2826   context.setLanguage(language);
2827   return language;
2828   }
2829   } catch (Exception e) {
2830   }
2831  
2832   // As no language parameter was passed in the request, try to get the language to use
2833   // from a cookie.
2834   try {
2835   // First we get the language from the cookie
2836   language = Util.normalizeLanguage(getUserPreferenceFromCookie("language", context));
2837   if ((language != null) && (!language.equals(""))) {
2838   context.setLanguage(language);
2839   return language;
2840   }
2841   } catch (Exception e) {
2842   }
2843  
2844   // Next from the default user preference
2845   try {
2846   String user = context.getUser();
2847   XWikiDocument userdoc = null;
2848   userdoc = getDocument(user, context);
2849   if (userdoc != null) {
2850   language = Util.normalizeLanguage(userdoc.getStringValue("XWiki.XWikiUsers", "default_language"));
2851   if (!language.equals("")) {
2852   context.setLanguage(language);
2853   return language;
2854   }
2855   }
2856   } catch (XWikiException e) {
2857   }
2858  
2859   // If the default language is preferred, and since the user didn't explicitly ask for a
2860   // language already, then use the default wiki language.
2861   if (getConfiguration().getProperty("xwiki.language.preferDefault", "0").equals("1")
2862   || getSpacePreference("preferDefaultLanguage", "0", context).equals("1")) {
2863   language = defaultLanguage;
2864   context.setLanguage(language);
2865   return language;
2866   }
2867  
2868   // Then from the navigator language setting
2869   if (context.getRequest() != null) {
2870   String acceptHeader = context.getRequest().getHeader("Accept-Language");
2871   // If the client didn't specify some languages, skip this phase
2872   if ((acceptHeader != null) && (!acceptHeader.equals(""))) {
2873   List acceptedLanguages = getAcceptedLanguages(context.getRequest());
2874   // We can force one of the configured languages to be accepted
2875   if (getConfiguration().getProperty("xwiki.language.forceSupported", "0").equals("1")) {
2876   List available = Arrays.asList(getXWikiPreference("languages", context).split("[, |]"));
2877   // Filter only configured languages
2878   acceptedLanguages.retainAll(available);
2879   }
2880   if (acceptedLanguages.size() > 0) {
2881   // Use the "most-preferred" language, as requested by the client.
2882   context.setLanguage(acceptedLanguages.get(0));
2883   return acceptedLanguages.get(0);
2884   }
2885   // If none of the languages requested by the client is acceptable, skip to next
2886   // phase (use default language).
2887   }
2888   }
2889  
2890   // Finally, use the default language from the global preferences.
2891   context.setLanguage(defaultLanguage);
2892   return defaultLanguage;
2893   }
2894  
2895   /**
2896   * Construct a list of language codes (ISO 639-1) from the Accept-Languages header. This method filters out some
2897   * bugs in different browsers or containers, like returning '*' as a language (Jetty) or using '_' as a
2898   * language--country delimiter (some versions of Opera).
2899   *
2900   * @param request The client request.
2901   * @return A list of language codes, in the client preference order; might be empty if the header is not well
2902   * formed.
2903   */
2904   private List getAcceptedLanguages(XWikiRequest request)
2905   {
2906   List result = new ArrayList();
2907   Enumeration e = request.getLocales();
2908   while (e.hasMoreElements()) {
2909   String language = e.nextElement().getLanguage().toLowerCase();
2910   // All language codes should have 2 letters.
2911   if (StringUtils.isAlpha(language)) {
2912   result.add(language);
2913   }
2914   }
2915   return result;
2916   }
2917  
2918   /**
2919   * @deprecated since 5.1M2 use {@link #getDefaultLocale(XWikiContext)} instead
2920   */
2921   @Deprecated
2922   public String getDefaultLanguage(XWikiContext xcontext)
2923   {
2924   return getDefaultLocale(xcontext).toString();
2925   }
2926  
2927   /**
2928   * The default locale in the preferences.
2929   *
2930   * @param xcontext the XWiki context.
2931   * @return the default locale
2932   * @since 5.1M2
2933   */
2934   public Locale getDefaultLocale(XWikiContext xcontext)
2935   {
2936   // Find out what is the default language from the XWiki preferences settings.
2937   String defaultLanguage = xcontext.getWiki().getXWikiPreference("default_language", "", xcontext);
2938  
2939   Locale defaultLocale;
2940  
2941   if (StringUtils.isBlank(defaultLanguage)) {
2942   defaultLocale = Locale.ENGLISH;
2943   } else {
2944   try {
2945   defaultLocale = LocaleUtils.toLocale(Util.normalizeLanguage(defaultLanguage));
2946   } catch (Exception e) {
2947   LOGGER.warn("Invalid locale [{}] set as default locale in the preferences", defaultLanguage);
2948   defaultLocale = Locale.ENGLISH;
2949   }
2950   }
2951  
2952   return defaultLocale;
2953   }
2954  
2955   /**
2956   * Get the available locales according to the preferences.
2957   *
2958   * @param xcontext the XWiki context
2959   * @return all the available locales
2960   * @since 5.1M2
2961   */
2962   public List getAvailableLocales(XWikiContext xcontext)
2963   {
2964   String[] languages = StringUtils.split(xcontext.getWiki().getXWikiPreference("languages", xcontext), ", |");
2965  
2966   List locales = new ArrayList(languages.length);
2967  
2968   for (String language : languages) {
2969   if (StringUtils.isNotBlank(language)) {
2970   try {
2971   locales.add(LocaleUtils.toLocale(language));
2972   } catch (Exception e) {
2973   LOGGER.warn("Invalid locale [{}] listed as available in the preferences", language);
2974   }
2975   }
2976   }
2977  
2978   // Add default language in case it's not listed as available (which is wrong but it happen)
2979   Locale defaultocale = getDefaultLocale(xcontext);
2980   if (!locales.contains(defaultocale)) {
2981   locales.add(defaultocale);
2982   }
2983  
2984   return locales;
2985   }
2986  
2987   /**
2988   * @since 8.0M1
2989   */
2990   public Locale getDocLocalePreferenceNew(XWikiContext context)
2991   {
2992   String language = getDocLanguagePreferenceNew(context);
2993  
2994   return LocaleUtils.toLocale(language);
2995   }
2996  
2997   /**
2998   * @deprecated since 8.0M1, use {@link #getDocLocalePreferenceNew(XWikiContext)} instead
2999   */
3000   @Deprecated
3001   // TODO: move implementation to #getDocLocalePreferenceNew
3002   public String getDocLanguagePreferenceNew(XWikiContext context)
3003   {
3004   // Get context language
3005   String contextLanguage = context.getLanguage();
3006   // If the language exists in the context, it was previously set by another call
3007   if (contextLanguage != null && contextLanguage != "") {
3008   return contextLanguage;
3009   }
3010  
3011   String language = "", requestLanguage = "", userPreferenceLanguage = "", navigatorLanguage = "",
3012   cookieLanguage = "";
3013   boolean setCookie = false;
3014  
3015   if (!context.getWiki().isMultiLingual(context)) {
3016   language = context.getWiki().getXWikiPreference("default_language", "", context);
3017   context.setLanguage(language);
3018   return language;
3019   }
3020  
3021   // Get request language
3022   try {
3023   requestLanguage = Util.normalizeLanguage(context.getRequest().getParameter("language"));
3024   } catch (Exception ex) {
3025   }
3026  
3027   // Get user preference
3028   try {
3029   String user = context.getUser();
3030   XWikiDocument userdoc = getDocument(user, context);
3031   if (userdoc != null) {
3032   userPreferenceLanguage = userdoc.getStringValue("XWiki.XWikiUsers", "default_language");
3033   }
3034   } catch (XWikiException e) {
3035   }
3036  
3037   // Get navigator language setting
3038   if (context.getRequest() != null) {
3039   String accept = context.getRequest().getHeader("Accept-Language");
3040   if ((accept != null) && (!accept.equals(""))) {
3041   String[] alist = StringUtils.split(accept, ",;-");
3042   if ((alist != null) && !(alist.length == 0)) {
3043   context.setLanguage(alist[0]);
3044   navigatorLanguage = alist[0];
3045   }
3046   }
3047   }
3048  
3049   // Get language from cookie
3050   try {
3051   cookieLanguage = Util.normalizeLanguage(getUserPreferenceFromCookie("language", context));
3052   } catch (Exception e) {
3053   }
3054  
3055   // Determine which language to use
3056   // First we get the language from the request
3057   if (StringUtils.isNotEmpty(requestLanguage)) {
3058   if (requestLanguage.equals("default")) {
3059   setCookie = true;
3060   } else {
3061   language = requestLanguage;
3062   context.setLanguage(language);
3063   Cookie cookie = new Cookie("language", language);
3064   cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
3065   cookie.setPath("/");
3066   context.getResponse().addCookie(cookie);
3067   return language;
3068   }
3069   }
3070   // Next we get the language from the cookie
3071   if (StringUtils.isNotEmpty(cookieLanguage)) {
3072   language = cookieLanguage;
3073   }
3074   // Next from the default user preference
3075   else if (StringUtils.isNotEmpty(userPreferenceLanguage)) {
3076   language = userPreferenceLanguage;
3077   }
3078   // Then from the navigator language setting
3079   else if (StringUtils.isNotEmpty(navigatorLanguage)) {
3080   language = navigatorLanguage;
3081   }
3082   context.setLanguage(language);
3083   if (setCookie) {
3084   Cookie cookie = new Cookie("language", language);
3085   cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
3086   cookie.setPath("/");
3087   context.getResponse().addCookie(cookie);
3088   }
3089   return language;
3090   }
3091  
3092   /**
3093   * @since 8.0M1
3094   */
3095   public Locale getInterfaceLocalePreference(XWikiContext context)
3096   {
3097   String language = getInterfaceLanguagePreference(context);
3098  
3099   return LocaleUtils.toLocale(language);
3100   }
3101  
3102   /**
3103   * @deprecated since 8.0M1, use {@link #getInterfaceLocalePreference(XWikiContext)} instead
3104   */
3105   @Deprecated
3106   // TODO: move implementation to #getInterfaceLocalePreference
3107   public String getInterfaceLanguagePreference(XWikiContext context)
3108   {
3109   String language = "", requestLanguage = "", userPreferenceLanguage = "", navigatorLanguage = "",
3110   cookieLanguage = "", contextLanguage = "";
3111   boolean setCookie = false;
3112  
3113   if (!context.getWiki().isMultiLingual(context)) {
3114   language = Util.normalizeLanguage(context.getWiki().getXWikiPreference("default_language", "", context));
3115   context.setInterfaceLanguage(language);
3116   return language;
3117   }
3118  
3119   // Get request language
3120   try {
3121   requestLanguage = Util.normalizeLanguage(context.getRequest().getParameter("interfacelanguage"));
3122   } catch (Exception ex) {
3123   }
3124  
3125   // Get context language
3126   contextLanguage = context.getInterfaceLanguage();
3127  
3128   // Get user preference
3129   try {
3130   String user = context.getUser();
3131   XWikiDocument userdoc = null;
3132   userdoc = getDocument(user, context);
3133   if (userdoc != null) {
3134   userPreferenceLanguage = userdoc.getStringValue("XWiki.XWikiUsers", "default_interface_language");
3135   }
3136   } catch (XWikiException e) {
3137   }
3138  
3139   // Get navigator language setting
3140   if (context.getRequest() != null) {
3141   String accept = context.getRequest().getHeader("Accept-Language");
3142   if ((accept != null) && (!accept.equals(""))) {
3143   String[] alist = StringUtils.split(accept, ",;-");
3144   if ((alist != null) && !(alist.length == 0)) {
3145   context.setLanguage(alist[0]);
3146   navigatorLanguage = alist[0];
3147   }
3148   }
3149   }
3150  
3151   // Get language from cookie
3152   try {
3153   cookieLanguage = Util.normalizeLanguage(getUserPreferenceFromCookie("interfacelanguage", context));
3154   } catch (Exception e) {
3155   }
3156  
3157   // Determine which language to use
3158   // First we get the language from the request
3159   if ((requestLanguage != null) && (!requestLanguage.equals(""))) {
3160   if (requestLanguage.equals("default")) {
3161   setCookie = true;
3162   } else {
3163   language = requestLanguage;
3164   context.setLanguage(language);
3165   Cookie cookie = new Cookie("interfacelanguage", language);
3166   cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
3167   cookie.setPath("/");
3168   context.getResponse().addCookie(cookie);
3169   return language;
3170   }
3171   }
3172   // Next we get the language from the context
3173   if (contextLanguage != null && contextLanguage != "") {
3174   language = contextLanguage;
3175   }
3176   // Next we get the language from the cookie
3177   else if (StringUtils.isNotEmpty(cookieLanguage)) {
3178   language = cookieLanguage;
3179   }
3180   // Next from the default user preference
3181   else if (StringUtils.isNotEmpty(userPreferenceLanguage)) {
3182   language = userPreferenceLanguage;
3183   }
3184   // Then from the navigator language setting
3185   else if (StringUtils.isNotEmpty(navigatorLanguage)) {
3186   language = navigatorLanguage;
3187   }
3188   context.setLanguage(language);
3189   if (setCookie) {
3190   Cookie cookie = new Cookie("interfacelanguage", language);
3191   cookie.setMaxAge(60 * 60 * 24 * 365 * 10);
3192   cookie.setPath("/");
3193   context.getResponse().addCookie(cookie);
3194   }
3195   return language;
3196   }
3197  
3198   public long getXWikiPreferenceAsLong(String preference, XWikiContext context)
3199   {
3200   return Long.parseLong(getXWikiPreference(preference, context));
3201   }
3202  
3203   public long getSpacePreferenceAsLong(String preference, XWikiContext context)
3204   {
3205   return Long.parseLong(getSpacePreference(preference, context));
3206   }
3207  
3208   public long getXWikiPreferenceAsLong(String preference, long defaultValue, XWikiContext context)
3209   {
3210   return NumberUtils.toLong((getXWikiPreference(preference, context)), defaultValue);
3211   }
3212  
3213   public long getXWikiPreferenceAsLong(String preference, String fallbackParameter, long defaultValue,
3214   XWikiContext context)
3215   {
3216   return NumberUtils.toLong(getXWikiPreference(preference, fallbackParameter, "", context), defaultValue);
3217   }
3218  
3219   public long getSpacePreferenceAsLong(String preference, long defaultValue, XWikiContext context)
3220   {
3221   return NumberUtils.toLong(getSpacePreference(preference, context), defaultValue);
3222   }
3223  
3224   public long getUserPreferenceAsLong(String preference, XWikiContext context)
3225   {
3226   return Long.parseLong(getUserPreference(preference, context));
3227   }
3228  
3229   public int getXWikiPreferenceAsInt(String preference, XWikiContext context)
3230   {
3231   return Integer.parseInt(getXWikiPreference(preference, context));
3232   }
3233  
3234   public int getSpacePreferenceAsInt(String preference, XWikiContext context)
3235   {
3236   return Integer.parseInt(getSpacePreference(preference, context));
3237   }
3238  
3239   public int getXWikiPreferenceAsInt(String preference, int defaultValue, XWikiContext context)
3240   {
3241   return NumberUtils.toInt(getXWikiPreference(preference, context), defaultValue);
3242   }
3243  
3244   public int getXWikiPreferenceAsInt(String preference, String fallbackParameter, int defaultValue,
3245   XWikiContext context)
3246   {
3247   return NumberUtils.toInt(getXWikiPreference(preference, fallbackParameter, "", context), defaultValue);
3248   }
3249  
3250   public int getSpacePreferenceAsInt(String preference, int defaultValue, XWikiContext context)
3251   {
3252   return NumberUtils.toInt(getSpacePreference(preference, context), defaultValue);
3253   }
3254  
3255   public int getUserPreferenceAsInt(String prefname, XWikiContext context)
3256   {
3257   return Integer.parseInt(getUserPreference(prefname, context));
3258   }
3259  
3260   public void flushCache(XWikiContext context)
3261   {
3262   // We need to flush the virtual wiki list
3263   this.initializedWikis = new ConcurrentHashMap<>();
3264  
3265   // We need to flush the group service cache
3266   if (this.groupService != null) {
3267   this.groupService.flushCache();
3268   }
3269  
3270   // If we use the Cache Store layer.. we need to flush it
3271   XWikiStoreInterface store = getStore();
3272   if ((store != null) && (store instanceof XWikiCacheStoreInterface)) {
3273   ((XWikiCacheStoreInterface) getStore()).flushCache();
3274   }
3275   // Flush renderers.. Groovy renderer has a cache
3276   getOldRendering().flushCache();
3277   getParseGroovyFromString().flushCache();
3278  
3279   XWikiPluginManager pmanager = getPluginManager();
3280   if (pmanager != null) {
3281   pmanager.flushCache(context);
3282   }
3283  
3284   // Make sure we call all classes flushCache function
3285   try {
3286   List classes = getClassList(context);
3287   for (int i = 0; i < classes.size(); i++) {
3288   String className = classes.get(i);
3289   try {
3290   getClass(className, context).flushCache();
3291   } catch (Exception e) {
3292   }
3293   }
3294   } catch (Exception e) {
3295   }
3296  
3297   }
3298  
3299   public XWikiPluginManager getPluginManager()
3300   {
3301   return this.pluginManager;
3302   }
3303  
3304   public void setPluginManager(XWikiPluginManager pluginManager)
3305   {
3306   this.pluginManager = pluginManager;
3307   }
3308  
3309   public void setStore(XWikiStoreInterface store)
3310   {
3311   this.store = store;
3312   }
3313  
3314   /**
3315   * @param attachmentContentStore the store to use by default when saving a new attachment content
3316   * @since 9.10RC1
3317   */
3318   public void setDefaultAttachmentContentStore(XWikiAttachmentStoreInterface attachmentContentStore)
3319   {
3320   this.defaultAttachmentContentStore = attachmentContentStore;
3321   }
3322  
3323   /**
3324   * @deprecated since 9.9RC1, use {@link #setDefaultAttachmentContentStore(XWikiAttachmentStoreInterface)} instead
3325   */
3326   @Deprecated
3327   public void setAttachmentStore(XWikiAttachmentStoreInterface attachmentStore)
3328   {
3329   this.defaultAttachmentContentStore = attachmentStore;
3330   }
3331  
3332   /**
3333   * @param attachmentArchiveStore the store to use by default when saving a new attachment archive
3334   * @since 9.10RC1
3335   */
3336   public void setDefaultAttachmentArchiveStore(AttachmentVersioningStore attachmentArchiveStore)
3337   {
3338   this.defaultAttachmentArchiveStore = attachmentArchiveStore;
3339   }
3340  
3341   /**
3342   * @deprecated since 9.10RC1, use {@link #setDefaultAttachmentArchiveStore(AttachmentVersioningStore)} instead
3343   */
3344   @Deprecated
3345   public void setAttachmentVersioningStore(AttachmentVersioningStore attachmentArchiveStore)
3346   {
3347   setDefaultAttachmentArchiveStore(attachmentArchiveStore);
3348   }
3349  
3350   public void setVersioningStore(XWikiVersioningStoreInterface versioningStore)
3351   {
3352   this.versioningStore = versioningStore;
3353   }
3354  
3355   public void setRecycleBinStore(XWikiRecycleBinStoreInterface recycleBinStore)
3356   {
3357   this.recycleBinStore = recycleBinStore;
3358   }
3359  
3360   public void setAttachmentRecycleBinStore(AttachmentRecycleBinStore attachmentRecycleBinStore)
3361   {
3362   this.attachmentRecycleBinStore = attachmentRecycleBinStore;
3363   }
3364  
3365   public void setCriteriaService(XWikiCriteriaService criteriaService)
3366   {
3367   this.criteriaService = criteriaService;
3368   }
3369  
3370   public void setVersion(String version)
3371   {
3372   this.version = version;
3373   }
3374  
3375   /**
3376   * Verify if the provided xclass page exists and that it contains all the required configuration properties to make
3377   * the tag feature work properly. If some properties are missing they are created and saved in the database.
3378   *
3379   * @param context see {@link XWikiContext}
3380   * @param classReference the reference of the document containing the class
3381   * @return the Base Class object containing the properties
3382   * @throws XWikiException if an error happens during the save to the database
3383   */
3384   private BaseClass getMandatoryClass(XWikiContext context, DocumentReference classReference) throws XWikiException
3385   {
3386   XWikiDocument document = getDocument(classReference, context);
3387  
3388   if (context.get("initdone") == null) {
3389   @SuppressWarnings("deprecation")
3390   MandatoryDocumentInitializer initializer =
3391   Utils.getComponent(MandatoryDocumentInitializer.class, document.getFullName());
3392  
3393   if (initializer.updateDocument(document)) {
3394   saveDocument(document, localizePlainOrKey("core.model.xclass.mandatoryUpdateProperty.versionSummary"),
3395   context);
3396   }
3397   }
3398  
3399   return document.getXClass();
3400   }
3401  
3402   /**
3403   * Verify if the XWiki.TagClass page exists and that it contains all the required configuration
3404   * properties to make the tag feature work properly. If some properties are missing they are created and saved in
3405   * the database.
3406   *
3407   * @param context see {@link XWikiContext}
3408   * @return the TagClass Base Class object containing the properties
3409   * @throws XWikiException if an error happens during the save to the datavase
3410   */
3411   public BaseClass getTagClass(XWikiContext context) throws XWikiException
3412   {
3413   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "TagClass"));
3414   }
3415  
3416   /**
3417   * Verify if the XWiki.SheetClass page exists and that it contains all the required configuration
3418   * properties to make the sheet feature work properly. If some properties are missing they are created and saved in
3419   * the database. SheetClass is used to a page as a sheet. When a page is tagged as a sheet and that page is included
3420   * in another page using the include macro then editing it triggers automatic inline edition (for XWiki Syntax 2.0
3421   * only - for XWiki Syntax 1.0 automatic inline edition is triggered using #includeForm).
3422   *
3423   * @param context see {@link XWikiContext}
3424   * @return the SheetClass Base Class object containing the properties
3425   * @throws XWikiException if an error happens during the save to the database
3426   * @deprecated since 3.1M2 edit mode class should be used for this purpose, not the sheet class
3427   * @see #getEditModeClass(XWikiContext)
3428   */
3429   @Deprecated
3430   public BaseClass getSheetClass(XWikiContext context) throws XWikiException
3431   {
3432   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "SheetClass"));
3433   }
3434  
3435   /**
3436   * Verify if the {@code XWiki.EditModeClass} page exists and that it contains all the required configuration
3437   * properties to make the edit mode feature work properly. If some properties are missing they are created and saved
3438   * in the database. EditModeClass is used to specify the default edit mode of a page. It can also be used to mark a
3439   * page as a sheet. When a page is marked as a sheet and that page is included in another page using the include
3440   * macro then editing it triggers automatic inline edition (for XWiki Syntax 2.0 only - for XWiki Syntax 1.0
3441   * automatic inline edition is triggered using #includeForm). It replaces and enhances the SheetClass mechanism (see
3442   * {@link #getSheetClass(XWikiContext)}).
3443   *
3444   * @param context see {@link XWikiContext}
3445   * @return the EditModeClass Base Class object containing the properties
3446   * @throws XWikiException if an error happens during the save to the database
3447   * @since 3.1M2
3448   */
3449   public BaseClass getEditModeClass(XWikiContext context) throws XWikiException
3450   {
3451   return getMandatoryClass(context, new DocumentReference(
3452   new LocalDocumentReference(XWikiConstant.EDIT_MODE_CLASS), new WikiReference(context.getWikiId())));
3453   }
3454  
3455   /**
3456   * Verify if the XWiki.XWikiUsers page exists and that it contains all the required configuration
3457   * properties to make the user feature work properly. If some properties are missing they are created and saved in
3458   * the database.
3459   *
3460   * @param context see {@link XWikiContext}
3461   * @return the XWikiUsers Base Class object containing the properties
3462   * @throws XWikiException if an error happens during the save to the datavase
3463   */
3464   public BaseClass getUserClass(XWikiContext context) throws XWikiException
3465   {
3466   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiUsers"));
3467   }
3468  
3469   /**
3470   * Verify if the XWiki.GlobalRedirect page exists and that it contains all the required configuration
3471   * properties to make the redirection feature work properly. If some properties are missing they are created and
3472   * saved in the database.
3473   *
3474   * @param context see {@link XWikiContext}
3475   * @return the GlobalRedirect Base Class object containing the properties
3476   * @throws XWikiException if an error happens during the save to the datavase
3477   */
3478   public BaseClass getRedirectClass(XWikiContext context) throws XWikiException
3479   {
3480   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "GlobalRedirect"));
3481   }
3482  
3483   /**
3484   * Verify if the XWiki.XWikiPreferences page exists and that it contains all the required configuration
3485   * properties to make XWiki work properly. If some properties are missing they are created and saved in the
3486   * database.
3487   *
3488   * @param context see {@link XWikiContext}
3489   * @return the XWiki Base Class object containing the properties
3490   * @throws XWikiException if an error happens during the save to the datavase
3491   */
3492   public BaseClass getPrefsClass(XWikiContext context) throws XWikiException
3493   {
3494   return getMandatoryClass(context, getPreferencesDocumentReference(context));
3495   }
3496  
3497   public BaseClass getGroupClass(XWikiContext context) throws XWikiException
3498   {
3499   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiGroups"));
3500   }
3501  
3502   public BaseClass getRightsClass(String pagename, XWikiContext context) throws XWikiException
3503   {
3504   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, pagename));
3505   }
3506  
3507   public BaseClass getRightsClass(XWikiContext context) throws XWikiException
3508   {
3509   return getRightsClass("XWikiRights", context);
3510   }
3511  
3512   public BaseClass getGlobalRightsClass(XWikiContext context) throws XWikiException
3513   {
3514   return getRightsClass("XWikiGlobalRights", context);
3515   }
3516  
3517   public BaseClass getCommentsClass(XWikiContext context) throws XWikiException
3518   {
3519   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiComments"));
3520   }
3521  
3522   public BaseClass getSkinClass(XWikiContext context) throws XWikiException
3523   {
3524   return getMandatoryClass(context, new DocumentReference(context.getWikiId(), SYSTEM_SPACE, "XWikiSkins"));
3525   }
3526  
3527   public int createUser(XWikiContext context) throws XWikiException
3528   {
3529   return createUser(false, "edit", context);
3530   }
3531  
3532   public int validateUser(boolean withConfirmEmail, XWikiContext context) throws XWikiException
3533   {
3534   try {
3535   XWikiRequest request = context.getRequest();
3536   // Get the user document
3537   String username = convertUsername(request.getParameter("xwikiname"), context);
3538   if (username.indexOf('.') == -1) {
3539   username = "XWiki." + username;
3540   }
3541   XWikiDocument userDocument = getDocument(username, context);
3542  
3543   // Get the stored validation key
3544   BaseObject userObject = userDocument.getObject("XWiki.XWikiUsers", 0);
3545   String storedKey = userObject.getStringValue("validkey");
3546  
3547   // Get the validation key from the URL
3548   String validationKey = request.getParameter("validkey");
3549   PropertyInterface validationKeyClass = getClass("XWiki.XWikiUsers", context).get("validkey");
3550   if (validationKeyClass instanceof PasswordClass) {
3551   validationKey = ((PasswordClass) validationKeyClass).getEquivalentPassword(storedKey, validationKey);
3552   }
3553  
3554   // Compare the two keys
3555   if ((!storedKey.equals("") && (storedKey.equals(validationKey)))) {
3556   userObject.setIntValue("active", 1);
3557   saveDocument(userDocument, context);
3558  
3559   if (withConfirmEmail) {
3560   String email = userObject.getStringValue("email");
3561   String password = userObject.getStringValue("password");
3562   sendValidationEmail(username, password, email, request.getParameter("validkey"),
3563   "confirmation_email_content", context);
3564   }
3565  
3566   return 0;
3567   } else {
3568   return -1;
3569   }
3570   } catch (Exception e) {
3571   LOGGER.error(e.getMessage(), e);
3572  
3573   throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_VALIDATE_USER,
3574   "Exception while validating user", e, null);
3575   }
3576   }
3577  
3578   public int createUser(boolean withValidation, String userRights, XWikiContext context) throws XWikiException
3579   {
3580   try {
3581   XWikiRequest request = context.getRequest();
3582   Map map = Util.getObject(request, "register");
3583  
3584   String content = "";
3585   Syntax syntax = getDefaultDocumentSyntaxInternal();
3586  
3587   // Read the values from the request.
3588   String xwikiname = request.getParameter("xwikiname");
3589   String password2 = request.getParameter("register2_password");
3590   String password = (map.get("password"))[0];
3591   String email = (map.get("email"))[0];
3592   String template = request.getParameter("template");
3593   String parent = request.getParameter("parent");
3594   String validkey = null;
3595  
3596   // Validate the values.
3597   if (XWikiRightService.SUPERADMIN_USER.equalsIgnoreCase(xwikiname)) {
3598   return -8;
3599   }
3600   try {
3601   if (!context.getUtil().match(getConfiguration().getProperty("xwiki.validusername", "/^[a-zA-Z0-9_]+$/"),
3602   xwikiname)) {
3603   return -4;
3604   }
3605   } catch (RuntimeException ex) {
3606   LOGGER.warn("Invalid regular expression for xwiki.validusername", ex);
3607   if (!context.getUtil().match("/^[a-zA-Z0-9_]+$/", xwikiname)) {
3608   return -4;
3609   }
3610   }
3611  
3612   if ((!password.equals(password2)) || (password.trim().equals(""))) {
3613   // TODO: throw wrong password exception
3614   return -2;
3615   }
3616  
3617   if ((template != null) && (!template.equals(""))) {
3618   XWikiDocument tdoc = getDocument(template, context);
3619   if ((!tdoc.isNew())) {
3620   // FIXME: This ignores template objects, attachments, etc.
3621   content = tdoc.getContent();
3622   syntax = tdoc.getSyntax();
3623   }
3624   }
3625  
3626   if ((parent == null) || (parent.equals(""))) {
3627   parent = "XWiki.XWikiUsers";
3628   }
3629  
3630   // Mark the user as active or waiting email validation.
3631   if (withValidation) {
3632   map.put("active", new String[] { "0" });
3633   validkey = generateValidationKey(16);
3634   map.put("validkey", new String[] { validkey });
3635  
3636   } else {
3637   // Mark user active
3638   map.put("active", new String[] { "1" });
3639   }
3640  
3641   // Create the user.
3642   int result =
3643   createUser(xwikiname, map, getRelativeEntityReferenceResolver().resolve(parent, EntityType.DOCUMENT),
3644   content, syntax, userRights, context);
3645  
3646   // Send validation mail, if needed.
3647   if ((result > 0) && (withValidation)) {
3648   // Send the validation email
3649   try {
3650   sendValidationEmail(xwikiname, password, email, validkey, "validation_email_content", context);
3651   } catch (XWikiException e) {
3652   LOGGER.warn("User created. Failed to send the mail to the created user.", e);
3653   return -11;
3654   }
3655  
3656   }
3657  
3658   return result;
3659   } catch (XWikiException e) {
3660   LOGGER.error(e.getMessage(), e);
3661  
3662   throw e;
3663   } catch (Exception e) {
3664   LOGGER.error(e.getMessage(), e);
3665  
3666   throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_CREATE_USER,
3667   "Exception while creating user", e, null);
3668   }
3669   }
3670  
3671   /**
3672   * Method allows to create an empty user with no password (he won't be able to login) This method is usefull for
3673   * authentication like LDAP or App Server trusted
3674   *
3675   * @param xwikiname
3676   * @param userRights
3677   * @param context see {@link XWikiContext}
3678   * @return true if success
3679   * @throws XWikiException
3680   */
3681   public boolean createEmptyUser(String xwikiname, String userRights, XWikiContext context) throws XWikiException
3682   {
3683   Map map = new HashMap();
3684   map.put("active", "1");
3685   map.put("first_name", xwikiname);
3686  
3687   if (createUser(xwikiname, map, userRights, context) == 1) {
3688   return true;
3689   } else {
3690   return false;
3691   }
3692   }
3693  
3694   public void sendConfirmationEmail(String xwikiname, String password, String email, String message,
3695   String contentfield, XWikiContext context) throws XWikiException
3696   {
3697   sendValidationEmail(xwikiname, password, email, "message", message, contentfield, context);
3698   }
3699  
3700   public void sendValidationEmail(String xwikiname, String password, String email, String validkey,
3701   String contentfield, XWikiContext context) throws XWikiException
3702   {
3703   sendValidationEmail(xwikiname, password, email, "validkey", validkey, contentfield, context);
3704   }
3705  
3706   public void sendValidationEmail(String xwikiname, String password, String email, String addfieldname,
3707   String addfieldvalue, String contentfield, XWikiContext context) throws XWikiException
3708   {
3709   MailSenderConfiguration configuration = Utils.getComponent(MailSenderConfiguration.class);
3710  
3711   String sender;
3712   String content;
3713   try {
3714   sender = configuration.getFromAddress();
3715   if (StringUtils.isBlank(sender)) {
3716   String server = context.getRequest().getServerName();
3717   if (server.matches("\\[.*\\]|(\\d{1,3}+\\.){3}+\\d{1,3}+")) {
3718   sender = "noreply@domain.net";
3719   } else {
3720   sender = "noreply@" + server;
3721   }
3722   }
3723   content = getXWikiPreference(contentfield, context);
3724   } catch (Exception e) {
3725   throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
3726   XWikiException.ERROR_XWIKI_EMAIL_CANNOT_GET_VALIDATION_CONFIG,
3727   "Exception while reading the validation email config", e, null);
3728  
3729   }
3730  
3731   try {
3732   VelocityContext vcontext = (VelocityContext) context.get("vcontext");
3733   vcontext.put(addfieldname, addfieldvalue);
3734   vcontext.put("email", email);
3735   vcontext.put("password", password);
3736   vcontext.put("sender", sender);
3737   vcontext.put("xwikiname", xwikiname);
3738   content = parseContent(content, context);
3739   } catch (Exception e) {
3740   throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
3741   XWikiException.ERROR_XWIKI_EMAIL_CANNOT_PREPARE_VALIDATION_EMAIL,
3742   "Exception while preparing the validation email", e, null);
3743  
3744   }
3745  
3746   // Let's now send the message
3747   try {
3748   Session session =
3749   Session.getInstance(configuration.getAllProperties(), new XWikiAuthenticator(configuration));
3750   InputStream is = new ByteArrayInputStream(content.getBytes());
3751   MimeMessage message = new MimeMessage(session, is);
3752   message.setFrom(new InternetAddress(sender));
3753   message.setRecipients(Message.RecipientType.TO, email);
3754   message.setHeader("X-MailType", "Account Validation");
3755   MailSender mailSender = Utils.getComponent(MailSender.class);
3756   MailListener mailListener = Utils.getComponent(MailListener.class, "database");
3757   mailSender.sendAsynchronously(Arrays.asList(message), session, mailListener);
3758   mailListener.getMailStatusResult().waitTillProcessed(Long.MAX_VALUE);
3759   String errorMessage = MailStatusResultSerializer.serializeErrors(mailListener.getMailStatusResult());
3760   if (errorMessage != null) {
3761   throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
3762   XWikiException.ERROR_XWIKI_EMAIL_ERROR_SENDING_EMAIL,
3763   String.format("Error while sending the validation email. %s", errorMessage));
3764   }
3765   } catch (Exception e) {
3766   throw new XWikiException(XWikiException.MODULE_XWIKI_EMAIL,
3767   XWikiException.ERROR_XWIKI_EMAIL_ERROR_SENDING_EMAIL, "Error while sending the validation email", e);
3768   }
3769   }
3770  
3771   public String generateRandomString(int size)
3772   {
3773   return RandomStringUtils.randomAlphanumeric(size);
3774   }
3775  
3776   public String generateValidationKey(int size)
3777   {
3778   return generateRandomString(size);
3779   }
3780  
3781   /**
3782   * Create a new user.
3783   *
3784   * @param userName the name of the user (without the space)
3785   * @param map extra datas to add to user profile object
3786   * @param context see {@link XWikiContext}
3787   * @return
3788   *
3789   *
  • 1: ok
  • 3790   *
  • -3: user already exists
  • 3791   *
    3792   * @throws XWikiException failed to create the new user
    3793   */
    3794   public int createUser(String userName, Map map, XWikiContext context) throws XWikiException
    3795   {
    3796   return createUser(userName, map, "edit", context);
    3797   }
    3798  
    3799   /**
    3800   * Create a new user.
    3801   *
    3802   * @param userName the name of the user (without the space)
    3803   * @param map extra datas to add to user profile object
    3804   * @param userRights the right of the user on his own profile page
    3805   * @param context see {@link XWikiContext}
    3806   * @return
    3807   *
    3808   *
  • 1: ok
  • 3809   *
  • -3: user already exists
  • 3810   *
    3811   * @throws XWikiException failed to create the new user
    3812   */
    3813   public int createUser(String userName, Map map, String userRights, XWikiContext context)
    3814   throws XWikiException
    3815   {
    3816   BaseClass userClass = getUserClass(context);
    3817  
    3818   String content = "";
    3819   Syntax syntax = getDefaultDocumentSyntaxInternal();
    3820  
    3821   return createUser(userName, map,
    3822   new EntityReference(userClass.getDocumentReference().getName(), EntityType.DOCUMENT), content, syntax,
    3823   userRights, context);
    3824   }
    3825  
    3826   /**
    3827   * @deprecated since 2.4RC1 use
    3828   * {@link #createUser(String, Map, EntityReference, String, Syntax, String, XWikiContext)} instead
    3829   */
    3830   @Deprecated
    3831   public int createUser(String userName, Map map, String parent, String content, String syntaxId,
    3832   String userRights, XWikiContext context) throws XWikiException
    3833   {
    3834   Syntax syntax;
    3835  
    3836   try {
    3837   syntax = Syntax.valueOf(syntaxId);
    3838   } catch (ParseException e) {
    3839   syntax = getDefaultDocumentSyntaxInternal();
    3840   }
    3841  
    3842   return createUser(userName, map, getRelativeEntityReferenceResolver().resolve(parent, EntityType.DOCUMENT),
    3843   content, syntax, userRights, context);
    3844   }
    3845  
    3846   /**
    3847   * Create a new user.
    3848   *
    3849   * @param userName the name of the user (without the space)
    3850   * @param map extra datas to add to user profile object
    3851   * @param parentReference the parent of the user profile
    3852   * @param content the content of the user profile
    3853   * @param syntax the syntax of the provided content
    3854   * @param userRights the right of the user on his own profile page
    3855   * @param context see {@link XWikiContext}
    3856   * @return
    3857   *
    3858   *
  • 1: ok
  • 3859   *
  • -3: user already exists
  • 3860   *
    3861   * @throws XWikiException failed to create the new user
    3862   */
    3863   public int createUser(String userName, Map map, EntityReference parentReference, String content,
    3864   Syntax syntax, String userRights, XWikiContext context) throws XWikiException
    3865   {
    3866   BaseClass userClass = getUserClass(context);
    3867  
    3868   try {
    3869   // TODO: Verify existing user
    3870   XWikiDocument doc = getDocument(new DocumentReference(context.getWikiId(), "XWiki", userName), context);
    3871  
    3872   if (!doc.isNew()) {
    3873   // TODO: throws Exception
    3874   return -3;
    3875   }
    3876  
    3877   DocumentReference userClassReference = userClass.getDocumentReference();
    3878   BaseObject userObject =
    3879   doc.newXObject(userClassReference.removeParent(userClassReference.getWikiReference()), context);
    3880   userClass.fromMap(map, userObject);
    3881  
    3882   doc.setParentReference(parentReference);
    3883   doc.setContent(content);
    3884   doc.setSyntax(syntax);
    3885  
    3886   // Set the user itself as the creator of the document, so that she has the CREATOR right on her user page.
    3887   doc.setCreatorReference(doc.getDocumentReference());
    3888  
    3889   // However, we use the context user for the author to see in the history who has really created the user
    3890   // (it may be an administrator).
    3891   if (context.getUserReference() != null) {
    3892   doc.setAuthorReference(context.getUserReference());
    3893   } else {
    3894   // Except if the current user is guest (which means the user registered herself)
    3895   doc.setAuthorReference(doc.getDocumentReference());
    3896   }
    3897  
    3898   // The information from the user profile needs to be indexed using the proper locale. If multilingual is
    3899   // enabled then the user can choose the desired locale (from the list of supported locales) before
    3900   // registering. An administrator registering users can do the same. Otherwise, if there is only one locale
    3901   // supported then that langage will be used.
    3902   doc.setDefaultLocale(context.getLocale());
    3903  
    3904   protectUserPage(doc.getFullName(), userRights, doc, context);
    3905  
    3906   saveDocument(doc, localizePlainOrKey("core.comment.createdUser"), context);
    3907  
    3908   // Now let's add the user to XWiki.XWikiAllGroup
    3909   setUserDefaultGroup(doc.getFullName(), context);
    3910  
    3911   return 1;
    3912   } catch (Exception e) {
    3913   Object[] args = { "XWiki." + userName };
    3914   throw new XWikiException(XWikiException.MODULE_XWIKI_USER, XWikiException.ERROR_XWIKI_USER_CREATE,
    3915   "Cannot create user {0}", e, args);
    3916   }
    3917   }
    3918  
    3919   /**
    3920   * @deprecated starting with XE 1.8.1 use
    3921   * {@link #createUser(String, Map, String, String, String, String, XWikiContext)} instead
    3922   */
    3923   @Deprecated
    3924   public int createUser(String xwikiname, Map map, String parent, String content, String userRights,
    3925   XWikiContext context) throws XWikiException
    3926   {
    3927   return createUser(xwikiname, map, parent, content, Syntax.XWIKI_1_0.toIdString(), userRights, context);
    3928   }
    3929  
    3930   public void setUserDefaultGroup(String fullwikiname, XWikiContext context) throws XWikiException
    3931   {
    3932   String groupsPreference = isAllGroupImplicit() ? getConfiguration().getProperty("xwiki.users.initialGroups")
    3933   : getConfiguration().getProperty("xwiki.users.initialGroups", "XWiki.XWikiAllGroup");
    3934  
    3935   if (groupsPreference != null) {
    3936   String[] groups = groupsPreference.split(",");
    3937   for (String groupName : groups) {
    3938   if (StringUtils.isNotBlank(groupName)) {
    3939   addUserToGroup(fullwikiname, groupName.trim(), context);
    3940   }
    3941   }
    3942   }
    3943   }
    3944  
    3945   protected void addUserToGroup(String userName, String groupName, XWikiContext context) throws XWikiException
    3946   {
    3947   XWikiDocument groupDoc = getDocument(groupName, context);
    3948  
    3949   DocumentReference groupClassReference = getGroupClass(context).getDocumentReference();
    3950   BaseObject memberObject =
    3951   groupDoc.newXObject(groupClassReference.removeParent(groupClassReference.getWikiReference()), context);
    3952  
    3953   memberObject.setStringValue("member", userName);
    3954  
    3955   this.saveDocument(groupDoc, localizePlainOrKey("core.comment.addedUserToGroup"), context);
    3956   }
    3957  
    3958   public void protectUserPage(String userName, String userRights, XWikiDocument doc, XWikiContext context)
    3959   throws XWikiException
    3960   {
    3961   DocumentReference rightClassReference = getRightsClass(context).getDocumentReference();
    3962  
    3963   EntityReference relativeRightClassReference =
    3964   rightClassReference.removeParent(rightClassReference.getWikiReference());
    3965  
    3966   // Allow users to edit their own profiles
    3967   BaseObject newuserrightsobject = doc.newXObject(relativeRightClassReference, context);
    3968   newuserrightsobject.setLargeStringValue("users", userName);
    3969   newuserrightsobject.setStringValue("levels", userRights);
    3970   newuserrightsobject.setIntValue("allow", 1);
    3971   }
    3972  
    3973   public User getUser(XWikiContext context)
    3974   {
    3975   XWikiUser xwikiUser = context.getXWikiUser();
    3976   User user = new User(xwikiUser, context);
    3977   return user;
    3978   }
    3979  
    3980   public User getUser(String username, XWikiContext context)
    3981   {
    3982   XWikiUser xwikiUser = new XWikiUser(username);
    3983   User user = new User(xwikiUser, context);
    3984   return user;
    3985   }
    3986  
    3987   /**
    3988   * Prepares the localized resources, according to the selected locale. Set context "msg" and locale.
    3989   *
    3990   * @param context see {@link XWikiContext}
    3991   */
    3992   public void prepareResources(XWikiContext context)
    3993   {
    3994   if (context.get("msg") == null) {
    3995   Locale locale = getLocalePreference(context);
    3996   context.setLocale(locale);
    3997   if (context.getResponse() != null) {
    3998   context.getResponse().setLocale(locale);
    3999   }
    4000   XWikiMessageTool msg = new XWikiMessageTool(Utils.getComponent(ContextualLocalizationManager.class));
    4001   context.put("msg", msg);
    4002   }
    4003   }
    4004  
    4005   public XWikiUser checkAuth(XWikiContext context) throws XWikiException
    4006   {
    4007   return getAuthService().checkAuth(context);
    4008   }
    4009  
    4010   public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException
    4011   {
    4012   // Handle the 'skin' action specially so that resources don`t require special (or even 'view') rights.
    4013   String firstSpaceName = doc.getDocumentReference().getSpaceReferences().get(0).getName();
    4014   if (action.equals("skin") && SKIN_RESOURCE_SPACE_NAMES.contains(firstSpaceName)) {
    4015   // We still need to call checkAuth to set the proper user.
    4016   XWikiUser user = checkAuth(context);
    4017   if (user != null) {
    4018   context.setUser(user.getUser());
    4019   }
    4020  
    4021   // Always allow.
    4022   return true;
    4023   }
    4024  
    4025   return getRightService().checkAccess(action, doc, context);
    4026   }
    4027  
    4028   public String include(String topic, boolean isForm, XWikiContext context) throws XWikiException
    4029   {
    4030   String database = null, incdatabase = null;
    4031   String prefixedTopic, localTopic;
    4032  
    4033   // Save current documents in script context
    4034   Document currentAPIdoc = null, currentAPIcdoc = null, currentAPItdoc = null;
    4035   ScriptContextManager scritContextManager = Utils.getComponent(ScriptContextManager.class);
    4036   ScriptContext scontext = scritContextManager.getScriptContext();
    4037   String currentDocName = context.getWikiId() + ":" + context.getDoc().getFullName();
    4038   if (scontext != null) {
    4039   currentAPIdoc = (Document) scontext.getAttribute("doc");
    4040   currentAPIcdoc = (Document) scontext.getAttribute("cdoc");
    4041   currentAPItdoc = (Document) scontext.getAttribute("tdoc");
    4042   }
    4043  
    4044   try {
    4045   int i0 = topic.indexOf(':');
    4046   if (i0 != -1) {
    4047   incdatabase = topic.substring(0, i0);
    4048   database = context.getWikiId();
    4049   context.setWikiId(incdatabase);
    4050   prefixedTopic = topic;
    4051   localTopic = topic.substring(i0 + 1);
    4052   } else {
    4053   prefixedTopic = context.getWikiId() + ":" + topic;
    4054   localTopic = topic;
    4055   }
    4056  
    4057   XWikiDocument doc = null;
    4058   try {
    4059   LOGGER.debug("Including Topic " + topic);
    4060   try {
    4061   @SuppressWarnings("unchecked")
    4062   Set includedDocs = (Set) context.get("included_docs");
    4063   if (includedDocs == null) {
    4064   includedDocs = new HashSet();
    4065   context.put("included_docs", includedDocs);
    4066   }
    4067  
    4068   if (includedDocs.contains(prefixedTopic) || currentDocName.equals(prefixedTopic)) {
    4069   LOGGER.warn("Error on too many recursive includes for topic " + topic);
    4070   return "Cannot make recursive include";
    4071   }
    4072   includedDocs.add(prefixedTopic);
    4073   } catch (Exception e) {
    4074   }
    4075  
    4076   // Get document to include
    4077   DocumentReference targetDocumentReference =
    4078   getCurrentMixedDocumentReferenceResolver().resolve(localTopic);
    4079   doc = getDocument(targetDocumentReference, context);
    4080  
    4081   if (checkAccess("view", doc, context) == false) {
    4082   throw new XWikiException(XWikiException.MODULE_XWIKI_ACCESS,
    4083   XWikiException.ERROR_XWIKI_ACCESS_DENIED, "Access to this document is denied: " + doc);
    4084   }
    4085   } catch (XWikiException e) {
    4086   LOGGER.warn("Exception Including Topic " + topic, e);
    4087   return "Topic " + topic + " does not exist";
    4088   }
    4089  
    4090   XWikiDocument contentdoc = doc.getTranslatedDocument(context);
    4091  
    4092   String result;
    4093   if (isForm) {
    4094   // We do everything in the context of the including document
    4095   if (database != null) {
    4096   context.setWikiId(database);
    4097   }
    4098  
    4099   // Note: the Script macro in the new rendering checks for programming rights for the document in
    4100   // the xwiki context.
    4101   result = getRenderedContent(contentdoc, (XWikiDocument) context.get("doc"), context);
    4102   } else {
    4103   // We stay in the included document context
    4104  
    4105   // Since the Script macro checks for programming rights in the current document, we need to
    4106   // temporarily set the contentdoc as the current doc before rendering it.
    4107   XWikiDocument originalDoc = null;
    4108   try {
    4109   originalDoc = context.getDoc();
    4110   context.put("doc", doc);
    4111   result = getRenderedContent(contentdoc, doc, context);
    4112   } finally {
    4113   context.put("doc", originalDoc);
    4114   }
    4115   }
    4116   try {
    4117   @SuppressWarnings("unchecked")
    4118   Set includedDocs = (Set) context.get("included_docs");
    4119   if (includedDocs != null) {
    4120   includedDocs.remove(prefixedTopic);
    4121   }
    4122   } catch (Exception e) {
    4123   }
    4124   return result;
    4125   } finally {
    4126   if (database != null) {
    4127   context.setWikiId(database);
    4128   }
    4129  
    4130   if (currentAPIdoc != null) {
    4131   if (scontext != null) {
    4132   scontext.setAttribute("doc", currentAPIdoc, ScriptContext.ENGINE_SCOPE);
    4133   }
    4134   }
    4135   if (currentAPIcdoc != null) {
    4136   if (scontext != null) {
    4137   scontext.setAttribute("cdoc", currentAPIcdoc, ScriptContext.ENGINE_SCOPE);
    4138   }
    4139   }
    4140   if (currentAPItdoc != null) {
    4141   if (scontext != null) {
    4142   scontext.setAttribute("tdoc", currentAPItdoc, ScriptContext.ENGINE_SCOPE);
    4143   }
    4144   }
    4145   }
    4146   }
    4147  
    4148   /**
    4149   * Render content from the passed included document, setting the correct security doc (sdoc) and including doc
    4150   * (idoc).
    4151   *
    4152   * @since 2.2M2
    4153   */
    4154   private String getRenderedContent(XWikiDocument includedDoc, XWikiDocument includingDoc, XWikiContext context)
    4155   throws XWikiException
    4156   {
    4157   String result;
    4158   XWikiDocument idoc = (XWikiDocument) context.get("idoc");
    4159   XWikiDocument sdoc = (XWikiDocument) context.get("sdoc");
    4160  
    4161   context.put("idoc", includingDoc);
    4162   context.put("sdoc", includedDoc);
    4163   try {
    4164   result = includedDoc.getRenderedContent(Utils.getComponent(RenderingContext.class).getTargetSyntax(), false,
    4165   context);
    4166   } finally {
    4167   // Remove including doc or set the previous one
    4168   if (idoc == null) {
    4169   context.remove("idoc");
    4170   } else {
    4171   context.put("idoc", idoc);
    4172   }
    4173  
    4174   // Remove security doc or set the previous one
    4175   if (sdoc == null) {
    4176   context.remove("sdoc");
    4177   } else {
    4178   context.put("sdoc", sdoc);
    4179   }
    4180   }
    4181  
    4182   return result;
    4183   }
    4184  
    4185   public void deleteDocument(XWikiDocument doc, XWikiContext context) throws XWikiException
    4186   {
    4187   deleteDocument(doc, true, context);
    4188   }
    4189  
    4190   public void deleteDocument(XWikiDocument doc, boolean totrash, XWikiContext context) throws XWikiException
    4191   {
    4192   String currentWiki = null;
    4193  
    4194   currentWiki = context.getWikiId();
    4195   try {
    4196   context.setWikiId(doc.getDocumentReference().getWikiReference().getName());
    4197  
    4198   // The source document is a new empty XWikiDocument to follow
    4199   // DocumentUpdatedEvent policy: source document in new document and the old version is available using
    4200   // doc.getOriginalDocument()
    4201   XWikiDocument blankDoc = new XWikiDocument(doc.getDocumentReference());
    4202   // Again to follow general event policy, new document author is the user who modified the document
    4203   // (here the modification is delete)
    4204   blankDoc.setOriginalDocument(doc.getOriginalDocument());
    4205   blankDoc.setAuthorReference(context.getUserReference());
    4206   blankDoc.setContentAuthorReference(context.getUserReference());
    4207  
    4208   ObservationManager om = getObservationManager();
    4209  
    4210   // Inform notification mechanisms that a document is about to be deleted
    4211   // Note that for the moment the event being send is a bridge event, as we are still passing around
    4212   // an XWikiDocument as source and an XWikiContext as data.
    4213   if (om != null) {
    4214   CancelableEvent documentEvent = new DocumentDeletingEvent(doc.getDocumentReference());
    4215   om.notify(documentEvent, blankDoc, context);
    4216  
    4217   // If the action has been canceled by the user then don't perform any deletion and throw an exception
    4218   if (documentEvent.isCanceled()) {
    4219   throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
    4220   XWikiException.ERROR_XWIKI_STORE_HIBERNATE_DELETING_DOC,
    4221   String.format("An Event Listener has cancelled the document deletion for [%s]. Reason: [%s]",
    4222   doc.getDocumentReference(), documentEvent.getReason()));
    4223   }
    4224   }
    4225  
    4226   if (hasRecycleBin(context) && totrash) {
    4227   // Extract any existing batchId from the context.
    4228   String batchId = Utils.getComponent(BatchOperationExecutor.class).getCurrentBatchId();
    4229  
    4230   // Save to recycle bin together with any determined batch ID.
    4231   getRecycleBinStore().saveToRecycleBin(doc, context.getUser(), new Date(), batchId, context, true);
    4232   }
    4233  
    4234   getStore().deleteXWikiDoc(doc, context);
    4235  
    4236   try {
    4237   // Inform notification mechanisms that a document has been deleted
    4238   // Note that for the moment the event being send is a bridge event, as we are still passing around
    4239   // an XWikiDocument as source and an XWikiContext as data.
    4240   if (om != null) {
    4241   om.notify(new DocumentDeletedEvent(doc.getDocumentReference()), blankDoc, context);
    4242   }
    4243   } catch (Exception ex) {
    4244   LOGGER.error("Failed to send document delete notifications for document [{}]",
    4245   doc.getDocumentReference(), ex);
    4246   }
    4247   } finally {
    4248   context.setWikiId(currentWiki);
    4249   }
    4250   }
    4251  
    4252   public String getDatabase()
    4253   {
    4254   return this.database;
    4255   }
    4256  
    4257   public void setDatabase(String database)
    4258   {
    4259   this.database = database;
    4260   }
    4261  
    4262   public void gc()
    4263   {
    4264   System.gc();
    4265   }
    4266  
    4267   public long freeMemory()
    4268   {
    4269   return Runtime.getRuntime().freeMemory();
    4270   }
    4271  
    4272   public long totalMemory()
    4273   {
    4274   return Runtime.getRuntime().totalMemory();
    4275   }
    4276  
    4277   public long maxMemory()
    4278   {
    4279   return Runtime.getRuntime().maxMemory();
    4280   }
    4281  
    4282   public String[] split(String str, String sep)
    4283   {
    4284   return StringUtils.split(str, sep);
    4285   }
    4286  
    4287   /**
    4288   * @deprecated use {@link ExceptionUtils#getStackTrace(Throwable)} instead
    4289   */
    4290   @Deprecated
    4291   public String printStrackTrace(Throwable e)
    4292   {
    4293   StringWriter strwriter = new StringWriter();
    4294   PrintWriter writer = new PrintWriter(strwriter);
    4295   e.printStackTrace(writer);
    4296  
    4297   return strwriter.toString();
    4298   }
    4299  
    4300   /**
    4301   * @since 2.2M2
    4302   */
    4303   public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
    4304   XWikiContext context) throws XWikiException
    4305   {
    4306   return copyDocument(sourceDocumentReference, targetDocumentReference, null, true, context);
    4307   }
    4308  
    4309   /**
    4310   * @since 2.2M2
    4311   */
    4312   public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
    4313   boolean reset, XWikiContext context) throws XWikiException
    4314   {
    4315   return copyDocument(sourceDocumentReference, targetDocumentReference, null, reset, context);
    4316   }
    4317  
    4318   /**
    4319   * @since 2.2M2
    4320   */
    4321   public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
    4322   boolean reset, boolean force, boolean resetCreationData, XWikiContext context) throws XWikiException
    4323   {
    4324   return copyDocument(sourceDocumentReference, targetDocumentReference, null, reset, force, resetCreationData,
    4325   context);
    4326   }
    4327  
    4328   /**
    4329   * @since 2.2M2
    4330   */
    4331   public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
    4332   String wikilocale, XWikiContext context) throws XWikiException
    4333   {
    4334   return copyDocument(sourceDocumentReference, targetDocumentReference, wikilocale, true, context);
    4335   }
    4336  
    4337   /**
    4338   * @since 2.2M2
    4339   */
    4340   public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
    4341   String wikilocale, boolean reset, XWikiContext context) throws XWikiException
    4342   {
    4343   return copyDocument(sourceDocumentReference, targetDocumentReference, wikilocale, reset, false, context);
    4344   }
    4345  
    4346   /**
    4347   * @since 2.2M2
    4348   */
    4349   public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
    4350   String wikilocale, boolean reset, boolean force, XWikiContext context) throws XWikiException
    4351   {
    4352   return copyDocument(sourceDocumentReference, targetDocumentReference, wikilocale, reset, force, false, context);
    4353   }
    4354  
    4355   /**
    4356   * @since 2.2M2
    4357   */
    4358   public boolean copyDocument(DocumentReference sourceDocumentReference, DocumentReference targetDocumentReference,
    4359   String wikilocale, boolean reset, boolean force, boolean resetCreationData, XWikiContext context)
    4360   throws XWikiException