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