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