001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.main;
029
030import org.opencms.ade.configuration.CmsADEManager;
031import org.opencms.ade.containerpage.CmsContainerpageService;
032import org.opencms.cache.CmsVfsMemoryObjectCache;
033import org.opencms.configuration.CmsConfigurationException;
034import org.opencms.configuration.CmsConfigurationManager;
035import org.opencms.configuration.CmsImageCacheConfiguration;
036import org.opencms.configuration.CmsImportExportConfiguration;
037import org.opencms.configuration.CmsModuleConfiguration;
038import org.opencms.configuration.CmsParameterConfiguration;
039import org.opencms.configuration.CmsSchedulerConfiguration;
040import org.opencms.configuration.CmsSearchConfiguration;
041import org.opencms.configuration.CmsSitesConfiguration;
042import org.opencms.configuration.CmsSystemConfiguration;
043import org.opencms.configuration.CmsVariablesConfiguration;
044import org.opencms.configuration.CmsVfsConfiguration;
045import org.opencms.configuration.CmsWorkplaceConfiguration;
046import org.opencms.configuration.I_CmsNeedsAdminCmsObject;
047import org.opencms.crypto.I_CmsTextEncryption;
048import org.opencms.db.CmsAliasManager;
049import org.opencms.db.CmsDbEntryNotFoundException;
050import org.opencms.db.CmsDefaultUsers;
051import org.opencms.db.CmsExportPoint;
052import org.opencms.db.CmsLoginManager;
053import org.opencms.db.CmsModificationContext;
054import org.opencms.db.CmsSecurityManager;
055import org.opencms.db.CmsSqlManager;
056import org.opencms.db.CmsSubscriptionManager;
057import org.opencms.db.timing.CmsDefaultProfilingHandler;
058import org.opencms.db.timing.CmsThreadStatsTreeProfilingHandler;
059import org.opencms.file.CmsObject;
060import org.opencms.file.CmsProject;
061import org.opencms.file.CmsProperty;
062import org.opencms.file.CmsPropertyDefinition;
063import org.opencms.file.CmsRequestContext;
064import org.opencms.file.CmsResource;
065import org.opencms.file.CmsResourceFilter;
066import org.opencms.file.CmsUser;
067import org.opencms.file.CmsVfsResourceNotFoundException;
068import org.opencms.file.quota.CmsFolderSizeTracker;
069import org.opencms.flex.CmsFlexCache;
070import org.opencms.flex.CmsFlexCacheConfiguration;
071import org.opencms.flex.CmsFlexController;
072import org.opencms.gwt.CmsGwtService;
073import org.opencms.gwt.CmsGwtServiceContext2;
074import org.opencms.gwt.shared.CmsGwtConstants;
075import org.opencms.i18n.CmsEncoder;
076import org.opencms.i18n.CmsI18nInfo;
077import org.opencms.i18n.CmsLocaleManager;
078import org.opencms.i18n.CmsMessageContainer;
079import org.opencms.i18n.CmsSingleTreeLocaleHandler;
080import org.opencms.i18n.CmsVfsBundleManager;
081import org.opencms.importexport.CmsImportExportManager;
082import org.opencms.json.JSONObject;
083import org.opencms.jsp.CmsDefaultElementMarker;
084import org.opencms.jsp.I_CmsElementMarker;
085import org.opencms.jsp.jsonpart.CmsJsonPartFilter;
086import org.opencms.jsp.userdata.CmsUserDataRequestManager;
087import org.opencms.jsp.util.CmsJspStandardContextBean;
088import org.opencms.letsencrypt.CmsLetsEncryptConfiguration;
089import org.opencms.loader.CmsImageLoader;
090import org.opencms.loader.CmsJspLoader;
091import org.opencms.loader.CmsResourceManager;
092import org.opencms.loader.CmsTemplateContextManager;
093import org.opencms.loader.I_CmsFlexCacheEnabledLoader;
094import org.opencms.loader.I_CmsResourceLoader;
095import org.opencms.lock.CmsLockManager;
096import org.opencms.module.CmsModuleManager;
097import org.opencms.monitor.CmsMemoryMonitor;
098import org.opencms.monitor.CmsMemoryMonitorConfiguration;
099import org.opencms.mx.CmsDiagnosticsMXBean;
100import org.opencms.publish.CmsPublishEngine;
101import org.opencms.publish.CmsPublishManager;
102import org.opencms.repository.CmsRepositoryManager;
103import org.opencms.rmi.CmsRemoteShellServer;
104import org.opencms.scheduler.CmsScheduleManager;
105import org.opencms.search.CmsSearchManager;
106import org.opencms.security.CmsOrgUnitManager;
107import org.opencms.security.CmsPersistentLoginTokenHandler;
108import org.opencms.security.CmsRole;
109import org.opencms.security.CmsRoleManager;
110import org.opencms.security.CmsRoleViolationException;
111import org.opencms.security.CmsSecurityException;
112import org.opencms.security.I_CmsAuthorizationHandler;
113import org.opencms.security.I_CmsCredentialsResolver;
114import org.opencms.security.I_CmsPasswordHandler;
115import org.opencms.security.I_CmsSecretStore;
116import org.opencms.security.I_CmsValidationHandler;
117import org.opencms.security.twofactor.CmsTwoFactorAuthenticationHandler;
118import org.opencms.site.CmsSite;
119import org.opencms.site.CmsSiteManagerImpl;
120import org.opencms.site.CmsSiteMatcher;
121import org.opencms.staticexport.CmsDefaultLinkSubstitutionHandler;
122import org.opencms.staticexport.CmsLinkManager;
123import org.opencms.staticexport.CmsStaticExportManager;
124import org.opencms.ugc.CmsUgcSessionFactory;
125import org.opencms.ui.apps.CmsWorkplaceAppManager;
126import org.opencms.ui.dialogs.CmsPublishScheduledDialog;
127import org.opencms.ui.error.CmsErrorUI;
128import org.opencms.ui.login.CmsLoginHelper;
129import org.opencms.ui.login.CmsLoginUI;
130import org.opencms.util.CmsRequestUtil;
131import org.opencms.util.CmsStringUtil;
132import org.opencms.util.CmsTaskWatcher;
133import org.opencms.util.CmsUUID;
134import org.opencms.workflow.CmsDefaultWorkflowManager;
135import org.opencms.workflow.I_CmsWorkflowManager;
136import org.opencms.workplace.CmsWorkplace;
137import org.opencms.workplace.CmsWorkplaceLoginHandler;
138import org.opencms.workplace.CmsWorkplaceManager;
139import org.opencms.workplace.CmsWorkplaceSettings;
140import org.opencms.xml.CmsXmlContentTypeManager;
141import org.opencms.xml.CmsXmlUtils;
142import org.opencms.xml.containerpage.CmsFormatterConfiguration;
143import org.opencms.xml.xml2json.I_CmsApiAuthorizationHandler;
144
145import java.io.FileOutputStream;
146import java.io.IOException;
147import java.security.Security;
148import java.util.ArrayList;
149import java.util.Collections;
150import java.util.Date;
151import java.util.HashMap;
152import java.util.HashSet;
153import java.util.Hashtable;
154import java.util.Iterator;
155import java.util.LinkedHashMap;
156import java.util.List;
157import java.util.Locale;
158import java.util.Map;
159import java.util.ServiceLoader;
160import java.util.Set;
161import java.util.concurrent.CopyOnWriteArrayList;
162import java.util.concurrent.Future;
163import java.util.concurrent.ScheduledThreadPoolExecutor;
164import java.util.concurrent.TimeUnit;
165
166import org.apache.commons.logging.Log;
167import org.apache.logging.log4j.CloseableThreadContext;
168import org.apache.logging.log4j.jul.Log4jBridgeHandler;
169
170import org.antlr.stringtemplate.StringTemplate;
171
172import com.google.common.base.Optional;
173import com.google.common.util.concurrent.ThreadFactoryBuilder;
174
175import jakarta.servlet.ServletConfig;
176import jakarta.servlet.ServletContext;
177import jakarta.servlet.ServletException;
178import jakarta.servlet.http.HttpServletRequest;
179import jakarta.servlet.http.HttpServletResponse;
180import jakarta.servlet.http.HttpSession;
181
182/**
183 * The internal implementation of the core OpenCms "operating system" functions.<p>
184 *
185 * All access to this class must be done through the public static methods
186 * of the <code>{@link org.opencms.main.OpenCms}</code> object.
187 * Under no circumstances should you ever try to access this class directly.<p>
188 *
189 * This class is so OpenCms internal you should not even be reading this documentation ;-)<p>
190 *
191 * Any request to the <code>{@link org.opencms.main.OpenCmsServlet}</code> will be forwarded to this core class.
192 * The core will then try to map the request to a VFS (Virtual File System) URI,
193 * that is a <code>{@link org.opencms.file.CmsResource}</code> in the OpenCms database.
194 * If a resource is found, it will be read and forwarded to
195 * to the corresponding <code>{@link org.opencms.loader.I_CmsResourceLoader}</code>,
196 * which will then generate the output for the requested resource and return it to the requesting client.<p>
197 *
198 * There will be only one singleton instance of this object created for
199 * this core class. This means that in the default configuration, where
200 * OpenCms is accessed through a servlet context, there will be only one instance of
201 * the core in that servlet context.<p>
202 *
203 * @since 6.0.0
204 */
205public final class OpenCmsCore {
206
207    static {
208        Log4jBridgeHandler.install(true, null, true);
209    }
210
211    /** Parameter to control whether generated links should always include the host. */
212    public static final String PARAM_FORCE_ABSOLUTE_LINKS = "__forceAbsoluteLinks";
213
214    /** The static log object for this class. */
215    static final Log LOG = CmsLog.getLog(OpenCmsCore.class);
216
217    /** Lock object for synchronization. */
218    private static final Object LOCK = new Object();
219
220    /** Indicates if the configuration was successfully finished or not. */
221    private static CmsMessageContainer m_errorCondition;
222
223    /** One instance to rule them all, one instance to find them... */
224    private static OpenCmsCore m_instance;
225
226    static {
227        final String keyEntityExpansionLimit = "jdk.xml.entityExpansionLimit";
228        if (System.getProperty(keyEntityExpansionLimit) == null) {
229            System.setProperty(keyEntityExpansionLimit, "64000");
230        }
231    }
232
233    /** The ADE manager instance. */
234    private CmsADEManager m_adeManager;
235
236    /** The manager for page aliases. */
237    private CmsAliasManager m_aliasManager;
238
239    /** Map of API authorization handlers, with their names as keys. */
240    private Map<String, I_CmsApiAuthorizationHandler> m_apiAuthorizations;
241
242    /** The configured authorization handler. */
243    private I_CmsAuthorizationHandler m_authorizationHandler;
244
245    /** Admin CMS object. */
246    private CmsObject m_configAdminCms;
247
248    /** The configuration manager that contains the information from the XML configuration. */
249    private CmsConfigurationManager m_configurationManager;
250
251    /** The object used for resolving database user credentials. */
252    private I_CmsCredentialsResolver m_credentialsResolver;
253
254    /** List of configured directory default file names. */
255    private List<String> m_defaultFiles;
256
257    /** The default user and group names. */
258    private CmsDefaultUsers m_defaultUsers;
259
260    /** The event manager for the event handling. */
261    private CmsEventManager m_eventManager;
262
263    /** The thread pool executor. */
264    private ScheduledThreadPoolExecutor m_executor;
265
266    /** The set of configured export points. */
267    private Set<CmsExportPoint> m_exportPoints;
268
269    /** The flex cache instance. */
270    private CmsFlexCache m_flexCache;
271
272    /** The context objects for GWT services. */
273    private Map<String, CmsGwtServiceContext2> m_gwtServiceContexts;
274
275    /** The site manager contains information about the Cms import/export. */
276    private CmsImportExportManager m_importExportManager;
277
278    /** The LetsEncrypt configuration. */
279    private CmsLetsEncryptConfiguration m_letsEncryptConfig;
280
281    /** The link manager to resolve links in &lt;cms:link&gt; tags. */
282    private CmsLinkManager m_linkManager;
283
284    /** The locale manager used for obtaining the current locale. */
285    private CmsLocaleManager m_localeManager;
286
287    /** The login manager. */
288    private CmsLoginManager m_loginManager;
289
290    /** The memory monitor for the collection of memory and runtime statistics. */
291    private CmsMemoryMonitor m_memoryMonitor;
292
293    /** The module manager. */
294    private CmsModuleManager m_moduleManager;
295
296    /** The organizational unit manager. */
297    private CmsOrgUnitManager m_orgUnitManager;
298
299    /** The password handler used to digest and validate passwords. */
300    private I_CmsPasswordHandler m_passwordHandler;
301
302    /** The publish engine. */
303    private CmsPublishEngine m_publishEngine;
304
305    /** The publish manager instance. */
306    private CmsPublishManager m_publishManager;
307
308    /** The remote shell server. */
309    private CmsRemoteShellServer m_remoteShellServer;
310
311    /** The repository manager. */
312    private CmsRepositoryManager m_repositoryManager;
313
314    /** The configured request handlers that handle "special" requests, for example in the static export on demand. */
315    private Map<String, I_CmsRequestHandler> m_requestHandlers;
316
317    /** Stores the resource init handlers that allow modification of the requested resource. */
318    private List<I_CmsResourceInit> m_resourceInitHandlers;
319
320    /** The resource manager. */
321    private CmsResourceManager m_resourceManager;
322
323    /** The role manager. */
324    private CmsRoleManager m_roleManager;
325
326    /** The runlevel of this OpenCmsCore object instance. */
327    private int m_runLevel;
328
329    /** The runtime properties allow storage of system wide accessible runtime information. */
330    private Map<Object, Object> m_runtimeProperties;
331
332    /** The configured scheduler manager. */
333    private CmsScheduleManager m_scheduleManager;
334
335    /** The search manager provides indexing and searching. */
336    private CmsSearchManager m_searchManager;
337
338    /** The security manager to access the database and validate user permissions. */
339    private CmsSecurityManager m_securityManager;
340
341    /** The session manager. */
342    private CmsSessionManager m_sessionManager;
343
344    /** The site manager contains information about all configured sites. */
345    private CmsSiteManagerImpl m_siteManager;
346
347    /** List of start/stop handlers. */
348    private List<I_CmsStartStopHandler> m_startStopHandlers = new ArrayList<>();
349
350    /** The static export manager. */
351    private CmsStaticExportManager m_staticExportManager;
352
353    /** The subscription manager. */
354    private CmsSubscriptionManager m_subscriptionManager;
355
356    /** The system information container for "read only" system settings. */
357    private CmsSystemInfo m_systemInfo;
358
359    /** The template context manager. */
360    private CmsTemplateContextManager m_templateContextManager;
361
362    /** The text encryptions. */
363    private LinkedHashMap<String, I_CmsTextEncryption> m_textEncryptions;
364
365    /** The thread store. */
366    private CmsThreadStore m_threadStore;
367
368    /** The 2FA handler. */
369    private CmsTwoFactorAuthenticationHandler m_twoFactorAuthenticationHandler;
370
371    /** The user data request manager. */
372    private CmsUserDataRequestManager m_userDataRequestManager;
373
374    /** The runtime validation handler. */
375    private I_CmsValidationHandler m_validationHandler;
376
377    /** The VFS bundle manager. */
378    private CmsVfsBundleManager m_vfsBundleManager;
379
380    /** The default memory object cache instance. */
381    private CmsVfsMemoryObjectCache m_vfsMemoryObjectCache;
382
383    /** The workflow manager instance. */
384    private I_CmsWorkflowManager m_workflowManager;
385
386    /** The workplace app manager. */
387    private CmsWorkplaceAppManager m_workplaceAppManager;
388
389    /** The workplace manager contains information about the global workplace settings. */
390    private CmsWorkplaceManager m_workplaceManager;
391
392    /** The XML content type manager that contains the initialized XML content types. */
393    private CmsXmlContentTypeManager m_xmlContentTypeManager;
394
395    /** The future for the offline folder size tracker. */
396    private Future<CmsFolderSizeTracker> m_folderSizeTrackerFuture;
397
398    /** The future for the online folder size tracker. */
399    private Future<CmsFolderSizeTracker> m_onlineFolderSizeTrackerFuture;
400
401    private List<Runnable> m_shutdownActions = new CopyOnWriteArrayList<Runnable>();
402
403    /** The configured secret store. */
404    private I_CmsSecretStore m_secretStore;
405
406    /** The configured element marker handler (no-op default until configured). */
407    private I_CmsElementMarker m_elementMarker = new CmsDefaultElementMarker();
408
409    /**
410     * Protected constructor that will initialize the singleton OpenCms instance
411     * with runlevel {@link OpenCms#RUNLEVEL_1_CORE_OBJECT}.<p>
412     *
413     * @throws CmsInitException in case of errors during the initialization
414     */
415    private OpenCmsCore()
416    throws CmsInitException {
417
418        if ((m_instance != null) && (m_instance.getRunLevel() > OpenCms.RUNLEVEL_0_OFFLINE)) {
419            throw new CmsInitException(Messages.get().container(Messages.ERR_ALREADY_INITIALIZED_0));
420        }
421        initMembers();
422        m_instance = this;
423        setRunLevel(OpenCms.RUNLEVEL_1_CORE_OBJECT);
424    }
425
426    /**
427     * Returns the path for the request.<p>
428     *
429     * First checks the {@link HttpServletRequest#getPathInfo()}, then
430     * the configured request error page attribute (if set), and then
431     * if still undefined the <code>/</code> is returned as path info.<p>
432     *
433     * This is only needed when the {@link HttpServletRequest#getPathInfo()}
434     * is not really working as expected like in BEA WLS 9.x, where we have
435     * to use the 'weblogic.servlet.errorPage' request attribute.<p>
436     *
437     * @param req the http request context
438     *
439     * @return the path for the request
440     */
441    public static String getPathInfo(HttpServletRequest req) {
442
443        String path = req.getPathInfo();
444        if (path == null) {
445            // if the HttpServletRequest#getPathInfo() method does not work properly
446            String requestErrorPageAttribute = OpenCms.getSystemInfo().getServletContainerSettings().getRequestErrorPageAttribute();
447            if (requestErrorPageAttribute != null) {
448                // use the proper page attribute
449                path = (String)req.getAttribute(requestErrorPageAttribute);
450                if (path != null) {
451                    int pos = path.indexOf("/", 1);
452                    if (pos > 0) {
453                        // cut off the servlet name
454                        path = path.substring(pos);
455                    }
456                }
457            }
458        }
459        if (path == null) {
460            path = "/";
461        }
462        return path;
463    }
464
465    /**
466     * Returns the initialized OpenCms singleton instance.<p>
467     *
468     * @return the initialized OpenCms singleton instance
469     */
470    protected static OpenCmsCore getInstance() {
471
472        if (m_errorCondition != null) {
473            // OpenCms is not properly initialized
474            throw new CmsInitException(m_errorCondition, false);
475        }
476
477        if (m_instance != null) {
478            return m_instance;
479        }
480        synchronized (LOCK) {
481            if (m_instance == null) {
482                try {
483                    // create a new core object with runlevel 1
484                    m_instance = new OpenCmsCore();
485                } catch (CmsInitException e) {
486                    // already initialized, this is all we need
487                    LOG.debug(e.getMessage(), e);
488                }
489            }
490        }
491        return m_instance;
492    }
493
494    /**
495     * Sets the error condition.<p>
496     *
497     * @param errorCondition the error condition to set
498     */
499    protected static void setErrorCondition(CmsMessageContainer errorCondition) {
500
501        // init exceptions should only be thrown during setup process
502        if ((m_instance != null) && (m_instance.getRunLevel() < OpenCms.RUNLEVEL_3_SHELL_ACCESS)) {
503            if (!Messages.ERR_CRITICAL_INIT_WIZARD_0.equals(errorCondition.getKey())) {
504                // if wizard is still enabled allow retry of initialization (for setup wizard)
505                m_errorCondition = errorCondition;
506                // output an error message to the console
507                System.err.println(
508                    Messages.get().getBundle().key(Messages.LOG_INIT_FAILURE_MESSAGE_1, errorCondition.key()));
509            }
510            LOG.error(errorCondition.key(), new CmsException(errorCondition));
511            m_instance = null;
512        } else if (m_instance != null) {
513            // OpenCms already was successful initialized
514            LOG.warn(
515                Messages.get().getBundle().key(
516                    Messages.LOG_INIT_INVALID_ERROR_2,
517                    Integer.valueOf(m_instance.getRunLevel()),
518                    errorCondition.key()));
519        }
520    }
521
522    /**
523     * Gets the default CmsVfsMemoryCache instance.
524     *
525     * @return the default cache instance
526     */
527    public CmsVfsMemoryObjectCache getVfsMemoryObjectCache() {
528
529        if (m_vfsMemoryObjectCache == null) {
530            m_vfsMemoryObjectCache = new CmsVfsMemoryObjectCache();
531        }
532        return m_vfsMemoryObjectCache;
533
534    }
535
536    /**
537     * Registers a callback to be called before shutdown.
538     *
539     * @param action the action to execute before shutdown
540     */
541    public void registerShutdownAction(Runnable action) {
542
543        m_shutdownActions.add(action);
544    }
545
546    /**
547     * Adds the specified request handler to the Map of OpenCms request handlers. <p>
548     *
549     * @param handler the handler to add
550     */
551    protected void addRequestHandler(I_CmsRequestHandler handler) {
552
553        if (handler == null) {
554            return;
555        }
556        String[] names = handler.getHandlerNames();
557        for (int i = 0; i < names.length; i++) {
558            String name = names[i];
559            if (m_requestHandlers.get(name) != null) {
560                CmsLog.INIT.error(Messages.get().getBundle().key(Messages.LOG_DUPLICATE_REQUEST_HANDLER_1, name));
561                continue;
562            }
563            m_requestHandlers.put(name, handler);
564            if (CmsLog.INIT.isInfoEnabled()) {
565                CmsLog.INIT.info(
566                    Messages.get().getBundle().key(
567                        Messages.INIT_ADDED_REQUEST_HANDLER_2,
568                        name,
569                        handler.getClass().getName()));
570            }
571        }
572    }
573
574    /**
575     * Gets the ADE manager, and makes sure it is initialized.<p>
576     *
577     * @return the initialized ADE manager
578     */
579    protected CmsADEManager getADEManager() {
580
581        if (!m_adeManager.isInitialized()) {
582            m_adeManager.initialize();
583        }
584        return m_adeManager;
585    }
586
587    /**
588     * Returns the alias manager.<p>
589     *
590     * @return the alias manager
591     */
592    protected CmsAliasManager getAliasManager() {
593
594        return m_aliasManager;
595    }
596
597    /**
598     * Gets the API authorization handler with the given name, or null if it doesn't exist.
599     *
600     * @param name the name of the API authorization handler
601     * @return the API authorization handler, or null if it wasn't found
602     */
603    protected I_CmsApiAuthorizationHandler getApiAuthorization(String name) {
604
605        return m_apiAuthorizations.get(name);
606
607    }
608
609    /**
610     * Returns the configured authorization handler.<p>
611     *
612     * @return the configured authorization handler
613     */
614    protected I_CmsAuthorizationHandler getAuthorizationHandler() {
615
616        return m_authorizationHandler;
617    }
618
619    /**
620     * Returns the initialized OpenCms configuration manager.<p>
621     *
622     * @return the initialized OpenCms configuration manager
623     */
624    protected CmsConfigurationManager getConfigurationManager() {
625
626        return m_configurationManager;
627    }
628
629    /**
630     * Gets the configured credentials resolver instance.<p>
631     *
632     * @return the credentials resolver
633     */
634    protected I_CmsCredentialsResolver getCredentialsResolver() {
635
636        if (m_credentialsResolver == null) {
637            CmsSystemConfiguration systemConfig = (CmsSystemConfiguration)m_configurationManager.getConfiguration(
638                CmsSystemConfiguration.class);
639            return systemConfig.getCredentialsResolver();
640        }
641
642        return m_credentialsResolver;
643    }
644
645    /**
646     * Gets the database pool names.<p>
647     *
648     * @return the configured database pool names
649     */
650    protected List<String> getDbPoolNames() {
651
652        return new ArrayList<>(m_configurationManager.getConfiguration().getList("db.pools"));
653
654    }
655
656    /**
657     * Returns the configured list of default directory file names.<p>
658     *
659     * @return the configured list of default directory file names
660     */
661    protected List<String> getDefaultFiles() {
662
663        return m_defaultFiles;
664    }
665
666    /**
667     * Returns the default user and group name configuration.<p>
668     *
669     * @return the default user and group name configuration
670     */
671    protected CmsDefaultUsers getDefaultUsers() {
672
673        return m_defaultUsers;
674    }
675
676    /**
677     * Gets the configured element marker handler (a no-op default when none is configured).
678     *
679     * @return the element marker handler (never <code>null</code>)
680     */
681    protected I_CmsElementMarker getElementMarker() {
682
683        return m_elementMarker;
684    }
685
686    /**
687     * Returns the OpenCms event manager.<p>
688     *
689     * @return the OpenCms event manager
690     */
691    protected CmsEventManager getEventManager() {
692
693        return m_eventManager;
694    }
695
696    /**
697     * Gets the thread pool executor.<p>
698     *
699     * @return the thread pool executor
700     */
701    protected ScheduledThreadPoolExecutor getExecutor() {
702
703        return m_executor;
704    }
705
706    /**
707     * Returns the configured export points,
708     * the returned set being an unmodifiable set.<p>
709     *
710     * @return an unmodifiable set of the configured export points
711     */
712    protected Set<CmsExportPoint> getExportPoints() {
713
714        return m_exportPoints;
715    }
716
717    /**
718     * Gets the flex cache.
719     * @return CmsFlexCache
720     */
721
722    protected CmsFlexCache getFlexCache() {
723
724        return m_flexCache;
725    }
726
727    /**
728     * Gets a string containing all keys and variations currently in the flex cache, for debug purposes.<p>
729     *
730     * @return a debug information string with the flex cache data
731     */
732    protected String getFlexCacheKeyDump() {
733
734        if (m_flexCache != null) {
735            StringBuffer buffer = new StringBuffer();
736            m_flexCache.dumpKeys(buffer);
737            return buffer.toString();
738        } else {
739            return null;
740        }
741    }
742
743    /**
744     * Gets the folder size tracker for the  Online or Offline project
745     * @return true to get the online folder size tracker, false for the offline one
746     */
747    protected CmsFolderSizeTracker getFolderSizeTracker(boolean online) {
748
749        try {
750            return online ? m_onlineFolderSizeTrackerFuture.get() : m_folderSizeTrackerFuture.get();
751        } catch (Exception e) {
752            LOG.error(e.getLocalizedMessage(), e);
753            return null;
754        }
755    }
756
757    /**
758     * Returns the central image cache retention and maintenance configuration.<p>
759     *
760     * @return the image cache configuration
761     */
762    protected CmsImageCacheConfiguration getImageCacheConfiguration() {
763
764        CmsSystemConfiguration systemConfig = (CmsSystemConfiguration)m_configurationManager.getConfiguration(
765            CmsSystemConfiguration.class);
766        return systemConfig.getImageCacheConfiguration();
767    }
768
769    /**
770     * Returns the initialized import/export manager,
771     * which contains information about the Cms import/export.<p>
772     *
773     * @return the initialized import/export manager
774     */
775    protected CmsImportExportManager getImportExportManager() {
776
777        return m_importExportManager;
778    }
779
780    /**
781     * Gets the LetsEncrypt configuration.<p>
782     *
783     * @return the LetsEncrypt configuration
784     */
785    protected CmsLetsEncryptConfiguration getLetsEncryptConfig() {
786
787        return m_letsEncryptConfig;
788    }
789
790    /**
791     * Returns the link manager to resolve links in &lt;link&gt; tags.<p>
792     *
793     * @return  the link manager to resolve links in &lt;link&gt; tags
794     */
795    protected CmsLinkManager getLinkManager() {
796
797        return m_linkManager;
798    }
799
800    /**
801     * Returns the locale manager used for obtaining the current locale.<p>
802     *
803     * @return the locale manager
804     */
805    protected CmsLocaleManager getLocaleManager() {
806
807        return m_localeManager;
808    }
809
810    /**
811     * Returns the lock manager used for the locking mechanism.<p>
812     *
813     * @return the lock manager used for the locking mechanism
814     */
815    protected CmsLockManager getLockManager() {
816
817        return m_securityManager.getLockManager();
818    }
819
820    /**
821     * Returns the login manager used to check the validity of a login.<p>
822     *
823     * @return the login manager
824     */
825    protected CmsLoginManager getLoginManager() {
826
827        return m_loginManager;
828    }
829
830    /**
831     * Returns the memory monitor.<p>
832     *
833     * @return the memory monitor
834     */
835    protected CmsMemoryMonitor getMemoryMonitor() {
836
837        return m_memoryMonitor;
838    }
839
840    /**
841     * Returns the module manager.<p>
842     *
843     * @return the module manager
844     */
845    protected CmsModuleManager getModuleManager() {
846
847        return m_moduleManager;
848    }
849
850    /**
851     * Returns the organizational unit manager.<p>
852     *
853     * @return the organizational unit manager
854     */
855    protected CmsOrgUnitManager getOrgUnitManager() {
856
857        return m_orgUnitManager;
858    }
859
860    /**
861     * Return the password handler.<p>
862     *
863     * @return the password handler
864     */
865    protected I_CmsPasswordHandler getPasswordHandler() {
866
867        return m_passwordHandler;
868    }
869
870    /**
871     * Returns the publish manager instance.<p>
872     *
873     * @return the publish manager instance
874     */
875    protected CmsPublishManager getPublishManager() {
876
877        return m_publishManager;
878    }
879
880    /**
881     * Returns the repository manager.<p>
882     *
883     * @return the repository manager
884     */
885    protected CmsRepositoryManager getRepositoryManager() {
886
887        return m_repositoryManager;
888    }
889
890    /**
891     * Returns the handler instance for the specified name,
892     * or null if the name does not match any handler name.<p>
893     *
894     * @param name the name of the handler instance to return
895     * @return the handler instance for the specified name
896     */
897    protected I_CmsRequestHandler getRequestHandler(String name) {
898
899        return m_requestHandlers.get(name);
900    }
901
902    /**
903     * Returns the resource manager.<p>
904     *
905     * @return the resource manager
906     */
907    protected CmsResourceManager getResourceManager() {
908
909        return m_resourceManager;
910    }
911
912    /**
913     * Returns the role manager.<p>
914     *
915     * @return the role manager
916     */
917    protected CmsRoleManager getRoleManager() {
918
919        return m_roleManager;
920    }
921
922    /**
923     * Returns the runlevel of this OpenCmsCore object instance.<p>
924     *
925     * For a detailed description about the possible run levels,
926     * please see {@link OpenCms#getRunLevel()}.<p>
927     *
928     * @return the runlevel of this OpenCmsCore object instance
929     *
930     * @see OpenCms#getRunLevel()
931     */
932    protected int getRunLevel() {
933
934        return m_runLevel;
935    }
936
937    /**
938     * Looks up a value in the runtime property Map.<p>
939     *
940     * @param key the key to look up in the runtime properties
941     * @return the value for the key, or null if the key was not found
942     */
943    protected Object getRuntimeProperty(Object key) {
944
945        return m_runtimeProperties.get(key);
946    }
947
948    /**
949     * Returns the configured schedule manager.<p>
950     *
951     * @return the configured schedule manager
952     */
953    protected CmsScheduleManager getScheduleManager() {
954
955        return m_scheduleManager;
956    }
957
958    /**
959     * Returns the initialized search manager,
960     * which provides indexing and searching operations.<p>
961     *
962     * @return the initialized search manager
963     */
964    protected CmsSearchManager getSearchManager() {
965
966        return m_searchManager;
967    }
968
969    /**
970     * Gets the secret store.
971     *
972     * @return the secret store
973     */
974    protected I_CmsSecretStore getSecretStore() {
975
976        return m_secretStore;
977    }
978
979    /**
980     * Returns the initialized OpenCms security manager.<p>
981     *
982     * @return the initialized OpenCms security manager
983     */
984    protected CmsSecurityManager getSecurityManager() {
985
986        return m_securityManager;
987    }
988
989    /**
990     * Returns the session manager.<p>
991     *
992     * @return the session manager
993     */
994    protected CmsSessionManager getSessionManager() {
995
996        return m_sessionManager;
997    }
998
999    /**
1000     * Returns the initialized site manager,
1001     * which contains information about all configured sites.<p>
1002     *
1003     * @return the initialized site manager
1004     */
1005    protected CmsSiteManagerImpl getSiteManager() {
1006
1007        return m_siteManager;
1008    }
1009
1010    /**
1011     * Returns an instance of the common sql manager.<p>
1012     *
1013     * @return an instance of the common sql manager
1014     */
1015    protected CmsSqlManager getSqlManager() {
1016
1017        return m_securityManager.getSqlManager();
1018    }
1019
1020    /**
1021     * Returns the properties for the static export.<p>
1022     *
1023     * @return the properties for the static export
1024     */
1025    protected CmsStaticExportManager getStaticExportManager() {
1026
1027        return m_staticExportManager;
1028    }
1029
1030    /**
1031     * Returns the subscription manager.<p>
1032     *
1033     * @return the subscription manager
1034     */
1035    protected CmsSubscriptionManager getSubscriptionManager() {
1036
1037        return m_subscriptionManager;
1038    }
1039
1040    /**
1041     * Returns the system information storage.<p>
1042     *
1043     * @return the system information storage
1044     */
1045    protected CmsSystemInfo getSystemInfo() {
1046
1047        return m_systemInfo;
1048    }
1049
1050    /**
1051     * Gets the template context manager instance.<p>
1052     *
1053     * @return the template context manager instance
1054     */
1055    protected CmsTemplateContextManager getTemplateContextManager() {
1056
1057        return m_templateContextManager;
1058
1059    }
1060
1061    /**
1062     * Gets the text encryptions.
1063     *
1064     * @return the text encryptions
1065     */
1066    protected Map<String, I_CmsTextEncryption> getTextEncryptions() {
1067
1068        return m_textEncryptions;
1069    }
1070
1071    /**
1072     * Returns the OpenCms Thread store.<p>
1073     *
1074     * @return the OpenCms Thread store
1075     */
1076    protected CmsThreadStore getThreadStore() {
1077
1078        return m_threadStore;
1079    }
1080
1081    /**
1082     * Gets the two-factor authentication handler.
1083     *
1084     * @return the two-factor authentication handler
1085     */
1086    protected CmsTwoFactorAuthenticationHandler getTwoFactorAuthenticationHandler() {
1087
1088        return m_twoFactorAuthenticationHandler;
1089    }
1090
1091    /**
1092     * Gets the user data request manager.
1093     *
1094     * @return the user data request manager
1095     */
1096    protected CmsUserDataRequestManager getUserDataRequestManager() {
1097
1098        return m_userDataRequestManager;
1099    }
1100
1101    /**
1102     * Returns the runtime validation handler.<p>
1103     *
1104     * @return the validation handler
1105     */
1106    protected I_CmsValidationHandler getValidationHandler() {
1107
1108        return m_validationHandler;
1109    }
1110
1111    /**
1112     * Returns the workflow manager instance.<p>
1113     *
1114     * @return the workflow manager
1115     */
1116    protected I_CmsWorkflowManager getWorkflowManager() {
1117
1118        return m_workflowManager;
1119    }
1120
1121    /**
1122     * Returns the workplace app manager.<p>
1123     *
1124     * @return the workplace app manager
1125     */
1126    protected CmsWorkplaceAppManager getWorkplaceAppManager() {
1127
1128        return m_workplaceAppManager;
1129    }
1130
1131    /**
1132     * Returns the initialized workplace manager,
1133     * which contains information about the global workplace settings.<p>
1134     *
1135     * @return the initialized workplace manager
1136     */
1137    protected CmsWorkplaceManager getWorkplaceManager() {
1138
1139        return m_workplaceManager;
1140    }
1141
1142    /**
1143     * Returns the XML content type manager.<p>
1144     *
1145     * @return the XML content type manager
1146     */
1147    protected CmsXmlContentTypeManager getXmlContentTypeManager() {
1148
1149        if (m_xmlContentTypeManager != null) {
1150            return m_xmlContentTypeManager;
1151        }
1152        if (getRunLevel() == OpenCms.RUNLEVEL_1_CORE_OBJECT) {
1153            // this is only to enable test cases to run
1154            m_xmlContentTypeManager = CmsXmlContentTypeManager.createTypeManagerForTestCases();
1155        }
1156        return m_xmlContentTypeManager;
1157    }
1158
1159    /**
1160     * Initializes the OpenCms context for Vaadin UI servlet.<p>
1161     *
1162     * @param req the request
1163     * @param res the response
1164     * @param servlet the UI servlet
1165     *
1166     * @throws IOException if user authentication fails
1167     * @throws CmsException if something goes wrong
1168     */
1169    protected void initCmsContextForUI(HttpServletRequest req, HttpServletResponse res, CmsUIServlet servlet)
1170    throws IOException, CmsException {
1171
1172        // instantiate CMS context
1173        String originalEncoding = req.getCharacterEncoding();
1174        String referrer = req.getHeader("referer");
1175        boolean allowPrivilegedLogin = (referrer == null) || !referrer.contains(CmsWorkplaceLoginHandler.LOGIN_HANDLER);
1176
1177        CmsObject cms = initCmsObject(req, res, allowPrivilegedLogin);
1178        servlet.setCms(cms);
1179        if (originalEncoding != null) {
1180            // getI18NInfo sets wrong encoding
1181            req.setCharacterEncoding(originalEncoding);
1182        }
1183    }
1184
1185    /**
1186     * Returns an independent copy of the provided CmsObject.<p>
1187     *
1188     * This can be useful in case a permanent reference to a CmsObject is stored.
1189     * Changing the request context values (for example project, siteroot) in the new CmsObject
1190     * will have no side effects to the CmsObject it was copied form.<p>
1191     *
1192     * The request time (<code>{@link CmsRequestContext#getRequestTime()}</code>)
1193     * is set to the current time.<p>
1194     *
1195     * @param cms the CmsObject to create a copy of
1196     *
1197     * @return an independent copy of the provided CmsObject
1198     *
1199     * @throws CmsException in case the initialization failed
1200     *
1201     * @see OpenCms#initCmsObject(CmsObject)
1202     * @see OpenCms#initCmsObject(CmsObject, CmsContextInfo)
1203     * @see OpenCms#initCmsObject(String)
1204     */
1205    protected CmsObject initCmsObject(CmsObject cms) {
1206
1207        CmsRequestContext requestContext = cms.getRequestContext();
1208        CmsRequestContext context = new CmsRequestContext(
1209            requestContext.getCurrentUser().clone(),
1210            (CmsProject)(requestContext.getCurrentProject().clone()),
1211            requestContext.getUri(),
1212            requestContext.getRequestMatcher(),
1213            requestContext.getSiteRoot(),
1214            requestContext.isSecureRequest(),
1215            requestContext.getLocale(),
1216            requestContext.getEncoding(),
1217            requestContext.getRemoteAddress(),
1218            System.currentTimeMillis(),
1219            m_resourceManager.getFolderTranslator(),
1220            m_resourceManager.getFileTranslator(),
1221            requestContext.getOuFqn(),
1222            requestContext.isForceAbsoluteLinks());
1223        context.setDetailResource(requestContext.getDetailResource());
1224        CmsObject result = new CmsObject(m_securityManager, context);
1225        return result;
1226    }
1227
1228    /**
1229     * Returns an initialized CmsObject with the user and context initialized as provided.<p>
1230     *
1231     * Note: Only if the provided <code>adminCms</code> CmsObject has admin permissions,
1232     * this method allows the creation a CmsObject for any existing user. Otherwise
1233     * only the default users 'Guest' and 'Export' can initialized with
1234     * this method, all other user names will throw an Exception.<p>
1235     *
1236     * @param adminCms must either be initialized with "Admin" permissions, or null
1237     * @param contextInfo the context info to create a CmsObject for
1238     *
1239     * @return an initialized CmsObject with the given users permissions
1240     *
1241     * @throws CmsException if an invalid user name was provided
1242     * @throws CmsRoleViolationException if the current user does not have the role permissions to create a context for the requested user
1243     *
1244     * @see org.opencms.db.CmsDefaultUsers#getUserGuest()
1245     * @see org.opencms.db.CmsDefaultUsers#getUserExport()
1246     * @see OpenCms#initCmsObject(CmsObject)
1247     * @see OpenCms#initCmsObject(CmsObject, CmsContextInfo)
1248     * @see OpenCms#initCmsObject(String)
1249     */
1250    protected CmsObject initCmsObject(CmsObject adminCms, CmsContextInfo contextInfo)
1251    throws CmsRoleViolationException, CmsException {
1252
1253        String userName = contextInfo.getUserName();
1254
1255        if ((adminCms == null) || !m_roleManager.hasRole(adminCms, CmsRole.ROOT_ADMIN)) {
1256            if (!userName.endsWith(getDefaultUsers().getUserGuest())
1257                && !userName.endsWith(getDefaultUsers().getUserExport())) {
1258
1259                // if no admin object is provided, only "Guest" or "Export" user can be generated
1260                CmsMessageContainer message = Messages.get().container(
1261                    Messages.ERR_INVALID_INIT_USER_2,
1262                    userName,
1263                    ((adminCms != null) ? (adminCms.getRequestContext().getCurrentUser().getName()) : ""));
1264                if (LOG.isWarnEnabled()) {
1265                    LOG.warn(message.key());
1266                }
1267                throw new CmsRoleViolationException(message);
1268            }
1269        }
1270
1271        return initCmsObject(contextInfo);
1272    }
1273
1274    /**
1275     * Handles the user authentification for each request sent to OpenCms.<p>
1276     *
1277     * User authentification is done in three steps:
1278     * <ol>
1279     * <li>Session authentification: OpenCms stores information of all authentificated
1280     *      users in an internal storage based on the users session.</li>
1281     * <li>Authorization handler authentification: If the session authentification fails,
1282     *      the current configured authorization handler is called.</li>
1283     * <li>Default user: When both authentification methods fail, the user is set to
1284     *      the default (Guest) user.</li>
1285     * </ol>
1286     *
1287     * @param req the current http request
1288     * @param res the current http response
1289     * @param allowPrivilegedLogin <code>true</code> to allow login through authorization handlers
1290     *
1291     * @return the initialized cms context
1292     *
1293     * @throws IOException if user authentication fails
1294     * @throws CmsException in case something goes wrong
1295     */
1296    protected CmsObject initCmsObject(HttpServletRequest req, HttpServletResponse res, boolean allowPrivilegedLogin)
1297    throws IOException, CmsException {
1298
1299        // first try to restore a stored session
1300        CmsObject cms = initCmsObjectFromSession(req);
1301        if (cms != null) {
1302            return cms;
1303        }
1304        if (allowPrivilegedLogin) {
1305            // if does not work, try to authorize the request
1306            I_CmsAuthorizationHandler.I_PrivilegedLoginAction loginAction = new I_CmsAuthorizationHandler.I_PrivilegedLoginAction() {
1307
1308                private CmsObject m_adminCms;
1309
1310                /**
1311                 * @see org.opencms.security.I_CmsAuthorizationHandler.I_PrivilegedLoginAction#doLogin(jakarta.servlet.http.HttpServletRequest, java.lang.String)
1312                 */
1313                public CmsObject doLogin(HttpServletRequest request, String principal) throws CmsException {
1314
1315                    try {
1316                        CmsUser user = m_adminCms.readUser(principal);
1317                        if (!user.isEnabled()) {
1318                            throw new CmsException(
1319                                Messages.get().container(Messages.ERR_INVALID_INIT_USER_2, user.getName(), "-"));
1320                        }
1321
1322                        // initialize the new cms object
1323                        CmsContextInfo contextInfo = new CmsContextInfo(m_adminCms.getRequestContext());
1324                        contextInfo.setUserName(principal);
1325                        CmsObject newCms = initCmsObject(m_adminCms, contextInfo);
1326
1327                        if ((contextInfo.getRequestedUri().startsWith("/system/workplace/")
1328                            // also check for new workplace
1329                            || request.getRequestURI().startsWith(OpenCms.getSystemInfo().getWorkplaceContext()))
1330                            && getRoleManager().hasRole(newCms, CmsRole.ELEMENT_AUTHOR)) {
1331                            LOG.debug("Handling workplace login for user " + principal);
1332                            CmsWorkplaceSettings settings = CmsLoginHelper.initSiteAndProject(newCms);
1333                            request.getSession(true).setAttribute(
1334                                CmsWorkplaceManager.SESSION_WORKPLACE_SETTINGS,
1335                                settings);
1336                            OpenCms.getSessionManager().updateSessionInfo(newCms, request);
1337                        }
1338                        m_adminCms.updateLastLoginDate(user);
1339
1340                        // fire the login user event
1341                        OpenCms.fireCmsEvent(
1342                            I_CmsEventListener.EVENT_LOGIN_USER,
1343                            Collections.<String, Object> singletonMap("data", user));
1344                        return newCms;
1345                    } finally {
1346                        m_adminCms = null;
1347                    }
1348                }
1349
1350                /**
1351                 * @see org.opencms.security.I_CmsAuthorizationHandler.I_PrivilegedLoginAction#getCmsObject()
1352                 */
1353                public CmsObject getCmsObject() {
1354
1355                    return m_adminCms;
1356                }
1357
1358                /**
1359                 * @see org.opencms.security.I_CmsAuthorizationHandler.I_PrivilegedLoginAction#setCmsObject(org.opencms.file.CmsObject)
1360                 */
1361                public void setCmsObject(CmsObject adminCms) {
1362
1363                    m_adminCms = adminCms;
1364                }
1365            };
1366            loginAction.setCmsObject(initCmsObject(req, res, OpenCms.getDefaultUsers().getUserAdmin(), null, null));
1367            cms = m_authorizationHandler.initCmsObject(req, loginAction);
1368            if (cms != null) {
1369                return cms;
1370            }
1371
1372            // authentification failed or not enough permissions, so display a login screen
1373            m_authorizationHandler.requestAuthorization(req, res, getLoginFormURL(req, res));
1374        }
1375        cms = initCmsObject(
1376            req,
1377            m_securityManager.readUser(null, OpenCms.getDefaultUsers().getUserGuest()),
1378            getSiteManager().matchRequest(req).getSiteRoot(),
1379            CmsProject.ONLINE_PROJECT_ID,
1380            "");
1381        // return the initialized cms user context object
1382        return cms;
1383    }
1384
1385    /**
1386     * Returns an initialized CmsObject with the user initialized as provided,
1387     * with the "Online" project selected and "/" set as the current site root.<p>
1388     *
1389     * Note: Only the default users 'Guest' and 'Export' can initialized with
1390     * this method, all other user names will throw an Exception.<p>
1391     *
1392     * @param user the user name to initialize, can only be
1393     *        {@link org.opencms.db.CmsDefaultUsers#getUserGuest()} or
1394     *        {@link org.opencms.db.CmsDefaultUsers#getUserExport()}
1395     *
1396     * @return an initialized CmsObject with the given users permissions
1397     *
1398     * @throws CmsException if an invalid user name was provided, or if something else goes wrong
1399     *
1400     * @see org.opencms.db.CmsDefaultUsers#getUserGuest()
1401     * @see org.opencms.db.CmsDefaultUsers#getUserExport()
1402     * @see OpenCms#initCmsObject(String)
1403     * @see #initCmsObject(CmsObject, CmsContextInfo)
1404     */
1405    protected CmsObject initCmsObject(String user) throws CmsException {
1406
1407        return initCmsObject(null, new CmsContextInfo(user));
1408    }
1409
1410    /**
1411     * Initializes a new cms object from the session data of the request.<p>
1412     *
1413     * If no session data is found, <code>null</code> is returned.<p>
1414     *
1415     * @param req the request
1416     *
1417     * @return the new initialized cms object
1418     *
1419     * @throws CmsException if something goes wrong
1420     */
1421    protected CmsObject initCmsObjectFromSession(HttpServletRequest req) throws CmsException {
1422
1423        String url = req.getRequestURL().toString();
1424        String p = "[ " + url + " ] ";
1425        if (LOG.isDebugEnabled()) {
1426            LOG.debug(p + "Trying to init cms object from session for request \"" + req.toString() + "\".");
1427        }
1428        // try to get an OpenCms user session info object for this request
1429        CmsSessionInfo sessionInfo = m_sessionManager.getSessionInfo(req);
1430
1431        if (sessionInfo == null) {
1432            if (LOG.isDebugEnabled()) {
1433                LOG.debug(p + "No session info found.");
1434            }
1435            return null;
1436        }
1437        if (!getSessionManager().hasValidClientToken(req)) {
1438            if (LOG.isDebugEnabled()) {
1439                LOG.debug("Client token in session invalid.");
1440            }
1441            return null;
1442        }
1443
1444        // initialize the requested site root
1445        CmsSite site = getSiteManager().matchRequest(req);
1446
1447        // a user name is found in the session manager, reuse this user information
1448        CmsUUID project = sessionInfo.getProject();
1449
1450        // initialize site root from request
1451        String siteroot = sessionInfo.getSiteRoot();
1452        if (siteroot == null) {
1453            // not sure if this can actually happen?
1454            LOG.debug(p + "site root from session info was null, determining site root from current request's host");
1455            siteroot = site.getSiteRoot();
1456        }
1457        // initialize user from request
1458        CmsUser user = m_securityManager.readUser(null, sessionInfo.getUserId());
1459
1460        if (LOG.isDebugEnabled()) {
1461            LOG.debug(p + "Initializing cms object with user \"" + user.getName() + "\".");
1462            LOG.debug(p + "siteRoot = " + siteroot);
1463        }
1464        return initCmsObject(req, user, siteroot, project, sessionInfo.getOrganizationalUnitFqn());
1465    }
1466
1467    /**
1468     * Constructor to create a new OpenCms object.<p>
1469     *
1470     * It reads the configurations from the <code>opencms.properties</code>
1471     * file in the <code>config/</code> subdirectory. With the information
1472     * from this file is inits a ResourceBroker (Database access module),
1473     * various caching systems and other options.<p>
1474     *
1475     * This will only be done once per accessing class.
1476     *
1477     * @param configuration the configurations from the <code>opencms.properties</code> file
1478     * @throws CmsInitException in case OpenCms can not be initialized
1479     */
1480    protected synchronized void initConfiguration(CmsParameterConfiguration configuration) throws CmsInitException {
1481
1482        String serverInfo = configuration.getString("context.servlet.container", null);
1483
1484        // output startup message to log file
1485        if (CmsLog.INIT.isInfoEnabled()) {
1486            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
1487            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
1488            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
1489            CmsLog.INIT.info(
1490                ". "
1491                    + Messages.get().getBundle().key(
1492                        Messages.GUI_SHELL_VERSION_1,
1493                        OpenCms.getSystemInfo().getVersionNumber()));
1494            for (int i = 0; i < Messages.COPYRIGHT_BY_ALKACON.length; i++) {
1495                CmsLog.INIT.info(". " + Messages.COPYRIGHT_BY_ALKACON[i]);
1496            }
1497            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LINE_0));
1498            CmsLog.INIT.info(
1499                Messages.get().getBundle().key(Messages.INIT_STARTUP_TIME_1, new Date(System.currentTimeMillis())));
1500            CmsLog.INIT.info(
1501                Messages.get().getBundle().key(
1502                    Messages.INIT_OPENCMS_VERSION_1,
1503                    OpenCms.getSystemInfo().getVersionNumber() + " [" + OpenCms.getSystemInfo().getVersionId() + "]"));
1504            if (serverInfo != null) {
1505                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SERVLET_CONTAINER_1, serverInfo));
1506            }
1507            CmsLog.INIT.info(
1508                Messages.get().getBundle().key(Messages.INIT_WEBAPP_NAME_1, getSystemInfo().getWebApplicationName()));
1509            CmsLog.INIT.info(
1510                Messages.get().getBundle().key(Messages.INIT_SERVLET_PATH_1, getSystemInfo().getServletPath()));
1511            CmsLog.INIT.info(
1512                Messages.get().getBundle().key(Messages.INIT_OPENCMS_CONTEXT_1, getSystemInfo().getOpenCmsContext()));
1513            CmsLog.INIT.info(
1514                Messages.get().getBundle().key(Messages.INIT_WEBINF_PATH_1, getSystemInfo().getWebInfRfsPath()));
1515            CmsLog.INIT.info(
1516                Messages.get().getBundle().key(
1517                    Messages.INIT_PROPERTY_FILE_1,
1518                    getSystemInfo().getConfigurationFileRfsPath()));
1519
1520            String logFileRfsPath = getSystemInfo().getLogFileRfsPath();
1521            CmsLog.INIT.info(
1522                Messages.get().getBundle().key(
1523                    Messages.INIT_LOG_FILE_1,
1524                    logFileRfsPath != null ? logFileRfsPath : "Managed by log4j"));
1525        }
1526
1527        String systemEncoding = null;
1528        try {
1529            systemEncoding = System.getProperty("file.encoding");
1530        } catch (SecurityException se) {
1531            // security manager is active, but we will try other options before giving up
1532            LOG.debug("Security manager preventing access to file.encoding system property.", se);
1533        }
1534        try {
1535            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
1536        } catch (Exception e) {
1537            CmsLog.INIT.error(e.getLocalizedMessage(), e);
1538        }
1539        if (CmsLog.INIT.isInfoEnabled()) {
1540            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_FILE_ENCODING_1, systemEncoding));
1541        }
1542
1543        // read server ethernet address (MAC) and init UUID generator
1544        String ethernetAddress = configuration.getString("server.ethernet.address", CmsStringUtil.getEthernetAddress());
1545        if (CmsLog.INIT.isInfoEnabled()) {
1546            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ETHERNET_ADDRESS_1, ethernetAddress));
1547        }
1548        CmsUUID.init(ethernetAddress);
1549
1550        // set the server name
1551        String serverName = configuration.getString("server.name", "OpenCmsServer");
1552        getSystemInfo().setServerName(serverName);
1553
1554        // check the installed Java SDK
1555        try {
1556            if (CmsLog.INIT.isInfoEnabled()) {
1557                String jdkinfo = System.getProperty("java.vm.name") + " ";
1558                jdkinfo += System.getProperty("java.vm.version") + " ";
1559                jdkinfo += System.getProperty("java.vm.info") + " ";
1560                jdkinfo += System.getProperty("java.vm.vendor") + " ";
1561                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_JAVA_VM_1, jdkinfo));
1562                String osinfo = System.getProperty("os.name") + " ";
1563                osinfo += System.getProperty("os.version") + " ";
1564                osinfo += System.getProperty("os.arch") + " ";
1565                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_OPERATING_SYSTEM_1, osinfo));
1566            }
1567        } catch (Exception e) {
1568            throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_PROP_0), e);
1569        }
1570
1571        // create the configuration manager instance
1572        m_configurationManager = new CmsConfigurationManager(getSystemInfo().getConfigFolder());
1573        // store the configuration read from "opencms.properties" in the configuration manager
1574        m_configurationManager.setConfiguration(configuration);
1575
1576        // now load the XML configuration
1577        try {
1578            m_configurationManager.loadXmlConfiguration();
1579        } catch (Exception e) {
1580            throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_XML_0), e);
1581        }
1582
1583        // get the system configuration
1584        CmsSystemConfiguration systemConfiguration = (CmsSystemConfiguration)m_configurationManager.getConfiguration(
1585            CmsSystemConfiguration.class);
1586
1587        if (systemConfiguration.useSaxImplSystemProperties()) {
1588            CmsXmlUtils.initSystemProperties();
1589        }
1590
1591        // initialize the memory monitor
1592        CmsMemoryMonitorConfiguration memoryMonitorConfiguration = systemConfiguration.getCmsMemoryMonitorConfiguration();
1593        // initialize the memory monitor
1594        try {
1595            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(memoryMonitorConfiguration.getClassName())) {
1596                m_memoryMonitor = (CmsMemoryMonitor)Class.forName(
1597                    memoryMonitorConfiguration.getClassName()).getDeclaredConstructor().newInstance();
1598            } else {
1599                m_memoryMonitor = new CmsMemoryMonitor();
1600            }
1601        } catch (Exception e) {
1602            // we can not start without a valid memory monitor
1603            throw new CmsInitException(
1604                Messages.get().container(
1605                    Messages.ERR_CRITICAL_INIT_MEMORY_MONITOR_1,
1606                    memoryMonitorConfiguration.getClassName()),
1607                e);
1608        }
1609        m_memoryMonitor.initialize(systemConfiguration);
1610
1611        // get the event manager from the configuration and initialize it with the events already registered
1612        CmsEventManager configuredEventManager = systemConfiguration.getEventManager();
1613        configuredEventManager.initialize(m_eventManager);
1614        m_eventManager = configuredEventManager;
1615
1616        // check if the encoding setting is valid
1617        String setEncoding = systemConfiguration.getDefaultContentEncoding();
1618        String defaultEncoding = CmsEncoder.lookupEncoding(setEncoding, null);
1619        if (defaultEncoding == null) {
1620            // we can not start without a valid encoding setting
1621            throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_ENCODING_1, setEncoding));
1622        }
1623        if (CmsLog.INIT.isInfoEnabled()) {
1624            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_OPENCMS_ENCODING_1, defaultEncoding));
1625        }
1626        getSystemInfo().setDefaultEncoding(defaultEncoding);
1627
1628        // set version history information
1629        getSystemInfo().setVersionHistorySettings(
1630            systemConfiguration.isHistoryEnabled(),
1631            systemConfiguration.getHistoryVersions(),
1632            systemConfiguration.getHistoryVersionsAfterDeletion());
1633        // set mail configuration
1634        getSystemInfo().setMailSettings(systemConfiguration.getMailSettings());
1635        // set HTTP authentication settings
1636        getSystemInfo().setHttpAuthenticationSettings(systemConfiguration.getHttpAuthenticationSettings());
1637        getSystemInfo().setRestrictDetailContents(systemConfiguration.isRestrictDetailContents());
1638
1639        // set content notification settings
1640        getSystemInfo().setNotificationTime(systemConfiguration.getNotificationTime());
1641        getSystemInfo().setNotificationProject(systemConfiguration.getNotificationProject());
1642        m_executor = new ScheduledThreadPoolExecutor(
1643            3,
1644            new ThreadFactoryBuilder().setNameFormat("OpenCmsCore-exec-%d").build());
1645        // set resource init classes
1646
1647        m_resourceInitHandlers = systemConfiguration.getResourceInitHandlers();
1648
1649        // register request handler classes
1650        Iterator<I_CmsRequestHandler> it = systemConfiguration.getRequestHandlers().iterator();
1651        while (it.hasNext()) {
1652            I_CmsRequestHandler handler = it.next();
1653            addRequestHandler(handler);
1654            if (CmsLog.INIT.isInfoEnabled()) {
1655                CmsLog.INIT.info(
1656                    Messages.get().getBundle().key(
1657                        Messages.INIT_REQUEST_HANDLER_CLASS_1,
1658                        handler.getClass().getName()));
1659            }
1660        }
1661
1662        // read the default user configuration
1663        m_defaultUsers = systemConfiguration.getCmsDefaultUsers();
1664
1665        // get the site manager from the configuration
1666        CmsSitesConfiguration sitesConfiguration = (CmsSitesConfiguration)m_configurationManager.getConfiguration(
1667            CmsSitesConfiguration.class);
1668        m_siteManager = sitesConfiguration.getSiteManager();
1669
1670        CmsSchedulerConfiguration schedulerConfiguration = (CmsSchedulerConfiguration)m_configurationManager.getConfiguration(
1671            CmsSchedulerConfiguration.class);
1672        // set the scheduler manager
1673        m_scheduleManager = schedulerConfiguration.getScheduleManager();
1674
1675        CmsVariablesConfiguration variablesConfiguration = (CmsVariablesConfiguration)m_configurationManager.getConfiguration(
1676            CmsVariablesConfiguration.class);
1677
1678        // get the VFS / resource configuration
1679        CmsVfsConfiguration vfsConfiguation = (CmsVfsConfiguration)m_configurationManager.getConfiguration(
1680            CmsVfsConfiguration.class);
1681        m_resourceManager = vfsConfiguation.getResourceManager();
1682        I_CmsResourceLoader imageLoader = m_resourceManager.getLoader(CmsImageLoader.RESOURCE_LOADER_ID_IMAGE_LOADER);
1683        if (imageLoader instanceof CmsImageLoader) {
1684            try {
1685                ((CmsImageLoader)imageLoader).initializeImageCache(configuration);
1686            } catch (CmsConfigurationException e) {
1687                throw new CmsInitException(e.getMessageContainer(), e);
1688            }
1689        }
1690        m_xmlContentTypeManager = vfsConfiguation.getXmlContentTypeManager();
1691        m_defaultFiles = vfsConfiguation.getDefaultFiles();
1692
1693        // initialize translation engines
1694        m_resourceManager.setTranslators(
1695            vfsConfiguation.getFolderTranslator(),
1696            vfsConfiguation.getFileTranslator(),
1697            vfsConfiguation.getXsdTranslator());
1698
1699        // try to initialize the flex cache
1700        CmsFlexCache flexCache = null;
1701        try {
1702            if (CmsLog.INIT.isInfoEnabled()) {
1703                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_FLEX_CACHE_STARTING_0));
1704            }
1705            // get the flex cache configuration from the SystemConfiguration
1706            CmsFlexCacheConfiguration flexCacheConfiguration = systemConfiguration.getCmsFlexCacheConfiguration();
1707            getSystemInfo().setDeviceSelector(flexCacheConfiguration.getDeviceSelector());
1708            // pass configuration to flex cache for initialization
1709            flexCache = new CmsFlexCache(flexCacheConfiguration);
1710            m_flexCache = flexCache;
1711            if (CmsLog.INIT.isInfoEnabled()) {
1712                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_FLEX_CACHE_FINISHED_0));
1713            }
1714        } catch (Exception e) {
1715            if (CmsLog.INIT.isWarnEnabled()) {
1716                CmsLog.INIT.warn(Messages.get().getBundle().key(Messages.INIT_FLEX_CACHE_ERROR_1, e.getMessage()));
1717            }
1718        }
1719
1720        if (flexCache != null) {
1721            // check all resource loaders if they require the Flex cache
1722            Iterator<I_CmsResourceLoader> i = m_resourceManager.getLoaders().iterator();
1723            while (i.hasNext()) {
1724                Object o = i.next();
1725                if (o instanceof I_CmsFlexCacheEnabledLoader) {
1726                    // this resource loader requires the Flex cache
1727                    ((I_CmsFlexCacheEnabledLoader)o).setFlexCache(flexCache);
1728                }
1729            }
1730        }
1731
1732        // get the import/export configuration
1733        CmsImportExportConfiguration importExportConfiguration = (CmsImportExportConfiguration)m_configurationManager.getConfiguration(
1734            CmsImportExportConfiguration.class);
1735        try {
1736            importExportConfiguration.validate();
1737        } catch (CmsConfigurationException e) {
1738            throw new CmsInitException(e.getMessageContainer(), e);
1739        }
1740        m_importExportManager = importExportConfiguration.getImportExportManager();
1741        m_staticExportManager = importExportConfiguration.getStaticExportManager();
1742        m_staticExportManager.setStoredContentDeliveryConfiguration(
1743            importExportConfiguration.getStoredContentDeliveryConfiguration());
1744        m_staticExportManager.setSharedCacheConfiguration(importExportConfiguration.getSharedCacheConfiguration());
1745        m_repositoryManager = importExportConfiguration.getRepositoryManager();
1746
1747        // get the search configuration
1748        CmsSearchConfiguration searchConfiguration = (CmsSearchConfiguration)m_configurationManager.getConfiguration(
1749            CmsSearchConfiguration.class);
1750        m_searchManager = searchConfiguration.getSearchManager();
1751
1752        // get the workplace configuration
1753        CmsWorkplaceConfiguration workplaceConfiguration = (CmsWorkplaceConfiguration)m_configurationManager.getConfiguration(
1754            CmsWorkplaceConfiguration.class);
1755        m_workplaceManager = workplaceConfiguration.getWorkplaceManager();
1756        // add the export points from the workplace
1757        addExportPoints(m_workplaceManager.getExportPoints());
1758        addExportPoints(m_staticExportManager.getExportPoints());
1759
1760        // get the module configuration
1761        CmsModuleConfiguration moduleConfiguration = (CmsModuleConfiguration)m_configurationManager.getConfiguration(
1762            CmsModuleConfiguration.class);
1763        m_moduleManager = moduleConfiguration.getModuleManager();
1764
1765        // get the password handler
1766        m_passwordHandler = systemConfiguration.getPasswordHandler();
1767
1768        // get the validation handler
1769        m_validationHandler = systemConfiguration.getValidationHandler();
1770
1771        // get the authorization handler
1772        m_authorizationHandler = systemConfiguration.getAuthorizationHandler();
1773
1774        // get the login manager
1775        m_loginManager = systemConfiguration.getLoginManager();
1776        // set the login message
1777        try {
1778            m_loginManager.setLoginMessage(null, variablesConfiguration.getLoginMessage());
1779            m_loginManager.setBeforeLoginMessage(null, variablesConfiguration.getBeforeLoginMessage());
1780        } catch (CmsRoleViolationException e1) {
1781            CmsLog.INIT.error(e1.getLocalizedMessage(), e1);
1782        }
1783
1784        // initialize the publish engine
1785        m_publishEngine = new CmsPublishEngine(systemConfiguration.getRuntimeInfoFactory());
1786
1787        // Credentials resolver - needs to be set before the driver manager is initialized
1788        m_credentialsResolver = systemConfiguration.getCredentialsResolver();
1789
1790        m_secretStore = systemConfiguration.getSecretStore();
1791
1792        m_elementMarker = systemConfiguration.getElementMarker();
1793
1794        // init the OpenCms security manager
1795        m_securityManager = CmsSecurityManager.newInstance(
1796            m_configurationManager,
1797            systemConfiguration.getRuntimeInfoFactory(),
1798            m_publishEngine);
1799
1800        // get the publish manager
1801        m_publishManager = systemConfiguration.getPublishManager();
1802
1803        // get the subscription manager
1804        m_subscriptionManager = systemConfiguration.getSubscriptionManager();
1805
1806        // initialize the role manager
1807        m_roleManager = new CmsRoleManager(m_securityManager);
1808
1809        // initialize the organizational unit manager
1810        m_orgUnitManager = new CmsOrgUnitManager(m_securityManager);
1811
1812        // initialize the Thread store
1813        m_threadStore = new CmsThreadStore(m_securityManager);
1814
1815        // initialize the link manager
1816        m_linkManager = new CmsLinkManager(m_staticExportManager.getLinkSubstitutionHandler());
1817
1818        m_aliasManager = new CmsAliasManager(m_securityManager);
1819
1820        // store the runtime properties
1821        m_runtimeProperties.putAll(systemConfiguration.getRuntimeProperties());
1822
1823        // initialize the session storage provider
1824        I_CmsSessionStorageProvider sessionStorageProvider = systemConfiguration.getSessionStorageProvider();
1825
1826        // get an Admin cms context object with site root set to "/"
1827        CmsObject adminCms;
1828        try {
1829            adminCms = initCmsObject(null, null, getDefaultUsers().getUserAdmin(), (String)null, (String)null);
1830        } catch (CmsException e) {
1831            throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_ADMINCMS_0), e);
1832        }
1833        m_configAdminCms = adminCms;
1834
1835        m_repositoryManager.initializeCms(adminCms);
1836        // now initialize the other managers
1837        try {
1838            if (flexCache != null) {
1839                flexCache.initializeCms(initCmsObject(adminCms));
1840            }
1841
1842            m_configurationManager.setAdminCms(adminCms);
1843
1844            // initialize the scheduler
1845            m_scheduleManager.initialize(initCmsObject(adminCms));
1846
1847            // initialize the locale manager
1848            m_localeManager = systemConfiguration.getLocaleManager();
1849            m_localeManager.initialize(initCmsObject(adminCms));
1850
1851            // initialize the site manager
1852            m_siteManager.initialize(initCmsObject(adminCms));
1853
1854            // initialize the static export manager
1855            m_staticExportManager.initialize(initCmsObject(adminCms));
1856
1857            // initialize the XML content type manager
1858            m_xmlContentTypeManager.initialize(initCmsObject(adminCms));
1859
1860            m_orgUnitManager.initialize(initCmsObject(adminCms));
1861
1862            // initialize the module manager
1863            m_moduleManager.initialize(initCmsObject(adminCms), m_configurationManager);
1864
1865            // initialize the resource manager
1866            m_resourceManager.initialize(initCmsObject(adminCms));
1867
1868            // initialize the publish manager
1869            m_publishManager.setPublishEngine(m_publishEngine);
1870            m_publishManager.setSecurityManager(m_securityManager);
1871            m_publishManager.setPublishListRemoveMode(systemConfiguration.getPublishListRemoveMode());
1872            m_publishManager.initialize(initCmsObject(adminCms));
1873
1874            // initialize the search manager
1875            m_searchManager.initialize(initCmsObject(adminCms));
1876
1877            // initialize the VFS bundle manager
1878            m_vfsBundleManager = new CmsVfsBundleManager(adminCms);
1879
1880            // initialize the workplace manager
1881            m_workplaceManager.initialize(initCmsObject(adminCms));
1882
1883            // initialize the session manager
1884            m_sessionManager.initialize(sessionStorageProvider, initCmsObject(adminCms));
1885            m_sessionManager.setUserSessionMode(systemConfiguration.getUserSessionMode(true));
1886
1887            // initialize the subscription manager
1888            m_subscriptionManager.setSecurityManager(m_securityManager);
1889            m_subscriptionManager.initialize(adminCms);
1890
1891            CmsUgcSessionFactory.setAdminCms(adminCms);
1892
1893            // initialize the formatter configuration
1894            CmsFormatterConfiguration.initialize(adminCms);
1895            CmsPersistentLoginTokenHandler.setAdminCms(initCmsObject(adminCms));
1896            CmsLoginUI.setAdminCmsObject(initCmsObject(adminCms));
1897
1898            // initialize ade manager
1899            m_adeManager = new CmsADEManager(initCmsObject(adminCms), m_memoryMonitor, systemConfiguration);
1900            m_workplaceAppManager = new CmsWorkplaceAppManager(initCmsObject(adminCms));
1901            m_workplaceAppManager.loadApps();
1902            m_workplaceAppManager.initWorkplaceCssUris(m_moduleManager);
1903
1904            m_templateContextManager = new CmsTemplateContextManager(initCmsObject(adminCms));
1905            m_workflowManager = systemConfiguration.getWorkflowManager();
1906            m_letsEncryptConfig = systemConfiguration.getLetsEncryptConfig();
1907
1908            m_userDataRequestManager = systemConfiguration.getUserDataRequestManager();
1909            if (m_userDataRequestManager != null) {
1910                m_userDataRequestManager.initialize(initCmsObject(adminCms));
1911            }
1912
1913            if (m_workflowManager == null) {
1914                m_workflowManager = new CmsDefaultWorkflowManager();
1915                m_workflowManager.setParameters(new HashMap<String, String>());
1916            }
1917
1918            m_remoteShellServer = CmsRemoteShellServer.initialize(systemConfiguration);
1919
1920            CmsPublishScheduledDialog.setAdminCms(initCmsObject(adminCms));
1921
1922            m_workflowManager.initialize(initCmsObject(adminCms));
1923            m_apiAuthorizations = systemConfiguration.getApiAuthorizations();
1924            for (I_CmsApiAuthorizationHandler apiAuthorization : m_apiAuthorizations.values()) {
1925                apiAuthorization.initialize(initCmsObject(adminCms));
1926            }
1927
1928            for (I_CmsResourceInit resourceInit : m_resourceInitHandlers) {
1929                if (resourceInit instanceof I_CmsNeedsAdminCmsObject) {
1930                    ((I_CmsNeedsAdminCmsObject)resourceInit).setAdminCmsObject(adminCms);
1931                }
1932            }
1933            for (I_CmsRequestHandler requestHandler : m_requestHandlers.values()) {
1934                if (requestHandler instanceof I_CmsNeedsAdminCmsObject) {
1935                    ((I_CmsNeedsAdminCmsObject)requestHandler).setAdminCmsObject(adminCms);
1936                }
1937            }
1938
1939            if (m_loginManager.getCustomLogin() != null) {
1940                m_loginManager.getCustomLogin().initialize(initCmsObject(adminCms));
1941            }
1942
1943            m_textEncryptions = new LinkedHashMap<>();
1944            for (I_CmsTextEncryption encryption : systemConfiguration.getTextEncryptions().values()) {
1945                encryption.initialize(OpenCms.initCmsObject(adminCms));
1946                m_textEncryptions.put(encryption.getName(), encryption);
1947            }
1948
1949            m_twoFactorAuthenticationHandler = new CmsTwoFactorAuthenticationHandler(
1950                OpenCms.initCmsObject(adminCms),
1951                systemConfiguration.getTwoFactorAuthenticationConfig());
1952
1953            m_secretStore.initialize(initCmsObject(adminCms));
1954
1955        } catch (CmsException e) {
1956            throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_MANAGERS_0), e);
1957        }
1958
1959        try {
1960            // mitigate potential stringtemplate 3 class loading deadlock by making sure the class is loaded on startup
1961            @SuppressWarnings("unused")
1962            StringTemplate stringTemplate = new org.antlr.stringtemplate.StringTemplate();
1963        } catch (Exception e) {
1964            CmsLog.INIT.error("Problem with initializing stringtemplate class: " + e.getLocalizedMessage(), e);
1965        }
1966
1967        try {
1968            CmsModificationContext.initialize(
1969                m_securityManager,
1970                initCmsObject(adminCms),
1971                vfsConfiguation.getOnlineFolderOptions());
1972        } catch (Exception e) {
1973            CmsLog.INIT.error("Problem with initializing modification context");
1974        }
1975
1976        try {
1977            getEventManager().fireEvent(I_CmsEventListener.EVENT_CLEAR_CACHES);
1978        } catch (Exception e) {
1979            CmsLog.INIT.error("Problem with clearing caches after initialization: " + e.getLocalizedMessage(), e);
1980        }
1981        CmsTaskWatcher.initialize();
1982    }
1983
1984    /**
1985     * Initialization of the OpenCms runtime environment.<p>
1986     *
1987     * The connection information for the database is read
1988     * from the <code>opencms.properties</code> configuration file and all
1989     * driver manager are initialized via the initializer,
1990     * which usually will be an instance of a <code>OpenCms</code> class.
1991     *
1992     * @param context configuration of OpenCms from <code>web.xml</code>
1993     * @throws CmsInitException in case OpenCms can not be initialized
1994     */
1995    protected synchronized void initContext(ServletContext context) throws CmsInitException {
1996
1997        m_gwtServiceContexts = new HashMap<String, CmsGwtServiceContext2>();
1998
1999        // automatic servlet container recognition and specific behavior:
2000        CmsServletContainerSettings servletContainerSettings = new CmsServletContainerSettings(context);
2001        getSystemInfo().init(servletContainerSettings);
2002        getSystemInfo().initJavaEeVersion(context.getMajorVersion(), context.getMinorVersion());
2003
2004        // Collect the configurations
2005        CmsParameterConfiguration configuration;
2006        try {
2007            configuration = new CmsParameterConfiguration(getSystemInfo().getConfigurationFileRfsPath());
2008        } catch (Exception e) {
2009            throw new CmsInitException(
2010                Messages.get().container(
2011                    Messages.ERR_CRITICAL_INIT_PROPFILE_1,
2012                    getSystemInfo().getConfigurationFileRfsPath()),
2013                e);
2014        }
2015
2016        String throwException = configuration.getString("servlet.exception.enabled", "auto");
2017        if (!throwException.equals("auto")) {
2018            // set the parameter is not automatic, the rest of the servlet container dependent parameters
2019            // will be set when reading the system configuration, if not set to auto
2020            boolean throwExc = Boolean.valueOf(throwException).booleanValue();
2021            getSystemInfo().getServletContainerSettings().setServletThrowsException(throwExc);
2022        }
2023
2024        // check if the wizard is enabled, if so stop initialization
2025        if (configuration.getBoolean("wizard.enabled", true)) {
2026            throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_WIZARD_0));
2027        }
2028
2029        // add an indicator that the configuration was processed from the servlet context
2030        configuration.add("context.servlet.container", context.getServerInfo());
2031
2032        // output startup message and copyright to STDERR
2033        System.err.println(
2034            Messages.get().getBundle().key(
2035                Messages.LOG_STARTUP_CONSOLE_NOTE_2,
2036                OpenCms.getSystemInfo().getVersionNumber(),
2037                getSystemInfo().getWebApplicationName()));
2038        for (int i = 0; i < Messages.COPYRIGHT_BY_ALKACON.length; i++) {
2039            System.err.println(Messages.COPYRIGHT_BY_ALKACON[i]);
2040        }
2041        System.err.println();
2042
2043        // initialize the configuration
2044        initConfiguration(configuration);
2045    }
2046
2047    /**
2048     * Initialize member variables.<p>
2049     */
2050    protected void initMembers() {
2051
2052        synchronized (LOCK) {
2053            m_resourceInitHandlers = new ArrayList<I_CmsResourceInit>();
2054            m_requestHandlers = new HashMap<String, I_CmsRequestHandler>();
2055            m_systemInfo = new CmsSystemInfo();
2056            m_exportPoints = Collections.emptySet();
2057            m_defaultUsers = new CmsDefaultUsers();
2058            m_localeManager = new CmsLocaleManager(Locale.ENGLISH);
2059            m_sessionManager = new CmsSessionManager();
2060            m_runtimeProperties = new Hashtable<Object, Object>();
2061            // the default event manager must be available because the configuration already registers events
2062            m_eventManager = new CmsEventManager();
2063            // default link manager is required for test cases
2064            m_linkManager = new CmsLinkManager(new CmsDefaultLinkSubstitutionHandler());
2065        }
2066    }
2067
2068    /**
2069     * Reads the requested resource from the OpenCms VFS,
2070     * in case a directory name is requested, the default files of the
2071     * directory will be looked up and the first match is returned.<p>
2072     *
2073     * The resource that is returned is always a <code>{@link org.opencms.file.CmsFile}</code>,
2074     * even though the content will usually not be loaded in the result. Folders are never returned since
2075     * the point of this method is really to load the default file if just a folder name is requested. If
2076     * there is no default file in a folder, then the return value is null and no CmsException is thrown.<p>
2077     *
2078     * The URI stored in the given OpenCms user context will be changed to the URI of the resource
2079     * that was found and returned.<p>
2080     *
2081     * Implementing and configuring an <code>{@link I_CmsResourceInit}</code> handler
2082     * allows to customize the process of default resource selection.<p>
2083     *
2084     * @param cms the current users OpenCms context
2085     * @param resourceName the path of the requested resource in the OpenCms VFS
2086     * @param req the current http request
2087     * @param res the current http response
2088     *
2089     * @return the requested resource read from the VFS
2090     *
2091     * @throws CmsException in case the requested file does not exist or the user has insufficient access permissions
2092     *
2093     * @see OpenCms#initResource(CmsObject, String, HttpServletRequest, HttpServletResponse)
2094     */
2095    protected CmsResource initResource(
2096        CmsObject cms,
2097        String resourceName,
2098        HttpServletRequest req,
2099        HttpServletResponse res)
2100    throws CmsException {
2101
2102        CmsException tmpException = null;
2103        CmsResource resource;
2104        boolean handledSecure = false;
2105
2106        try {
2107            // try to read the requested resource
2108            resource = cms.readDefaultFile(resourceName, CmsResourceFilter.ignoreExpirationOffline(cms));
2109        } catch (CmsException e) {
2110            // file or folder with given name does not exist, store exception
2111            tmpException = e;
2112            resource = null;
2113        }
2114
2115        if (resource != null) {
2116            // set the request uri to the right file
2117            cms.getRequestContext().setUri(cms.getSitePath(resource));
2118            // test if this file is only available for internal access operations
2119            if (resource.isInternalOrInInternalFolder()) {
2120                throw new CmsException(
2121                    Messages.get().container(Messages.ERR_READ_INTERNAL_RESOURCE_1, cms.getRequestContext().getUri()));
2122            }
2123
2124            resource = handleSecureResource(cms, req, res, resource, resourceName);
2125            if (resource == null) {
2126                handledSecure = true;
2127
2128            }
2129        }
2130
2131        boolean clearErrors = false;
2132        // test if this file has to be checked or modified
2133        for (I_CmsResourceInit handler : m_resourceInitHandlers) {
2134            try {
2135                resource = handler.initResource(resource, cms, req, res);
2136                // the loop has to be interrupted when the exception is thrown!
2137            } catch (CmsResourceInitException e) {
2138                if (e.isClearErrors()) {
2139                    tmpException = null;
2140                    clearErrors = true;
2141                }
2142                break;
2143            } catch (CmsSecurityException e) {
2144                tmpException = e;
2145                break;
2146            }
2147        }
2148
2149        // file is still null and not found exception was thrown, so throw original exception
2150        if (resource == null) {
2151            if (tmpException != null) {
2152                throw tmpException;
2153            } else if (!clearErrors) {
2154                throw new CmsVfsResourceNotFoundException(
2155                    org.opencms.main.Messages.get().container(
2156                        org.opencms.main.Messages.ERR_PATH_NOT_FOUND_1,
2157                        resourceName));
2158
2159            }
2160        } else {
2161            if (!handledSecure) {
2162                if (cms.getRequestContext().getDetailContentId() != null) {
2163                    // in theory we should do this for all kinds of resource init handlers,
2164                    // but I'm not clear on how to handle this in general, so only do this for detail pages for now
2165                    resource = handleSecureResource(cms, req, res, resource, resourceName);
2166                    handledSecure = true;
2167                }
2168            }
2169        }
2170
2171        // return the resource read from the VFS
2172        return resource;
2173    }
2174
2175    /**
2176     * Initializes the system with the OpenCms servlet.<p>
2177     *
2178     * This is the final step that is called on the servlets "init()" method.
2179     * It registers the servlets request handler and also outputs the final
2180     * startup message. The servlet should auto-load since the <code>&lt;load-on-startup&gt;</code>
2181     * parameter is set in the 'web.xml' by default.<p>
2182     *
2183     * @param servlet the OpenCms servlet
2184     */
2185    protected void initServlet(OpenCmsServlet servlet) {
2186
2187        synchronized (LOCK) {
2188            // add the servlets request handler
2189            addRequestHandler(servlet);
2190
2191            // output the final 'startup is finished' message
2192            if (CmsLog.INIT.isInfoEnabled()) {
2193                CmsLog.INIT.info(
2194                    Messages.get().getBundle().key(
2195                        Messages.INIT_SYSTEM_RUNNING_1,
2196                        CmsStringUtil.formatRuntime(getSystemInfo().getRuntime())));
2197                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LINE_0));
2198                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
2199            }
2200        }
2201    }
2202
2203    /**
2204     * Handler for built-in AJAX services that don't belong anywhere else and don't deserve their own request handler.
2205     *
2206     * @param remainingPath the remainder of the path after /handleBuiltinService
2207     * @param req the current request
2208     * @param res the current response
2209     *
2210     * @throws ServletException if something goes wrong
2211     */
2212    protected void invokeBuiltinService(String remainingPath, HttpServletRequest req, HttpServletResponse res)
2213    throws ServletException {
2214
2215        try {
2216            CmsObject cms = initCmsObject(req, res);
2217            if (CmsGwtConstants.HANDLER_UNLOCK_PAGE.equals(remainingPath)) {
2218                CmsContainerpageService.unlockPage(cms, req, res);
2219            } else if (CmsGwtConstants.HANDLER_UPDATE_SESSION.equals(remainingPath)) {
2220                // Count this as a heartbeat request, because it's not caused by user activity
2221                boolean isHeartbeatRequest = true;
2222                OpenCms.getSessionManager().updateSessionInfo(cms, req, isHeartbeatRequest);
2223            } else if (remainingPath.startsWith(CmsGwtConstants.UNLOCK_FILE_PREFIX)) {
2224                String idStr = remainingPath.substring(CmsGwtConstants.UNLOCK_FILE_PREFIX.length());
2225                try {
2226                    cms.unlockResource(cms.readResource(new CmsUUID(idStr), CmsResourceFilter.ALL));
2227                } catch (Exception e) {
2228                    LOG.debug(e.getLocalizedMessage(), e);
2229                }
2230            }
2231        } catch (Exception e) {
2232            LOG.error(e.getLocalizedMessage(), e);
2233            throw new ServletException(e);
2234        }
2235    }
2236
2237    /**
2238     * Invokes the GWT servlet from within OpenCms.<p>
2239     *
2240     * @param serviceName the GWT PRC service class name
2241     * @param req the current servlet request
2242     * @param res the current servlet response
2243     * @param servletConfig the servlet configuration
2244     */
2245    protected void invokeGwtService(
2246        String serviceName,
2247        HttpServletRequest req,
2248        HttpServletResponse res,
2249        ServletConfig servletConfig) {
2250
2251        CmsObject cms = null;
2252        try {
2253            // instantiate CMS context
2254            cms = initCmsObject(req, res);
2255            // instantiate GWT RPC service
2256            CmsGwtService rpcService = getGwtService(serviceName, servletConfig);
2257            // check permissions
2258            rpcService.checkPermissions(cms);
2259            String rpcContextStr = req.getHeader("X-OcmsRpcContext");
2260            if (rpcContextStr == null) {
2261                rpcContextStr = "{}";
2262            }
2263            // This makes the container page uri available in all RPC calls originating from the container page editor
2264            JSONObject rpcContext = new JSONObject(rpcContextStr);
2265            String pageIdStr = rpcContext.optString(CmsGwtConstants.RpcContext.PAGE_ID);
2266            CmsResource page = null;
2267            if (CmsUUID.isValidUUID(pageIdStr)) {
2268                try {
2269                    page = cms.readResource(new CmsUUID(pageIdStr), CmsResourceFilter.IGNORE_EXPIRATION);
2270                } catch (Exception e) {
2271                    LOG.error("Page id " + pageIdStr + " is unreadable: " + e.getLocalizedMessage(), e);
2272                }
2273            }
2274            if (page != null) {
2275                cms.getRequestContext().setUri(cms.getSitePath(page));
2276                cms.getRequestContext().setAttribute(CmsRequestContext.ATTRIBUTE_ADE_CONTEXT_PATH, page.getRootPath());
2277            }
2278
2279            // set runtime variables
2280            rpcService.setCms(cms);
2281            Object lock = req.getSession();
2282            if (lock == null) {
2283                lock = new Object();
2284            }
2285            rpcService.service(req, res);
2286            m_sessionManager.updateSessionInfo(cms, req, rpcService.isBroadcastCall());
2287        } catch (CmsRoleViolationException rv) {
2288            // don't log these into the error channel
2289            LOG.debug(rv.getLocalizedMessage(), rv);
2290            // error code not set - set "unauthorized error" (401)
2291            int status = HttpServletResponse.SC_UNAUTHORIZED;
2292            res.setStatus(status);
2293            try {
2294                res.sendError(status, rv.toString());
2295            } catch (IOException e) {
2296                // can be ignored
2297                LOG.error(e.getLocalizedMessage(), e);
2298            }
2299        } catch (Throwable t) {
2300            // error code not set - set "internal server error" (500)
2301            LOG.error(t.getLocalizedMessage(), t);
2302            int status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
2303            res.setStatus(status);
2304            try {
2305                res.sendError(status, t.toString());
2306            } catch (IOException e) {
2307                // can be ignored
2308                LOG.error(e.getLocalizedMessage(), e);
2309            }
2310        }
2311    }
2312
2313    /**
2314     * This method adds an Object to the OpenCms runtime properties.
2315     * The runtime properties can be used to store Objects that are shared
2316     * in the whole system.<p>
2317     *
2318     * @param key the key to add the Object with
2319     * @param value the value of the Object to add
2320     */
2321    protected void setRuntimeProperty(Object key, Object value) {
2322
2323        m_runtimeProperties.put(key, value);
2324    }
2325
2326    /**
2327     * Displays a resource from the OpenCms by writing the result to the provided
2328     * Servlet response output stream.<p>
2329     *
2330     * @param req the current servlet request
2331     * @param res the current servlet response
2332     */
2333    protected void showResource(HttpServletRequest req, HttpServletResponse res) {
2334
2335        CmsObject cms = null;
2336        try {
2337            cms = initCmsObject(req, res);
2338            Map<String, String> logInfo = new HashMap<>();
2339            logInfo.put("cms_siteroot", cms.getRequestContext().getSiteRoot());
2340            logInfo.put("cms_project", cms.getRequestContext().getCurrentProject().getName());
2341            try (CloseableThreadContext.Instance threadContext = CloseableThreadContext.putAll(logInfo)) {
2342                LOG.info("Updating log context: " + logInfo);
2343                String uri = cms.getRequestContext().getUri();
2344                if (cms.getRequestContext().getCurrentProject().isOnlineProject()) {
2345
2346                    if (uri.startsWith(CmsWorkplace.VFS_PATH_SITES)) {
2347                        // resources within the sites folder may only be called with their site relative path
2348                        // this should prevent showing pages from other sites with their root path
2349                        throw new CmsVfsResourceNotFoundException(
2350                            org.opencms.main.Messages.get().container(
2351                                org.opencms.main.Messages.ERR_PATH_NOT_FOUND_1,
2352                                uri));
2353                    }
2354                    if (OpenCms.getStaticExportManager().isExportLink(cms, uri)) {
2355                        // if we used the request's query string for getRfsName, clients could cause an unlimited number
2356                        // of files to be exported just by varying the request parameters!
2357                        String url = m_linkManager.getOnlineLink(cms, uri);
2358                        res.sendRedirect(url);
2359                        return;
2360                    }
2361                }
2362                List<CmsSiteMatcher> currentSiteAliases = m_siteManager.getCurrentSite(cms).getAliases();
2363                CmsSiteMatcher currentSiteMatcher = cms.getRequestContext().getRequestMatcher();
2364                if (currentSiteAliases.contains(currentSiteMatcher.forDifferentScheme("http"))
2365                    || currentSiteAliases.contains(currentSiteMatcher.forDifferentScheme("https"))) {
2366                    int pos = currentSiteAliases.indexOf(currentSiteMatcher.forDifferentScheme("http"));
2367                    if (pos == -1) {
2368                        pos = currentSiteAliases.indexOf(currentSiteMatcher.forDifferentScheme("https"));
2369                    }
2370                    switch (currentSiteAliases.get(pos).getRedirectMode()) {
2371                        case none:
2372                            break;
2373                        case temporary:
2374                            res.sendRedirect(
2375                                m_siteManager.getCurrentSite(cms).getUrl() + req.getContextPath() + req.getPathInfo());
2376                            return;
2377                        case permanent:
2378                            res.setHeader(
2379                                CmsRequestUtil.HEADER_LOCATION,
2380                                m_siteManager.getCurrentSite(cms).getUrl() + req.getContextPath() + req.getPathInfo());
2381                            res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
2382                            return;
2383                        default:
2384                            break;
2385                    }
2386                }
2387
2388                // user is initialized, now deliver the requested resource
2389                CmsResource resource = initResource(cms, cms.getRequestContext().getUri(), req, res);
2390
2391                // a resource init handler may use its own authentication, but return a resource to be loaded instead of handling the complete request processing by itself.
2392                // For this case, a request context attribute is used to pass  the CmsObject that should be used for loading the resource.
2393
2394                Object alternativeCmsObject = cms.getRequestContext().removeAttribute(
2395                    I_CmsResourceInit.ATTR_ALTERNATIVE_CMS_OBJECT);
2396                CmsObject cmsForLoad = cms;
2397                if (alternativeCmsObject instanceof CmsObject) {
2398                    // we know it's not null at this point
2399                    cmsForLoad = (CmsObject)alternativeCmsObject;
2400                }
2401                if (resource != null) {
2402                    boolean forceAbsoluteLinks = checkForceAbsoluteLinks(req, cms, resource);
2403                    cms.getRequestContext().setForceAbsoluteLinks(forceAbsoluteLinks);
2404
2405                    // a file was read, go on process it
2406                    m_resourceManager.loadResource(cmsForLoad, resource, req, res);
2407                    if (cmsForLoad == cms) {
2408                        // if we used a different CmsObject, we don't want to update the session with either
2409                        // CmsObject - it's not necessary to do it for the original CmsObject, and using the alternative CmsObject
2410                        // if there is already a session would switch the session user to the one of that CmsObject. We don't
2411                        // want that, since the primary use case for the alternative CmsObject mechanism is 'stateless' authentication
2412                        // for resource init handlers.
2413                        m_sessionManager.updateSessionInfo(cms, req);
2414                    }
2415                }
2416            }
2417
2418        } catch (
2419
2420        Throwable t) {
2421            errorHandling(cms, req, res, t);
2422        }
2423    }
2424
2425    /**
2426     * Destroys this OpenCms instance, called if the servlet (or shell) is shut down.<p>
2427     */
2428    protected void shutDown() {
2429
2430        synchronized (LOCK) {
2431            if (getRunLevel() > OpenCms.RUNLEVEL_0_OFFLINE) {
2432                System.err.println(
2433                    Messages.get().getBundle().key(
2434                        Messages.LOG_SHUTDOWN_CONSOLE_NOTE_2,
2435                        getSystemInfo().getVersionNumber(),
2436                        getSystemInfo().getWebApplicationName()));
2437                if (CmsLog.INIT.isInfoEnabled()) {
2438                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
2439                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
2440                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LINE_0));
2441                    CmsLog.INIT.info(
2442                        Messages.get().getBundle().key(
2443                            Messages.INIT_SHUTDOWN_START_1,
2444                            getSystemInfo().getVersionNumber() + " [" + getSystemInfo().getVersionId() + "]"));
2445                    CmsLog.INIT.info(
2446                        Messages.get().getBundle().key(
2447                            Messages.INIT_CURRENT_RUNLEVEL_1,
2448                            Integer.valueOf(getRunLevel())));
2449                    CmsLog.INIT.info(
2450                        Messages.get().getBundle().key(
2451                            Messages.INIT_SHUTDOWN_TIME_1,
2452                            new Date(System.currentTimeMillis())));
2453                }
2454
2455                // take the system offline
2456                setRunLevel(OpenCms.RUNLEVEL_0_OFFLINE);
2457
2458                if (LOG.isDebugEnabled()) {
2459                    // log exception to see which method did call the shutdown
2460                    LOG.debug(Messages.get().getBundle().key(Messages.LOG_SHUTDOWN_TRACE_0), new Exception());
2461                }
2462
2463                for (Runnable action : m_shutdownActions) {
2464                    try {
2465                        action.run();
2466                    } catch (Exception e) {
2467                        CmsLog.INIT.error(e.getLocalizedMessage());
2468                    }
2469                }
2470
2471                for (I_CmsStartStopHandler handler : m_startStopHandlers) {
2472                    try {
2473                        handler.shutdown();
2474                    } catch (Throwable e) {
2475                        CmsLog.INIT.error(e.getLocalizedMessage(), e);
2476                    }
2477                }
2478
2479                try {
2480                    // the first thing we have to do is to wait until the current publish process finishes
2481                    if (null != m_publishEngine) {
2482                        m_publishEngine.shutDown();
2483                    }
2484                } catch (Throwable e) {
2485                    CmsLog.INIT.error(
2486                        Messages.get().getBundle().key(Messages.LOG_ERROR_PUBLISH_SHUTDOWN_1, e.getMessage()),
2487                        e);
2488                }
2489                try {
2490                    // search manager must be shut down early since there may be background indexing still ongoing
2491                    if (m_searchManager != null) {
2492                        m_searchManager.shutDown();
2493                    }
2494                } catch (Throwable e) {
2495                    CmsLog.INIT.error(
2496                        Messages.get().getBundle().key(Messages.LOG_ERROR_SEARCH_MANAGER_SHUTDOWN_1, e.getMessage()),
2497                        e);
2498                }
2499                try {
2500                    // remote shell server must be shut down early since there is a background thread ongoing that reloads from the VFS
2501                    if (m_remoteShellServer != null) {
2502                        m_remoteShellServer.shutDown();
2503                    }
2504                } catch (Throwable e) {
2505                    CmsLog.INIT.error(
2506                        Messages.get().getBundle().key(Messages.LOG_ERROR_REMOTESHELL_SHUTDOWN_1, e.getMessage()),
2507                        e);
2508                }
2509                try {
2510                    // VFS bundle manager must be shut down early since there is a background thread ongoing that reloads from the VFS
2511                    if (m_vfsBundleManager != null) {
2512                        m_vfsBundleManager.shutDown();
2513                    }
2514                } catch (Throwable e) {
2515                    CmsLog.INIT.error(
2516                        Messages.get().getBundle().key(Messages.LOG_ERROR_VFSBUNDLE_MANAGER_SHUTDOWN_1, e.getMessage()),
2517                        e);
2518                }
2519                try {
2520                    if (m_staticExportManager != null) {
2521                        m_staticExportManager.shutDown();
2522                    }
2523                } catch (Throwable e) {
2524                    CmsLog.INIT.error(
2525                        Messages.get().getBundle().key(Messages.LOG_ERROR_EXPORT_SHUTDOWN_1, e.getMessage()),
2526                        e);
2527                }
2528                try {
2529                    if (m_moduleManager != null) {
2530                        m_moduleManager.shutDown();
2531                    }
2532                } catch (Throwable e) {
2533                    CmsLog.INIT.error(
2534                        Messages.get().getBundle().key(Messages.LOG_ERROR_MODULE_SHUTDOWN_1, e.getMessage()),
2535                        e);
2536                }
2537
2538                try {
2539                    if (m_executor != null) {
2540                        m_executor.shutdown();
2541                        m_executor.awaitTermination(30, TimeUnit.SECONDS);
2542                    }
2543                } catch (Throwable e) {
2544                    CmsLog.INIT.error(
2545                        Messages.get().getBundle().key(Messages.LOG_ERROR_MODULE_SHUTDOWN_1, e.getMessage()),
2546                        e);
2547                }
2548
2549                try {
2550                    if (m_scheduleManager != null) {
2551                        m_scheduleManager.shutDown();
2552                    }
2553                } catch (Throwable e) {
2554                    CmsLog.INIT.error(
2555                        Messages.get().getBundle().key(Messages.LOG_ERROR_SCHEDULE_SHUTDOWN_1, e.getMessage()),
2556                        e);
2557                }
2558                try {
2559                    if (m_resourceManager != null) {
2560                        m_resourceManager.shutDown();
2561                    }
2562                } catch (Throwable e) {
2563                    CmsLog.INIT.error(
2564                        Messages.get().getBundle().key(Messages.LOG_ERROR_RESOURCE_SHUTDOWN_1, e.getMessage()),
2565                        e);
2566                }
2567
2568                try {
2569                    if (m_repositoryManager != null) {
2570                        m_repositoryManager.shutDown();
2571                    }
2572                } catch (Throwable e) {
2573                    CmsLog.INIT.error(e.getLocalizedMessage(), e);
2574                }
2575
2576                try {
2577                    // has to be stopped before the security manager, since this thread uses it
2578                    if (m_threadStore != null) {
2579                        m_threadStore.shutDown();
2580                    }
2581                } catch (Throwable e) {
2582                    CmsLog.INIT.error(
2583                        Messages.get().getBundle().key(Messages.LOG_ERROR_THREAD_SHUTDOWN_1, e.getMessage()),
2584                        e);
2585                }
2586                try {
2587                    if (m_securityManager != null) {
2588                        m_securityManager.destroy();
2589                    }
2590                } catch (Throwable e) {
2591                    CmsLog.INIT.error(
2592                        Messages.get().getBundle().key(Messages.LOG_ERROR_SECURITY_SHUTDOWN_1, e.getMessage()),
2593                        e);
2594                }
2595                try {
2596                    if (m_sessionManager != null) {
2597                        m_sessionManager.shutdown();
2598                    }
2599                } catch (Throwable e) {
2600                    CmsLog.INIT.error(
2601                        Messages.get().getBundle().key(Messages.LOG_ERROR_SESSION_MANAGER_SHUTDOWN_1, e.getMessage()),
2602                        e);
2603                }
2604                try {
2605                    if (m_memoryMonitor != null) {
2606                        m_memoryMonitor.shutdown();
2607                    }
2608                } catch (Throwable e) {
2609                    CmsLog.INIT.error(
2610                        Messages.get().getBundle().key(Messages.LOG_ERROR_MEMORY_MONITOR_SHUTDOWN_1, e.getMessage()),
2611                        e);
2612                }
2613                try {
2614                    if (m_adeManager != null) {
2615                        m_adeManager.shutdown();
2616                    }
2617                } catch (Throwable e) {
2618                    CmsLog.INIT.error(
2619                        Messages.get().getBundle().key(Messages.LOG_ERROR_ADE_MANAGER_SHUTDOWN_1, e.getMessage()),
2620                        e);
2621                }
2622
2623                String runtime = CmsStringUtil.formatRuntime(getSystemInfo().getRuntime());
2624                if (CmsLog.INIT.isInfoEnabled()) {
2625                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_OPENCMS_STOPPED_1, runtime));
2626                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LINE_0));
2627                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
2628                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DOT_0));
2629                }
2630                System.err.println(Messages.get().getBundle().key(Messages.LOG_CONSOLE_TOTAL_RUNTIME_1, runtime));
2631
2632            }
2633            try {
2634                final javax.management.MBeanServer mbs = java.lang.management.ManagementFactory.getPlatformMBeanServer();
2635                final javax.management.ObjectName mxbeanName = new javax.management.ObjectName(
2636                    "org.opencms.mx:type=CmsDiagnosticsMXBean");
2637                if (mbs.isRegistered(mxbeanName)) {
2638                    mbs.unregisterMBean(mxbeanName);
2639                }
2640            } catch (Throwable e) {
2641                CmsLog.INIT.error(e.getLocalizedMessage(), e);
2642            }
2643            m_instance = null;
2644        }
2645    }
2646
2647    /**
2648     * This method updates the request context information.<p>
2649     *
2650     * The update information is:<br>
2651     * <ul>
2652     *   <li>Requested Url</li>
2653     *   <li>Locale</li>
2654     *   <li>Encoding</li>
2655     *   <li>Remote Address</li>
2656     *   <li>Request Time</li>
2657     * </ul>
2658     *
2659     * @param request the current request
2660     * @param cms the cms object to update the request context for
2661     *
2662     * @return a new updated cms context
2663     *
2664     * @throws CmsException if something goes wrong
2665     */
2666    protected CmsObject updateContext(HttpServletRequest request, CmsObject cms) throws CmsException {
2667
2668        // get the right site for the request
2669        String siteRoot = null;
2670        boolean isWorkplace = cms.getRequestContext().getUri().startsWith("/system/workplace/")
2671            || request.getRequestURI().startsWith(OpenCms.getSystemInfo().getWorkplaceContext());
2672        if (isWorkplace && getRoleManager().hasRole(cms, CmsRole.ELEMENT_AUTHOR)) {
2673            // keep the site root for workplace requests
2674            siteRoot = cms.getRequestContext().getSiteRoot();
2675        } else {
2676            CmsSite site = OpenCms.getSiteManager().matchRequest(request);
2677            siteRoot = site.getSiteRoot();
2678        }
2679        return initCmsObject(
2680            request,
2681            cms.getRequestContext().getCurrentUser(),
2682            siteRoot,
2683            cms.getRequestContext().getCurrentProject().getUuid(),
2684            cms.getRequestContext().getOuFqn());
2685    }
2686
2687    /**
2688     * Upgrades to runlevel {@link OpenCms#RUNLEVEL_3_SHELL_ACCESS},
2689     * this is shell access to the database but no Servlet context.<p>
2690     *
2691     * To upgrade the runlevel, the system must be in runlevel {@link OpenCms#RUNLEVEL_1_CORE_OBJECT},
2692     * otherwise an exception is thrown.<p>
2693     *
2694     * @param configuration the configuration
2695     * @throws CmsInitException in case OpenCms can not be initialized
2696     * @return the initialized OpenCmsCore
2697     */
2698    protected OpenCmsCore upgradeRunlevel(CmsParameterConfiguration configuration) throws CmsInitException {
2699
2700        synchronized (LOCK) {
2701            if ((m_instance != null) && (getRunLevel() >= OpenCms.RUNLEVEL_2_INITIALIZING)) {
2702                // instance already in runlevel 3 or 4
2703                return m_instance;
2704            }
2705            if (getRunLevel() != OpenCms.RUNLEVEL_1_CORE_OBJECT) {
2706                CmsLog.INIT.error(
2707                    Messages.get().getBundle().key(
2708                        Messages.LOG_WRONG_INIT_SEQUENCE_2,
2709                        Integer.valueOf(3),
2710                        Integer.valueOf(getRunLevel())));
2711                return m_instance;
2712            }
2713
2714            // set the runlevel to "initializing OpenCms"
2715            setRunLevel(OpenCms.RUNLEVEL_2_INITIALIZING);
2716            // initialize the configuration
2717            m_instance.initConfiguration(configuration);
2718            // upgrade the runlevel - OpenCms shell is available
2719            setRunLevel(OpenCms.RUNLEVEL_3_SHELL_ACCESS);
2720
2721            afterUpgradeRunlevel();
2722
2723            return m_instance;
2724        }
2725    }
2726
2727    /**
2728     * Upgrades to runlevel {@link OpenCms#RUNLEVEL_4_SERVLET_ACCESS},
2729     * this is the final runlevel with an initialized database and Servlet context.<p>
2730     *
2731     * To upgrade the runlevel, the system must be in runlevel {@link OpenCms#RUNLEVEL_1_CORE_OBJECT},
2732     * otherwise an exception is thrown.<p>
2733     *
2734     * @param context the current servlet context
2735     * @throws CmsInitException in case OpenCms can not be initialized
2736     * @return the initialized OpenCmsCore
2737     */
2738    protected OpenCmsCore upgradeRunlevel(ServletContext context) throws CmsInitException {
2739
2740        synchronized (LOCK) {
2741            if ((m_instance != null) && (getRunLevel() >= OpenCms.RUNLEVEL_4_SERVLET_ACCESS)) {
2742                // instance already in runlevel 5 or 6
2743                return m_instance;
2744            }
2745            if (getRunLevel() != OpenCms.RUNLEVEL_1_CORE_OBJECT) {
2746                CmsLog.INIT.error(
2747                    Messages.get().getBundle().key(
2748                        Messages.LOG_WRONG_INIT_SEQUENCE_2,
2749                        Integer.valueOf(4),
2750                        Integer.valueOf(getRunLevel())));
2751                return m_instance;
2752            }
2753
2754            // set the runlevel to "initializing OpenCms"
2755            setRunLevel(OpenCms.RUNLEVEL_2_INITIALIZING);
2756            // initialize the servlet context
2757            m_instance.initContext(context);
2758            // initialization successfully finished - OpenCms servlet is online
2759            // the runlevel will change from 2 directly to 4, this is on purpose
2760            setRunLevel(OpenCms.RUNLEVEL_4_SERVLET_ACCESS);
2761
2762            afterUpgradeRunlevel();
2763            return m_instance;
2764        }
2765    }
2766
2767    /**
2768     * Writes the XML configuration for the provided configuration class.<p>
2769     *
2770     * @param clazz the configuration class to write the XML for
2771     */
2772    protected void writeConfiguration(Class<?> clazz) {
2773
2774        // exception handling is provided here to ensure identical log messages
2775        try {
2776            m_configurationManager.writeConfiguration(clazz);
2777        } catch (IOException e) {
2778            CmsLog.getLog(CmsConfigurationManager.class).error(
2779                Messages.get().getBundle().key(Messages.LOG_ERROR_WRITING_CONFIG_1, clazz.getName()),
2780                e);
2781        } catch (CmsConfigurationException e) {
2782            CmsLog.getLog(CmsConfigurationManager.class).error(
2783                Messages.get().getBundle().key(Messages.LOG_ERROR_WRITING_CONFIG_1, clazz.getName()),
2784                e);
2785        }
2786    }
2787
2788    /**
2789     * Adds the given set of export points to the list of all configured export points.<p>
2790     *
2791     * @param exportPoints the export points to add
2792     */
2793    private void addExportPoints(Set<CmsExportPoint> exportPoints) {
2794
2795        // create a new immutable set of export points
2796        HashSet<CmsExportPoint> newSet = new HashSet<CmsExportPoint>(m_exportPoints.size() + exportPoints.size());
2797        newSet.addAll(exportPoints);
2798        newSet.addAll(m_exportPoints);
2799        m_exportPoints = Collections.unmodifiableSet(newSet);
2800    }
2801
2802    /**
2803     * Finishes the startup sequence after last runlevel upgrade.<p>
2804     */
2805    private void afterUpgradeRunlevel() {
2806
2807        try {
2808            // read the persistent locks
2809            m_instance.m_securityManager.readLocks();
2810        } catch (CmsException e) {
2811            if (LOG.isErrorEnabled()) {
2812                LOG.error(
2813                    org.opencms.lock.Messages.get().getBundle().key(org.opencms.lock.Messages.ERR_READ_LOCKS_0),
2814                    e);
2815            }
2816        }
2817
2818        if (OpenCms.getRunLevel() == OpenCms.RUNLEVEL_4_SERVLET_ACCESS) {
2819            // only init ADE manager in case of servlet initialization, it won't be needed in case of shell access
2820            CmsThreadStatsTreeProfilingHandler stats = new CmsThreadStatsTreeProfilingHandler();
2821            try {
2822                CmsDefaultProfilingHandler.INSTANCE.addHandler(stats);
2823                m_adeManager.initialize();
2824            } finally {
2825                CmsDefaultProfilingHandler.INSTANCE.removeHandler(stats);
2826                if (stats.hasData()) {
2827                    String adeInitData = stats.dump();
2828                    String prefix = String.format("%010X", Long.valueOf(System.currentTimeMillis() / 1000));
2829                    String path = OpenCms.getSystemInfo().getAbsoluteRfsPathRelativeToWebInf(
2830                        "logs/" + prefix + "_startup-ade-driver-report.xml");
2831                    try (FileOutputStream out = new FileOutputStream(path)) {
2832                        out.write(adeInitData.getBytes("UTF-8"));
2833                    } catch (Exception e) {
2834                        LOG.error(
2835                            "Could not write ADE init profiling data to file, writing to log instead: "
2836                                + e.getLocalizedMessage(),
2837                            e);
2838                        LOG.error(adeInitData);
2839                    }
2840                }
2841            }
2842
2843            try {
2844                // get an Admin cms context object with site root set to "/"
2845                CmsObject adminCms = initCmsObject(
2846                    null,
2847                    null,
2848                    getDefaultUsers().getUserAdmin(),
2849                    (String)null,
2850                    (String)null);
2851                OpenCms.getSearchManager().initSpellcheckIndex(adminCms);
2852            } catch (CmsException e) {
2853                throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_ADMINCMS_0), e);
2854            }
2855        }
2856
2857        try {
2858            m_folderSizeTrackerFuture = m_executor.submit(
2859                () -> new CmsFolderSizeTracker(m_configAdminCms, false).initialize());
2860        } catch (Exception e) {
2861            LOG.error(e.getLocalizedMessage(), e);
2862        }
2863
2864        try {
2865            m_onlineFolderSizeTrackerFuture = m_executor.submit(
2866                () -> new CmsFolderSizeTracker(m_configAdminCms, true).initialize());
2867        } catch (Exception e) {
2868            LOG.error(e.getLocalizedMessage(), e);
2869        }
2870
2871        // everything is initialized, now start publishing
2872        m_publishManager.startPublishing();
2873
2874        for (I_CmsStartStopHandler handler : ServiceLoader.load(I_CmsStartStopHandler.class)) {
2875            m_startStopHandlers.add(handler);
2876        }
2877
2878        for (I_CmsStartStopHandler handler : m_startStopHandlers) {
2879            try {
2880                handler.startup(m_configAdminCms);
2881            } catch (Exception e) {
2882                LOG.error(e.getLocalizedMessage(), e);
2883            }
2884        }
2885
2886        try {
2887            CmsDiagnosticsMXBean.register(m_configAdminCms);
2888        } catch (Throwable e) {
2889            CmsLog.INIT.error(e.getLocalizedMessage(), e);
2890        }
2891
2892    }
2893
2894    /**
2895     * Checks whether 'force absolute links' mode should be enabled in request context.
2896     *
2897     * @param req the current request
2898     * @param cms the CMS context
2899     * @param resource the resource to load
2900     *
2901     * @return true if 'force absolute links' mode should be enabled
2902     */
2903    private boolean checkForceAbsoluteLinks(HttpServletRequest req, CmsObject cms, CmsResource resource) {
2904
2905        try {
2906            boolean forceAbsoluteLinks = Boolean.parseBoolean(req.getParameter(PARAM_FORCE_ABSOLUTE_LINKS));
2907            if (forceAbsoluteLinks) {
2908                // only need to read the property if the request parameter is actually set
2909                CmsProperty enableForceAbsoluteProp = cms.readPropertyObject(
2910                    resource,
2911                    CmsPropertyDefinition.PROPERTY_LINKS_FORCEABSOLUTE_ENABLED,
2912                    true);
2913                return Boolean.parseBoolean(enableForceAbsoluteProp.getValue());
2914            } else {
2915                return false;
2916            }
2917        } catch (Exception e) {
2918            LOG.warn(e.getLocalizedMessage(), e);
2919            return false;
2920        }
2921    }
2922
2923    /**
2924     * This method performs the error handling for OpenCms.<p>
2925     *
2926     * @param cms the current cms context, might be null !
2927     * @param req the client request
2928     * @param res the client response
2929     * @param t the exception that occurred
2930     */
2931    private void errorHandling(CmsObject cms, HttpServletRequest req, HttpServletResponse res, Throwable t) {
2932
2933        // remove the controller attribute from the request
2934        CmsFlexController.removeController(req);
2935        req.removeAttribute(CmsJspStandardContextBean.ATTRIBUTE_NAME);
2936
2937        boolean canWrite = (!res.isCommitted() && !res.containsHeader("Location"));
2938        int status = -1;
2939        boolean isGuest = true;
2940
2941        if (t instanceof ServletException) {
2942            ServletException s = (ServletException)t;
2943            if (s.getRootCause() != null) {
2944                t = s.getRootCause();
2945            }
2946            if (CmsJspLoader.isJasperCompilerException(t)) {
2947                LOG.error(t.getLocalizedMessage());
2948            } else {
2949                LOG.error(t.getLocalizedMessage(), t);
2950            }
2951        } else if (t instanceof CmsSecurityException) {
2952            LOG.warn(t.getLocalizedMessage() + " rendering URL " + req.getRequestURL(), t);
2953            // access error - display login dialog
2954            if (canWrite) {
2955                try {
2956                    m_authorizationHandler.requestAuthorization(req, res, getLoginFormURL(req, res));
2957                } catch (IOException ioe) {
2958                    LOG.debug("Error calling authorization handler.", ioe);
2959                }
2960                return;
2961            }
2962        } else if (t instanceof CmsDbEntryNotFoundException) {
2963            LOG.warn(t.getLocalizedMessage() + " rendering URL " + req.getRequestURL(), t);
2964            // user or group does not exist
2965            status = HttpServletResponse.SC_SERVICE_UNAVAILABLE;
2966            isGuest = false;
2967        } else if (t instanceof CmsVfsResourceNotFoundException) {
2968            LOG.warn(t.getLocalizedMessage() + " rendering URL " + req.getRequestURL(), t);
2969            // file not found - display 404 error.
2970            status = HttpServletResponse.SC_NOT_FOUND;
2971        } else if (t instanceof CmsException) {
2972            LOG.error(t.getLocalizedMessage() + " rendering URL " + req.getRequestURL(), t);
2973            if (t.getCause() != null) {
2974                t = t.getCause();
2975            }
2976        } else if (t.getClass().getName().equals("org.apache.catalina.connector.ClientAbortException")) {
2977            // only log to debug channel any exceptions caused by a client abort - this is tomcat specific
2978            LOG.debug(t.getLocalizedMessage() + " rendering URL " + req.getRequestURL(), t);
2979        } else {
2980            LOG.error(t.getLocalizedMessage() + " rendering URL " + req.getRequestURL(), t);
2981        }
2982
2983        if (status < 1) {
2984            // error code not set - set "internal server error" (500)
2985            status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
2986        }
2987        res.setStatus(status);
2988
2989        try {
2990            if ((cms != null) && (cms.getRequestContext().getCurrentUser() != null)) {
2991                isGuest = isGuest
2992                    && (cms.getRequestContext().getCurrentUser().isGuestUser()
2993                        || cms.userInGroup(
2994                            cms.getRequestContext().getCurrentUser().getName(),
2995                            OpenCms.getDefaultUsers().getGroupGuests()));
2996            }
2997        } catch (CmsException e) {
2998            // result is false
2999            LOG.error(e.getLocalizedMessage(), e);
3000        }
3001
3002        if (canWrite) {
3003            res.setContentType("text/html");
3004            CmsRequestUtil.setNoCacheHeaders(res);
3005            if ((status != 404)
3006                && !isGuest
3007                && (cms != null)
3008                && (!CmsJsonPartFilter.isJsonRequest(req))
3009                && !cms.getRequestContext().getCurrentProject().isOnlineProject()) {
3010                try {
3011                    res.setStatus(HttpServletResponse.SC_OK);
3012                    res.getWriter().print(CmsErrorUI.getBootstrapPage(cms, t, req));
3013                } catch (IOException e) {
3014                    // can be ignored
3015                    LOG.error(e.getLocalizedMessage(), e);
3016                }
3017            } else {
3018                try {
3019                    res.sendError(status, t.toString());
3020                } catch (IOException e) {
3021                    // can be ignored
3022                    LOG.error(e.getLocalizedMessage(), e);
3023                }
3024            }
3025        }
3026    }
3027
3028    /**
3029     *
3030     *
3031     * @param serviceName the GWT PRC service class name
3032     * @param servletConfig the servlet configuration
3033     *
3034     * @return the GWT service instance
3035     *
3036     * @throws Throwable if something goes wrong
3037     */
3038    private synchronized CmsGwtService getGwtService(String serviceName, ServletConfig servletConfig) throws Throwable {
3039
3040        CmsGwtServiceContext2 context = m_gwtServiceContexts.get(serviceName);
3041        if (context == null) {
3042            context = new CmsGwtServiceContext2(serviceName);
3043            m_gwtServiceContexts.put(serviceName, context);
3044        }
3045        CmsGwtService gwtService = (CmsGwtService)Class.forName(serviceName).getDeclaredConstructor().newInstance();
3046        gwtService.init(servletConfig);
3047        gwtService.setContext(context);
3048        return gwtService;
3049    }
3050
3051    /**
3052     * Reads the login form which should be used for authenticating the current request.<p>
3053     *
3054     * @param req current request
3055     * @param res current response
3056     *
3057     * @return the URL of the login form or <code>null</code> if not set
3058     *
3059     * @throws IOException in case of IO errors
3060     */
3061    private String getLoginFormURL(HttpServletRequest req, HttpServletResponse res) throws IOException {
3062
3063        CmsHttpAuthenticationSettings httpAuthenticationSettings = OpenCms.getSystemInfo().getHttpAuthenticationSettings();
3064        String loginFormURL = null;
3065
3066        // this will create an admin user with the "right" site root already set
3067        CmsObject adminCms;
3068        try {
3069            adminCms = initCmsObject(req, res, OpenCms.getDefaultUsers().getUserAdmin(), null, null);
3070        } catch (CmsException e) {
3071            // this should never happen, if it does we can't continue
3072            throw new IOException(
3073                Messages.get().getBundle().key(
3074                    Messages.ERR_INVALID_INIT_USER_2,
3075                    OpenCms.getDefaultUsers().getUserAdmin(),
3076
3077                    null),
3078                e);
3079        }
3080        // get the requested resource
3081        String path = adminCms.getRequestContext().getUri();
3082        CmsProperty propertyLoginForm = null;
3083        try {
3084            propertyLoginForm = adminCms.readPropertyObject(path, CmsPropertyDefinition.PROPERTY_LOGIN_FORM, true);
3085        } catch (Throwable t) {
3086            if (t instanceof CmsVfsResourceNotFoundException) {
3087                // if we can't read the property from the path, try to use the resource init handlers to find the
3088                // resource to read it from
3089                CmsResource alternativeResource = null;
3090                try {
3091
3092                    try {
3093                        // use null as the response to avoid side effects like redirects, etc.
3094                        alternativeResource = initResource(adminCms, path, req, null);
3095                    } catch (Exception e) {
3096                        LOG.warn(e.getLocalizedMessage(), e);
3097                    }
3098                    if (alternativeResource != null) {
3099                        propertyLoginForm = adminCms.readPropertyObject(
3100                            adminCms.getSitePath(alternativeResource),
3101                            CmsPropertyDefinition.PROPERTY_LOGIN_FORM,
3102                            true);
3103                    }
3104                } catch (Exception e) {
3105                    LOG.error(e.getLocalizedMessage(), e);
3106                }
3107            }
3108
3109            if (propertyLoginForm == null) {
3110                if (LOG.isWarnEnabled()) {
3111                    LOG.warn(
3112                        Messages.get().getBundle().key(
3113                            Messages.LOG_ERROR_READING_AUTH_PROP_2,
3114                            CmsPropertyDefinition.PROPERTY_LOGIN_FORM,
3115                            path),
3116                        t);
3117                }
3118
3119            }
3120        }
3121
3122        String params = null;
3123        if ((propertyLoginForm != null)
3124            && (propertyLoginForm != CmsProperty.getNullProperty())
3125            && CmsStringUtil.isNotEmpty(propertyLoginForm.getValue())) {
3126            // login form property value was found
3127            // build a redirect URL using the value of the property
3128            // "__loginform" is a dummy request parameter that could be used in a JSP template to trigger
3129            // if the template should display a login formular or not
3130            loginFormURL = propertyLoginForm.getValue();
3131            params = "__loginform=true";
3132        } else if (!httpAuthenticationSettings.useBrowserBasedHttpAuthentication()
3133            && CmsStringUtil.isNotEmpty(httpAuthenticationSettings.getFormBasedHttpAuthenticationUri())) {
3134            // login form property value not set, but form login set in configuration
3135            // build a redirect URL to the default login form URI configured in opencms.properties
3136            loginFormURL = httpAuthenticationSettings.getFormBasedHttpAuthenticationUri();
3137        }
3138
3139        String callbackURL = CmsRequestUtil.encodeParamsWithUri(path, req);
3140        if (loginFormURL != null) {
3141            if (!loginFormURL.startsWith("http")) {
3142                loginFormURL = m_linkManager.substituteLink(adminCms, loginFormURL, null, true);
3143            } else {
3144                callbackURL = m_linkManager.getServerLink(adminCms, path);
3145                callbackURL = CmsRequestUtil.encodeParamsWithUri(callbackURL, req);
3146            }
3147        }
3148
3149        return m_authorizationHandler.getLoginFormURL(loginFormURL, params, callbackURL);
3150    }
3151
3152    /**
3153     * If we are in the Online project, check if the given resource is marked as secure, and handle it according to the secure server configuration.<p>
3154     *
3155     * @param cms the current CMS context
3156     * @param req the current request
3157     * @param res the current response
3158     * @param resource the resource to check
3159     * @param resourceName the resource path from the request
3160     *
3161     * @return the resource to replace the original resource
3162     *
3163     * @throws CmsException if something goes wrong
3164     * @throws CmsVfsResourceNotFoundException if the resource could not be found
3165     */
3166    private CmsResource handleSecureResource(
3167        CmsObject cms,
3168        HttpServletRequest req,
3169        HttpServletResponse res,
3170        CmsResource resource,
3171        String resourceName)
3172    throws CmsException, CmsVfsResourceNotFoundException {
3173
3174        // check online project
3175        if (cms.getRequestContext().getCurrentProject().isOnlineProject() && (res != null)) {
3176            boolean secure = false;
3177            try {
3178                // check if resource is secure
3179                secure = Boolean.valueOf(
3180                    cms.readPropertyObject(
3181                        cms.getSitePath(resource),
3182                        CmsPropertyDefinition.PROPERTY_SECURE,
3183                        true).getValue()).booleanValue();
3184            } catch (CmsVfsResourceNotFoundException e) {
3185                LOG.warn(e.getLocalizedMessage(), e);
3186            } catch (CmsException e) {
3187                LOG.error(e.getLocalizedMessage(), e);
3188            }
3189            if (secure) {
3190                CmsResource resource1 = resource;
3191                // resource is secure, check site config
3192                CmsSite site = OpenCms.getSiteManager().getCurrentSite(cms);
3193                // check the secure url
3194                String secureUrl = null;
3195                try {
3196                    secureUrl = site.getSecureUrl();
3197                } catch (Exception e) {
3198                    LOG.error(
3199                        Messages.get().getBundle().key(Messages.ERR_SECURE_SITE_NOT_CONFIGURED_1, resourceName),
3200                        e);
3201                    throw new CmsException(
3202                        Messages.get().container(Messages.ERR_SECURE_SITE_NOT_CONFIGURED_1, resourceName),
3203                        e);
3204                }
3205                boolean usingSec = true;
3206                if (req != null) {
3207                    usingSec = req.getRequestURL().toString().toUpperCase().startsWith(secureUrl.toUpperCase());
3208                }
3209                if (site.isExclusiveUrl() && !usingSec) {
3210                    resource1 = null;
3211                    // secure resource without secure protocol, check error config
3212                    if (site.isExclusiveError()) {
3213                        // trigger 404 error
3214                        throw new CmsVfsResourceNotFoundException(
3215                            Messages.get().container(Messages.ERR_REQUEST_SECURE_RESOURCE_0));
3216                    } else {
3217                        // redirect
3218                        String target = OpenCms.getLinkManager().getOnlineLink(cms, resourceName);
3219                        if (!target.toLowerCase().startsWith(secureUrl.toLowerCase())) {
3220                            Optional<String> targetWithReplacedHost = CmsStringUtil.replacePrefix(
3221                                target,
3222                                site.getSiteMatcher().getUrl(),
3223                                secureUrl,
3224                                true);
3225                            if (targetWithReplacedHost.isPresent()) {
3226                                target = targetWithReplacedHost.get();
3227                            }
3228                            if (!target.toLowerCase().startsWith(secureUrl.toLowerCase())) {
3229                                LOG.warn("Failed to generate secure URL for " + target + ", site = " + site);
3230                            }
3231                        }
3232
3233                        try {
3234                            if (site.usesPermanentRedirects()) {
3235                                res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
3236                                res.setHeader("Location", target);
3237                            } else {
3238                                res.sendRedirect(target);
3239                            }
3240                        } catch (Exception e) {
3241                            // ignore, but should never happen
3242                            LOG.error("Error sending secure resource redirect.", e);
3243                        }
3244                    }
3245                }
3246                resource = resource1;
3247            }
3248
3249        }
3250        return resource;
3251    }
3252
3253    /**
3254     * Initializes a CmsObject with the given context information.<p>
3255     *
3256     * @param contextInfo the information for the CmsObject context to create
3257     *
3258     * @return the initialized CmsObject
3259     *
3260     * @throws CmsException if something goes wrong
3261     */
3262    private CmsObject initCmsObject(CmsContextInfo contextInfo) throws CmsException {
3263
3264        CmsUser user = contextInfo.getUser();
3265        if (user == null) {
3266            user = m_securityManager.readUser(null, contextInfo.getUserName());
3267        }
3268
3269        CmsProject project = contextInfo.getProject();
3270        if (project == null) {
3271            project = m_securityManager.readProject(contextInfo.getProjectName());
3272        }
3273
3274        // first create the request context
3275        CmsRequestContext context = new CmsRequestContext(
3276            user,
3277            project,
3278            contextInfo.getRequestedUri(),
3279            contextInfo.getRequestMatcher(),
3280            contextInfo.getSiteRoot(),
3281            contextInfo.isSecureRequest(),
3282            contextInfo.getLocale(),
3283            contextInfo.getEncoding(),
3284            contextInfo.getRemoteAddr(),
3285            contextInfo.getRequestTime(),
3286            m_resourceManager.getFolderTranslator(),
3287            m_resourceManager.getFileTranslator(),
3288            contextInfo.getOuFqn(),
3289            contextInfo.isForceAbsoluteLinks());
3290        context.setDetailResource(contextInfo.getDetailResource());
3291
3292        // now initialize and return the CmsObject
3293        return new CmsObject(m_securityManager, context);
3294    }
3295
3296    /**
3297     * Initializes a {@link CmsObject} with the given users information.<p>
3298     *
3299     * @param request the current http request (or <code>null</code>)
3300     * @param user the initialized user
3301     * @param siteRoot the users current site
3302     * @param projectId the id of the users current project
3303     * @param ouFqn the organizational unit
3304     *
3305     * @return the initialized CmsObject
3306     *
3307     * @throws CmsException in case something goes wrong
3308     */
3309    private CmsObject initCmsObject(
3310        HttpServletRequest request,
3311        CmsUser user,
3312        String siteRoot,
3313        CmsUUID projectId,
3314        String ouFqn)
3315    throws CmsException {
3316
3317        CmsProject project = null;
3318        try {
3319            project = m_securityManager.readProject(projectId);
3320        } catch (CmsDbEntryNotFoundException e) {
3321            // project not found, switch to online project
3322            project = m_securityManager.readProject(CmsProject.ONLINE_PROJECT_ID);
3323            LOG.debug("Project '" + projectId + "' was not found, switch to online project.", e);
3324        }
3325
3326        // get requested resource uri and remote IP address, as well as time for "time warp" browsing
3327        String requestedResource = null;
3328        Long requestTimeAttr = null;
3329        String remoteAddr;
3330        CmsSiteMatcher requestMatcher;
3331
3332        boolean isSecureRequest = false;
3333        if (request != null) {
3334            // get path info from request
3335            requestedResource = getPathInfo(request);
3336
3337            // check for special header for remote address
3338            remoteAddr = request.getHeader(CmsRequestUtil.HEADER_X_FORWARDED_FOR);
3339            if (remoteAddr == null) {
3340                // if header is not available, use default remote address
3341                remoteAddr = request.getRemoteAddr();
3342            }
3343
3344            // check for special "time warp" browsing
3345            HttpSession session = request.getSession(false);
3346            if (session != null) {
3347                // no new session must be created here
3348                requestTimeAttr = (Long)session.getAttribute(CmsContextInfo.ATTRIBUTE_REQUEST_TIME);
3349            }
3350            isSecureRequest = OpenCms.getSiteManager().usesSecureSite(request);
3351
3352            // create the request matcher
3353            requestMatcher = new CmsSiteMatcher(request.getRequestURL().toString());
3354
3355        } else {
3356            // if no request is available, the IP is always set to localhost
3357            remoteAddr = CmsContextInfo.LOCALHOST;
3358            // also the request matcher is always the workplace server
3359            requestMatcher = OpenCms.getSiteManager().getWorkplaceSiteMatcher();
3360        }
3361        if (requestedResource == null) {
3362            // path info can still be null
3363            requestedResource = "/";
3364        }
3365
3366        // calculate the request time
3367        long requestTime;
3368        if (requestTimeAttr == null) {
3369            requestTime = System.currentTimeMillis();
3370        } else {
3371            requestTime = requestTimeAttr.longValue();
3372        }
3373
3374        // get locale and encoding
3375        CmsI18nInfo i18nInfo;
3376        if (m_localeManager.isInitialized()) {
3377            // locale manager is initialized
3378            // resolve locale and encoding
3379            if ((request != null)
3380                && (requestedResource.endsWith(OpenCmsServlet.HANDLE_GWT) || isWorkplaceServletRequest(request))) {
3381                // GWT RPC or workplace servlet call, always keep the request encoding and use the default locale
3382                i18nInfo = new CmsI18nInfo(CmsLocaleManager.getDefaultLocale(), request.getCharacterEncoding());
3383            } else {
3384                String resourceName;
3385                if (requestedResource.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)) {
3386                    // add site root only if resource name does not start with "/system"
3387                    resourceName = requestedResource;
3388                } else if (OpenCms.getSiteManager().startsWithShared(requestedResource)) {
3389                    resourceName = requestedResource;
3390                } else {
3391                    resourceName = siteRoot.concat(requestedResource);
3392                }
3393                i18nInfo = m_localeManager.getI18nInfo(request, user, project, resourceName);
3394            }
3395        } else {
3396            // locale manager not initialized, this will be true _only_ during system startup
3397            // the values set does not matter, no locale information form VFS is used on system startup
3398            // this is just to protect against null pointer exceptions
3399            i18nInfo = new CmsI18nInfo(Locale.ENGLISH, getSystemInfo().getDefaultEncoding());
3400        }
3401
3402        // decode the requested resource, always using UTF-8
3403        requestedResource = CmsEncoder.decode(requestedResource);
3404
3405        // in case the current site could be configured for single tree localization, if so, remove the locale prefix if present
3406        CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(siteRoot);
3407        if ((site != null) && CmsSite.LocalizationMode.singleTree.equals(site.getLocalizationMode())) {
3408            Locale locale = CmsSingleTreeLocaleHandler.getLocaleFromPath(requestedResource);
3409            if (locale != null) {
3410                requestedResource = requestedResource.substring(
3411                    requestedResource.indexOf(locale.toString()) + locale.toString().length());
3412            }
3413        }
3414
3415        // initialize the context info
3416        CmsContextInfo contextInfo = new CmsContextInfo(
3417            user,
3418            project,
3419            requestedResource,
3420            requestMatcher,
3421            siteRoot,
3422            isSecureRequest,
3423            i18nInfo.getLocale(),
3424            i18nInfo.getEncoding(),
3425            remoteAddr,
3426            requestTime,
3427            ouFqn,
3428            false);
3429
3430        // now generate and return the CmsObject
3431        return initCmsObject(contextInfo);
3432    }
3433
3434    /**
3435     * Handles the user authentification for each request sent to OpenCms.<p>
3436     *
3437     * User authentification is done in three steps:
3438     * <ol>
3439     * <li>Session authentification: OpenCms stores information of all authentificated
3440     *      users in an internal storage based on the users session.</li>
3441     * <li>Authorization handler authentification: If the session authentification fails,
3442     *      the current configured authorization handler is called.</li>
3443     * <li>Default user: When both authentification methods fail, the user is set to
3444     *      the default (Guest) user.</li>
3445     * </ol>
3446     *
3447     * @param req the current http request
3448     * @param res the current http response
3449     *
3450     * @return the initialized cms context
3451     *
3452     * @throws IOException if user authentication fails
3453     * @throws CmsException in case something goes wrong
3454     */
3455    private CmsObject initCmsObject(HttpServletRequest req, HttpServletResponse res) throws IOException, CmsException {
3456
3457        return initCmsObject(req, res, true);
3458    }
3459
3460    /**
3461     * Returns an initialized CmsObject with the given users permissions.<p>
3462     *
3463     * In case the password is <code>null</code>, or the user is the <code>Guest</code> user,
3464     * no password check is done. Therefore you can initialize all users without knowing their passwords
3465     * by just supplying <code>null</code> as password. This is intended only for
3466     * internal operation in the core.<p>
3467     *
3468     * @param req the current request
3469     * @param res the current response
3470     * @param user the user to initialize the CmsObject with
3471     * @param password the password of the user
3472     * @param ouFqn the organizational unit, if <code>null</code> the users ou is used
3473     *
3474     * @return a cms context that has been initialized with "Guest" permissions
3475     *
3476     * @throws CmsException in case the CmsObject could not be initialized
3477     */
3478    private CmsObject initCmsObject(
3479        HttpServletRequest req,
3480        HttpServletResponse res,
3481        String user,
3482        String password,
3483        String ouFqn)
3484    throws CmsException {
3485
3486        String siteroot = null;
3487        // gather information from request if provided
3488        if (req != null) {
3489            siteroot = OpenCms.getSiteManager().matchRequest(req).getSiteRoot();
3490        }
3491        // initialize the user
3492        if (user == null) {
3493            user = getDefaultUsers().getUserGuest();
3494        }
3495        if (siteroot == null) {
3496            siteroot = "/";
3497        }
3498        CmsObject cms = initCmsObject(
3499            req,
3500            m_securityManager.readUser(null, user),
3501            siteroot,
3502            CmsProject.ONLINE_PROJECT_ID,
3503            ouFqn);
3504        // login the user if different from Guest and password was provided
3505        if ((password != null) && !getDefaultUsers().isUserGuest(user)) {
3506            cms.loginUser(user, password, CmsContextInfo.LOCALHOST);
3507        }
3508        return cms;
3509    }
3510
3511    /**
3512     * Checks whether the given request targets the workplace UI servlet.<p>
3513     *
3514     * @param req the request
3515     *
3516     * @return <code>true</code> in case the given request targets the workplace UI servlet
3517     */
3518    private boolean isWorkplaceServletRequest(HttpServletRequest req) {
3519
3520        String servletPath = req.getServletPath();
3521        return (servletPath != null) && servletPath.startsWith(CmsSystemInfo.WORKPLACE_PATH);
3522    }
3523
3524    /**
3525     * Sets the init level of this OpenCmsCore object instance.<p>
3526     *
3527     * For a detailed description about the possible run levels,
3528     * please see {@link OpenCms#getRunLevel()}.<p>
3529     *
3530     * @param level the level to set
3531     */
3532    private void setRunLevel(int level) {
3533
3534        if (m_instance != null) {
3535            if (m_instance.m_runLevel >= OpenCms.RUNLEVEL_1_CORE_OBJECT) {
3536                // otherwise the log is not available
3537                if (CmsLog.INIT.isInfoEnabled()) {
3538                    CmsLog.INIT.info(
3539                        Messages.get().getBundle().key(
3540                            Messages.INIT_RUNLEVEL_CHANGE_2,
3541                            Integer.valueOf(m_instance.m_runLevel),
3542                            Integer.valueOf(level)));
3543                }
3544            }
3545            m_instance.m_runLevel = level;
3546        }
3547    }
3548
3549}