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