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