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