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.workplace;
029
030import org.opencms.ade.configuration.CmsElementView;
031import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode;
032import org.opencms.ade.galleries.shared.CmsGallerySearchScope;
033import org.opencms.ade.upload.CmsDefaultUploadRestriction;
034import org.opencms.ade.upload.I_CmsUploadRestriction;
035import org.opencms.configuration.CmsAdditionalLogFolderConfig;
036import org.opencms.configuration.CmsDefaultUserSettings;
037import org.opencms.db.CmsExportPoint;
038import org.opencms.db.CmsUserSettings;
039import org.opencms.db.I_CmsProjectDriver;
040import org.opencms.file.CmsFolder;
041import org.opencms.file.CmsObject;
042import org.opencms.file.CmsProject;
043import org.opencms.file.CmsPropertyDefinition;
044import org.opencms.file.CmsRequestContext;
045import org.opencms.file.CmsResource;
046import org.opencms.file.CmsResourceFilter;
047import org.opencms.file.CmsUser;
048import org.opencms.file.CmsVfsResourceNotFoundException;
049import org.opencms.file.types.CmsResourceTypeFolder;
050import org.opencms.file.types.CmsResourceTypeFolderExtended;
051import org.opencms.file.types.I_CmsResourceType;
052import org.opencms.i18n.CmsAcceptLanguageHeaderParser;
053import org.opencms.i18n.CmsEncoder;
054import org.opencms.i18n.CmsI18nInfo;
055import org.opencms.i18n.CmsLocaleComparator;
056import org.opencms.i18n.CmsLocaleManager;
057import org.opencms.i18n.I_CmsLocaleHandler;
058import org.opencms.loader.CmsLoaderException;
059import org.opencms.main.CmsBroadcast.ContentMode;
060import org.opencms.main.CmsEvent;
061import org.opencms.main.CmsException;
062import org.opencms.main.CmsLog;
063import org.opencms.main.I_CmsEventListener;
064import org.opencms.main.OpenCms;
065import org.opencms.module.CmsModule;
066import org.opencms.module.CmsModuleManager;
067import org.opencms.relations.CmsCategoryService;
068import org.opencms.security.CmsOrganizationalUnit;
069import org.opencms.security.CmsPermissionSet;
070import org.opencms.security.CmsPermissionViolationException;
071import org.opencms.security.CmsRole;
072import org.opencms.security.CmsRoleViolationException;
073import org.opencms.security.I_CmsPrincipal;
074import org.opencms.util.CmsRfsFileViewer;
075import org.opencms.util.CmsStringUtil;
076import org.opencms.util.CmsUUID;
077import org.opencms.workplace.CmsAccountInfo.Field;
078import org.opencms.workplace.editors.CmsEditorDisplayOptions;
079import org.opencms.workplace.editors.CmsEditorHandler;
080import org.opencms.workplace.editors.CmsWorkplaceEditorManager;
081import org.opencms.workplace.editors.I_CmsEditorActionHandler;
082import org.opencms.workplace.editors.I_CmsEditorCssHandler;
083import org.opencms.workplace.editors.I_CmsEditorHandler;
084import org.opencms.workplace.editors.I_CmsPreEditorActionDefinition;
085import org.opencms.workplace.editors.directedit.CmsDirectEditDefaultProvider;
086import org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider;
087import org.opencms.workplace.explorer.CmsExplorerTypeAccess;
088import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
089import org.opencms.workplace.galleries.A_CmsAjaxGallery;
090import org.opencms.workplace.tools.CmsToolManager;
091
092import java.io.IOException;
093import java.io.UnsupportedEncodingException;
094import java.net.URL;
095import java.util.ArrayList;
096import java.util.Arrays;
097import java.util.Collections;
098import java.util.Enumeration;
099import java.util.HashMap;
100import java.util.HashSet;
101import java.util.Iterator;
102import java.util.List;
103import java.util.Locale;
104import java.util.Map;
105import java.util.Set;
106import java.util.concurrent.TimeUnit;
107import java.util.jar.Manifest;
108import java.util.regex.Pattern;
109import java.util.regex.PatternSyntaxException;
110
111import javax.servlet.http.HttpServletRequest;
112import javax.servlet.http.HttpSession;
113
114import org.apache.commons.logging.Log;
115
116import com.google.common.cache.Cache;
117import com.google.common.cache.CacheBuilder;
118import com.google.common.collect.Lists;
119import com.google.common.collect.Maps;
120import com.google.common.collect.Sets;
121
122/**
123 * Manages the global OpenCms workplace settings for all users.<p>
124 *
125 * This class reads the settings from the "opencms.properties" and stores them in member variables.
126 * For each setting one or more get methods are provided.<p>
127 *
128 * @since 6.0.0
129 */
130public final class CmsWorkplaceManager implements I_CmsLocaleHandler, I_CmsEventListener {
131
132    /**
133     * Helper class used to easily define default view mappings for standard resource types.<p>
134     */
135    static class ViewRules {
136
137        /**
138         * Internal view map.<p>
139         */
140        private Map<String, String> m_viewMap = Maps.newHashMap();
141
142        /**
143         * Creates a new instance.<p>
144         *
145         * @param rules an array of strings of the form 'foo,bar,baz:view1', where foo, ... are type names and view1 is a view name (explorertype)
146         */
147        public ViewRules(String... rules) {
148
149            for (String rule : rules) {
150                int colIndex = rule.indexOf(':');
151                if (colIndex != -1) {
152                    String before = rule.substring(0, colIndex);
153                    String after = rule.substring(colIndex + 1);
154                    for (String token : CmsStringUtil.splitAsList(before, ",")) {
155                        m_viewMap.put(token.trim(), after);
156                    }
157                }
158
159            }
160        }
161
162        /**
163         * Gets the view configured for the given type.<p>
164         *
165         * @param type a resource type name
166         * @return the view explorer type for the given resource type
167         */
168        public String getViewForType(String type) {
169
170            return m_viewMap.get(type);
171
172        }
173    }
174
175    /** The default encoding for the workplace (UTF-8). */
176    public static final String DEFAULT_WORKPLACE_ENCODING = CmsEncoder.ENCODING_UTF_8;
177
178    /** The workplace localization manifest attribute name. */
179    public static final String LOCALIZATION_ATTRIBUTE_NAME = "OpenCms-Localization";
180
181    /** The manifest file resource name. */
182    public static final String MANIFEST_RESOURCE_NAME = "META-INF/MANIFEST.MF";
183
184    /** The id of the "requestedResource" parameter for the OpenCms login form. */
185    public static final String PARAM_LOGIN_REQUESTED_RESOURCE = "requestedResource";
186
187    /** Key name for the session workplace settings. */
188    public static final String SESSION_WORKPLACE_SETTINGS = "__CmsWorkplace.WORKPLACE_SETTINGS";
189
190    /** Default view configuration. */
191    static ViewRules m_defaultViewRules = new ViewRules(
192        "folder,plain,jsp,htmlredirect,containerpage:view_basic",
193        "imagegallery,downloadgallery,linkgallery,subsitemap,content_folder:view_folders",
194        "formatter_config,xmlvfsbundle,propertyvfsbundle,bundledescriptor,sitemap_config,sitemap_master_config,site_plugin,attr_editor_config,module_config,elementview,seo_file,containerpage_template,inheritance_config,macro_formatter,flex_formatter,settings_config:view_configs",
195        "xmlcontent,pointer:view_other");
196
197    /** The default account infos. */
198    private static final CmsAccountInfo[] DEFAULT_ACCOUNT_INFOS = new CmsAccountInfo[] {
199        new CmsAccountInfo(Field.firstname, null, false),
200        new CmsAccountInfo(Field.lastname, null, false),
201        new CmsAccountInfo(Field.email, null, false),
202        new CmsAccountInfo(Field.institution, null, false)};
203
204    /** The logger for this class. */
205    private static final Log LOG = CmsLog.getLog(CmsWorkplaceManager.class);
206
207    /** Value of the acacia-unlock configuration option (may be null if not set). */
208    private String m_acaciaUnlock;
209
210    /** The configured account infos. */
211    private List<CmsAccountInfo> m_accountInfos;
212
213    /** The admin cms context. */
214    private CmsObject m_adminCms;
215
216    /** Indicates if auto-locking of resources is enabled or disabled. */
217    private boolean m_autoLockResources;
218
219    /** The name of the local category folder(s). */
220    private String m_categoryFolder;
221
222    /** The default access for explorer types. */
223    private CmsExplorerTypeAccess m_defaultAccess;
224
225    /** The configured default locale of the workplace. */
226    private Locale m_defaultLocale;
227
228    /** The default property setting for setting new property values. */
229    private boolean m_defaultPropertiesOnStructure;
230
231    /** The default user settings. */
232    private CmsDefaultUserSettings m_defaultUserSettings;
233
234    /** The configured dialog handlers. */
235    private Map<String, I_CmsDialogHandler> m_dialogHandler;
236
237    /** The configured direct edit provider. */
238    private I_CmsDirectEditProvider m_directEditProvider;
239
240    /** A flag, indicating if the categories should be displayed separated by repository in the category selection dialog. */
241    private boolean m_displayCategoriesByRepository;
242
243    /** A flag, indicating if the categories should be displayed separated by repository in the category selection dialog. */
244    private boolean m_displayCategorySelectionCollapsed;
245
246    /** The edit action handler. */
247    private I_CmsEditorActionHandler m_editorAction;
248
249    /** The editor CSS handlers. */
250    private List<I_CmsEditorCssHandler> m_editorCssHandlers;
251
252    /** The workplace editor display options. */
253    private CmsEditorDisplayOptions m_editorDisplayOptions;
254
255    /** The editor handler. */
256    private I_CmsEditorHandler m_editorHandler;
257
258    /** The editor manager. */
259    private CmsWorkplaceEditorManager m_editorManager;
260
261    /** The element delete mode. */
262    private ElementDeleteMode m_elementDeleteMode;
263
264    /** The flag if switching tabs in the advanced property dialog is enabled. */
265    private boolean m_enableAdvancedPropertyTabs;
266
267    /** The configured encoding of the workplace. */
268    private String m_encoding;
269
270    /** The explorer type settings. */
271    private List<CmsExplorerTypeSettings> m_explorerTypeSettings;
272
273    /** The explorer type settings from the configured modules. */
274    private List<CmsExplorerTypeSettings> m_explorerTypeSettingsFromModules;
275
276    /** The explorer type settings from the XML configuration. */
277    private List<CmsExplorerTypeSettings> m_explorerTypeSettingsFromXml;
278
279    /** The explorer type settings as Map with resource type name as key. */
280    private Map<String, CmsExplorerTypeSettings> m_explorerTypeSettingsMap;
281
282    /** The element views generated from explorer types. */
283    private Map<CmsUUID, CmsElementView> m_explorerTypeViews = Maps.newHashMap();
284
285    /** The workplace export points. */
286    private Set<CmsExportPoint> m_exportPoints;
287
288    /** Maximum size of an upload file. */
289    private int m_fileMaxUploadSize;
290
291    /** The instance used for reading portions of lines of a file to choose. */
292    private CmsRfsFileViewer m_fileViewSettings;
293
294    /** The configured workplace galleries. */
295    private Map<String, A_CmsAjaxGallery> m_galleries;
296
297    /** The configured gallery default scope. */
298    private String m_galleryDefaultScope;
299
300    /** The group translation. */
301    private I_CmsGroupNameTranslation m_groupNameTranslation;
302
303    /** The configured group translation class name. */
304    private String m_groupTranslationClass;
305
306    /** Keep-alive flag. */
307    private Boolean m_keepAlive;
308
309    /** Contains all folders that should be labeled if siblings exist. */
310    private List<String> m_labelSiteFolders;
311
312    /** List of installed workplace locales, sorted ascending. */
313    private List<Locale> m_locales;
314
315    /** The configured list of localized workplace folders. */
316    private List<String> m_localizedFolders;
317
318    /** The additional log folder configuration. */
319    private CmsAdditionalLogFolderConfig m_logFolderConfig = new CmsAdditionalLogFolderConfig();
320
321    /** The workplace localized messages (mapped to the locales). */
322    private Map<Locale, CmsWorkplaceMessages> m_messages;
323
324    /** The post upload handler. */
325    private I_CmsPostUploadDialogHandler m_postUploadHandler;
326
327    /** The condition definitions for the resource types  which are triggered before opening the editor. */
328    private List<I_CmsPreEditorActionDefinition> m_preEditorConditionDefinitions;
329
330    /** The repository folder handler. */
331    private I_CmsRepositoryFolderHandler m_repositoryFolderHandler;
332
333    /** Indicates if the user management icon should be displayed in the workplace. */
334    private boolean m_showUserGroupIcon;
335
336    /** Exclude patterns for synchronization. */
337    private ArrayList<Pattern> m_synchronizeExcludePatterns;
338
339    /** The temporary file project used by the editors. */
340    private CmsProject m_tempFileProject;
341
342    /** The tool manager. */
343    private CmsToolManager m_toolManager;
344
345    /** The upload restriction. */
346    private I_CmsUploadRestriction m_uploadRestriction = CmsDefaultUploadRestriction.unrestricted();
347
348    /** Keeps track of whether the upload restriction has been set. */
349    private boolean m_uploadRestrictionSet;
350
351    /** The user additional information configuration. */
352    private CmsWorkplaceUserInfoManager m_userInfoManager;
353
354    /** The user list mode. */
355    private String m_userListMode;
356
357    /** The configured workplace views. */
358    private List<CmsWorkplaceView> m_views;
359
360    /** Expiring cache used to limit the number of notifications sent because of invalid workplace server names. */
361    private Cache<String, String> m_workplaceServerUserChecks;
362
363    /** The XML content auto correction flag. */
364    private boolean m_xmlContentAutoCorrect;
365
366    /** The role required for editing the sitemap configuration. */
367    private String m_sitemapConfigEditRole;
368
369    /**
370     * Creates a new instance for the workplace manager, will be called by the workplace configuration manager.<p>
371     */
372    public CmsWorkplaceManager() {
373
374        if (CmsLog.INIT.isInfoEnabled()) {
375            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_WORKPLACE_INITIALIZE_START_0));
376        }
377
378        m_locales = new ArrayList<Locale>();
379        m_labelSiteFolders = new ArrayList<String>();
380        m_localizedFolders = new ArrayList<String>();
381        m_autoLockResources = true;
382        m_categoryFolder = CmsCategoryService.REPOSITORY_BASE_FOLDER;
383        m_xmlContentAutoCorrect = true;
384        m_showUserGroupIcon = true;
385        m_dialogHandler = new HashMap<String, I_CmsDialogHandler>();
386        m_views = new ArrayList<CmsWorkplaceView>();
387        m_exportPoints = new HashSet<CmsExportPoint>();
388        m_editorHandler = new CmsEditorHandler();
389        m_fileMaxUploadSize = -1;
390        m_fileViewSettings = new CmsRfsFileViewer();
391        m_explorerTypeSettingsFromXml = new ArrayList<CmsExplorerTypeSettings>();
392        m_explorerTypeSettingsFromModules = new ArrayList<CmsExplorerTypeSettings>();
393        m_defaultPropertiesOnStructure = true;
394        m_enableAdvancedPropertyTabs = true;
395        m_defaultUserSettings = new CmsDefaultUserSettings();
396        m_defaultAccess = new CmsExplorerTypeAccess();
397        m_galleries = new HashMap<String, A_CmsAjaxGallery>();
398        flushMessageCache();
399        m_preEditorConditionDefinitions = new ArrayList<I_CmsPreEditorActionDefinition>();
400        m_editorCssHandlers = new ArrayList<I_CmsEditorCssHandler>();
401        m_synchronizeExcludePatterns = new ArrayList<Pattern>();
402
403        // important to set this to null to avoid unnecessary overhead during configuration phase
404        m_explorerTypeSettings = null;
405        CacheBuilder<Object, Object> cb = CacheBuilder.newBuilder().expireAfterWrite(
406            2,
407            TimeUnit.MINUTES).concurrencyLevel(3);
408        m_workplaceServerUserChecks = cb.build();
409    }
410
411    /**
412     * Returns true if the provided request was done by a Workplace user.<p>
413     *
414     * @param req the request to check
415     *
416     * @return true if the provided request was done by a Workplace user
417     */
418    public static boolean isWorkplaceUser(HttpServletRequest req) {
419
420        HttpSession session = req.getSession(false);
421        if (session != null) {
422            // if a session is available, check for a workplace configuration
423            CmsWorkplaceSettings workplaceSettings = (CmsWorkplaceSettings)session.getAttribute(
424                CmsWorkplaceManager.SESSION_WORKPLACE_SETTINGS);
425            return ((null != workplaceSettings) && !workplaceSettings.getUser().isGuestUser());
426        }
427        // no session means no workplace use
428        return false;
429    }
430
431    /**
432     * Adds an account info.<p>
433     *
434     * @param info the account info to add
435     */
436    public void addAccountInfo(CmsAccountInfo info) {
437
438        if (m_accountInfos == null) {
439            m_accountInfos = new ArrayList<CmsAccountInfo>();
440        }
441        m_accountInfos.add(info);
442    }
443
444    /**
445     * Adds an account info.<p>
446     *
447     * @param field the field
448     * @param addInfoKey the additional info key
449     * @param editable the editable flag
450     */
451    public void addAccountInfo(String field, String addInfoKey, String editable) {
452
453        addAccountInfo(new CmsAccountInfo(field, addInfoKey, editable));
454    }
455
456    /**
457     * Adds a dialog handler instance to the list of configured dialog handlers.<p>
458     *
459     * @param clazz the instantiated dialog handler to add
460     */
461    public void addDialogHandler(I_CmsDialogHandler clazz) {
462
463        m_dialogHandler.put(clazz.getDialogHandler(), clazz);
464        if (CmsLog.INIT.isInfoEnabled()) {
465            CmsLog.INIT.info(
466                Messages.get().getBundle().key(
467                    Messages.INIT_ADD_DIALOG_HANDLER_2,
468                    clazz.getDialogHandler(),
469                    clazz.getClass().getName()));
470        }
471    }
472
473    /**
474     * Adds an editor CSS handler class to the list of handlers.<p>
475     *
476     * @param editorCssHandlerClassName full class name of the css handler class
477     */
478    public void addEditorCssHandler(String editorCssHandlerClassName) {
479
480        try {
481            I_CmsEditorCssHandler editorCssHandler = (I_CmsEditorCssHandler)Class.forName(
482                editorCssHandlerClassName).newInstance();
483            m_editorCssHandlers.add(editorCssHandler);
484            if (CmsLog.INIT.isInfoEnabled()) {
485                CmsLog.INIT.info(
486                    Messages.get().getBundle().key(Messages.INIT_EDITOR_CSSHANDLER_CLASS_1, editorCssHandlerClassName));
487            }
488        } catch (Exception e) {
489            LOG.error(
490                Messages.get().getBundle().key(Messages.LOG_INVALID_EDITOR_CSSHANDLER_1, editorCssHandlerClassName),
491                e);
492        }
493    }
494
495    /**
496     * Adds an editor CSS handler class at the first position of the list of handlers.<p>
497     *
498     * @param editorCssHandlerClassName full class name of the css handler class
499     */
500    public void addEditorCssHandlerToHead(String editorCssHandlerClassName) {
501
502        try {
503            I_CmsEditorCssHandler editorCssHandler = (I_CmsEditorCssHandler)Class.forName(
504                editorCssHandlerClassName).newInstance();
505
506            List<I_CmsEditorCssHandler> editorCssHandlers = new ArrayList<I_CmsEditorCssHandler>();
507            editorCssHandlers.add(editorCssHandler);
508            editorCssHandlers.addAll(m_editorCssHandlers);
509
510            m_editorCssHandlers = editorCssHandlers;
511
512            if (CmsLog.INIT.isInfoEnabled()) {
513                CmsLog.INIT.info(
514                    Messages.get().getBundle().key(Messages.INIT_EDITOR_CSSHANDLER_CLASS_1, editorCssHandlerClassName));
515            }
516        } catch (Exception e) {
517            LOG.error(
518                Messages.get().getBundle().key(Messages.LOG_INVALID_EDITOR_CSSHANDLER_1, editorCssHandlerClassName),
519                e);
520        }
521    }
522
523    /**
524     * Adds an explorer type setting object to the list of type settings.<p>
525     *
526     * @param settings the explorer type settings
527     */
528    public void addExplorerTypeSetting(CmsExplorerTypeSettings settings) {
529
530        m_explorerTypeSettingsFromXml.add(settings);
531        if (CmsLog.INIT.isInfoEnabled()) {
532            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_TYPE_SETTING_1, settings.getName()));
533        }
534        if (m_explorerTypeSettings != null) {
535            // reset the list of all explorer type settings, but not during startup
536            initExplorerTypeSettings();
537        }
538    }
539
540    /**
541     * Adds the list of explorer type settings from the given module.<p>
542     *
543     * @param module the module witch contains the explorer type settings to add
544     */
545    public void addExplorerTypeSettings(CmsModule module) {
546
547        List<CmsExplorerTypeSettings> explorerTypes = module.getExplorerTypes();
548        if ((explorerTypes != null) && (explorerTypes.size() > 0)) {
549            Iterator<CmsExplorerTypeSettings> i = explorerTypes.iterator();
550            while (i.hasNext()) {
551                CmsExplorerTypeSettings settings = i.next();
552                if (m_explorerTypeSettingsFromModules.contains(settings)) {
553                    m_explorerTypeSettingsFromModules.remove(settings);
554                }
555                m_explorerTypeSettingsFromModules.add(settings);
556                if (CmsLog.INIT.isInfoEnabled()) {
557                    CmsLog.INIT.info(
558                        Messages.get().getBundle().key(Messages.INIT_ADD_TYPE_SETTING_1, settings.getName()));
559                }
560            }
561            // reset the list of all explorer type settings
562            initExplorerTypeSettings();
563        }
564    }
565
566    /**
567     * Adds newly created export point to the workplace configuration.<p>
568     *
569     * @param uri the export point uri
570     * @param destination the export point destination
571     */
572    public void addExportPoint(String uri, String destination) {
573
574        CmsExportPoint point = new CmsExportPoint(uri, destination);
575        m_exportPoints.add(point);
576        if (CmsLog.INIT.isInfoEnabled() && (point.getDestinationPath() != null)) {
577            CmsLog.INIT.info(
578                Messages.get().getBundle().key(
579                    Messages.INIT_ADD_EXPORT_POINT_2,
580                    point.getUri(),
581                    point.getDestinationPath()));
582        }
583    }
584
585    /**
586     * Adds a folder to the list of labeled folders.<p>
587     *
588     * @param uri the folder uri to add
589     */
590    public void addLabeledFolder(String uri) {
591
592        m_labelSiteFolders.add(uri);
593        if (CmsLog.INIT.isInfoEnabled()) {
594            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LABEL_LINKS_IN_FOLDER_1, uri));
595        }
596    }
597
598    /**
599     * Adds a new folder to the list of localized workplace folders.<p>
600     *
601     * @param uri a new folder to add to the list of localized workplace folders
602     */
603    public void addLocalizedFolder(String uri) {
604
605        m_localizedFolders.add(uri);
606        if (CmsLog.INIT.isInfoEnabled()) {
607            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_WORKPLACE_LOCALIZED_1, uri));
608        }
609    }
610
611    /**
612     * Adds an initialized condition definition class that is triggered before opening the editor.<p>
613     *
614     * @param preEditorCondition the initialized condition definition class
615     */
616    public void addPreEditorConditionDefinition(I_CmsPreEditorActionDefinition preEditorCondition) {
617
618        m_preEditorConditionDefinitions.add(preEditorCondition);
619        if (CmsLog.INIT.isInfoEnabled()) {
620            CmsLog.INIT.info(
621                Messages.get().getBundle().key(
622                    Messages.INIT_EDITOR_PRE_ACTION_2,
623                    preEditorCondition.getClass().getName(),
624                    preEditorCondition.getResourceTypeName()));
625        }
626    }
627
628    /**
629     * Adds a condition definition class for a given resource type name that is triggered before opening the editor.<p>
630     *
631     * @param resourceTypeName the name of the resource type
632     * @param preEditorConditionDefinitionClassName full class name of the condition definition class
633     */
634    public void addPreEditorConditionDefinition(String resourceTypeName, String preEditorConditionDefinitionClassName) {
635
636        try {
637            I_CmsPreEditorActionDefinition preEditorCondition = (I_CmsPreEditorActionDefinition)Class.forName(
638                preEditorConditionDefinitionClassName).newInstance();
639            preEditorCondition.setResourceTypeName(resourceTypeName);
640            m_preEditorConditionDefinitions.add(preEditorCondition);
641            if (CmsLog.INIT.isInfoEnabled()) {
642                CmsLog.INIT.info(
643                    Messages.get().getBundle().key(
644                        Messages.INIT_EDITOR_PRE_ACTION_2,
645                        preEditorConditionDefinitionClassName,
646                        resourceTypeName));
647            }
648        } catch (Exception e) {
649            LOG.error(
650                Messages.get().getBundle().key(
651                    Messages.LOG_INVALID_EDITOR_PRE_ACTION_1,
652                    preEditorConditionDefinitionClassName),
653                e);
654        }
655    }
656
657    /**
658     * Adds a pattern to be excluded in VFS synchronization.<p>
659     *
660     * @param pattern a java regex to applied on the file name
661     */
662    public void addSynchronizeExcludePattern(String pattern) {
663
664        try {
665            m_synchronizeExcludePatterns.add(Pattern.compile(pattern));
666        } catch (PatternSyntaxException e) {
667            LOG.error(Messages.get().getBundle().key(Messages.LOG_INVALID_SYNCHRONIZE_EXCLUDE_PATTERN_1, pattern), e);
668        }
669    }
670
671    /**
672     * Returns if the autolock resources feature is enabled.<p>
673     *
674     * @return true if the autolock resources feature is enabled, otherwise false
675     */
676    public boolean autoLockResources() {
677
678        return m_autoLockResources;
679    }
680
681    /**
682     * Checks whether the workplace is accessed through the workplace server, and sends an error message otherwise.<p>
683     *
684     * @param request the request to check
685     * @param cms the CmsObject to use
686     */
687    public void checkWorkplaceRequest(HttpServletRequest request, CmsObject cms) {
688
689        try {
690            if ((OpenCms.getSiteManager().getSites().size() > 1)
691                && !OpenCms.getSiteManager().isWorkplaceRequest(request)) {
692                // this is a multi site-configuration, but not a request to the configured Workplace site
693
694                CmsUser user = cms.getRequestContext().getCurrentUser();
695                // to limit the number of times broadcast is called for a user, we use an expiring cache
696                // with the user name as  key
697                if (null == m_workplaceServerUserChecks.getIfPresent(user.getName())) {
698                    m_workplaceServerUserChecks.put(user.getName(), "");
699                    OpenCms.getSessionManager().sendBroadcast(
700                        null,
701                        Messages.get().getBundle(getWorkplaceLocale(cms)).key(
702                            Messages.ERR_WORKPLACE_SERVER_CHECK_FAILED_0),
703                        user,
704                        ContentMode.plain);
705
706                }
707
708            }
709        } catch (Exception e) {
710            LOG.error(e.getLocalizedMessage(), e);
711        }
712    }
713
714    /**
715     * Implements the event listener of this class.<p>
716     *
717     * @see org.opencms.main.I_CmsEventListener#cmsEvent(org.opencms.main.CmsEvent)
718     */
719    public void cmsEvent(CmsEvent event) {
720
721        switch (event.getType()) {
722            case I_CmsEventListener.EVENT_CLEAR_CACHES:
723                flushMessageCache();
724                m_editorDisplayOptions.clearCache();
725                if (LOG.isDebugEnabled()) {
726                    LOG.debug(Messages.get().getBundle().key(Messages.LOG_EVENT_CLEAR_CACHES_0));
727                }
728                break;
729            default: // no operation
730        }
731    }
732
733    /**
734     * Creates a temporary file which is needed while working in an editor with preview option.<p>
735     *
736     * <i>Note</i>: This method is synchronized to avoid rare issues that might be caused by
737     * double requests fired by some browser/OS combinations.<p>
738     *
739     * @param cms the cms context
740     * @param resourceName the name of the resource to copy
741     * @param currentProjectId the id of the project to work with
742     *
743     * @return the file name of the temporary file
744     *
745     * @throws CmsException if something goes wrong
746     */
747    public synchronized String createTempFile(CmsObject cms, String resourceName, CmsUUID currentProjectId)
748    throws CmsException {
749
750        // check that the current user has write permissions
751        if (!cms.hasPermissions(cms.readResource(resourceName, CmsResourceFilter.ALL), CmsPermissionSet.ACCESS_WRITE)) {
752            throw new CmsPermissionViolationException(
753                org.opencms.db.Messages.get().container(org.opencms.db.Messages.ERR_PERM_DENIED_2, resourceName, "w"));
754        }
755
756        // initialize admin cms context
757        CmsObject adminCms = getAdminCms(cms);
758
759        // generate the filename of the temporary file
760        String temporaryFilename = CmsWorkplace.getTemporaryFileName(resourceName);
761
762        // check if the temporary file is already present
763        if (adminCms.existsResource(temporaryFilename, CmsResourceFilter.ALL)) {
764            // delete old temporary file
765            if (!cms.getLock(temporaryFilename).isUnlocked()) {
766                // steal lock
767                cms.changeLock(temporaryFilename);
768            } else {
769                // lock resource to current user
770                cms.lockResource(temporaryFilename);
771            }
772            cms.deleteResource(temporaryFilename, CmsResource.DELETE_PRESERVE_SIBLINGS);
773        }
774
775        try {
776            // switch to the temporary file project
777            adminCms.getRequestContext().setCurrentProject(cms.readProject(getTempFileProjectId()));
778            // copy the file to edit to a temporary file
779            adminCms.copyResource(resourceName, temporaryFilename, CmsResource.COPY_AS_NEW);
780        } finally {
781            // switch back to current project
782            adminCms.getRequestContext().setCurrentProject(cms.readProject(currentProjectId));
783        }
784
785        try {
786            // switch to the temporary file project
787            cms.getRequestContext().setCurrentProject(
788                cms.readProject(OpenCms.getWorkplaceManager().getTempFileProjectId()));
789            // lock the temporary file
790            cms.changeLock(temporaryFilename);
791            // touch the temporary file
792            cms.setDateLastModified(temporaryFilename, System.currentTimeMillis(), false);
793            // set the temporary file flag
794            CmsResource tempFile = cms.readResource(temporaryFilename, CmsResourceFilter.ALL);
795            int flags = tempFile.getFlags();
796            if ((flags & CmsResource.FLAG_TEMPFILE) == 0) {
797                flags += CmsResource.FLAG_TEMPFILE;
798            }
799            cms.chflags(temporaryFilename, flags);
800            // remove eventual release & expiration date from temporary file to make preview in editor work
801            cms.setDateReleased(temporaryFilename, CmsResource.DATE_RELEASED_DEFAULT, false);
802            cms.setDateExpired(temporaryFilename, CmsResource.DATE_EXPIRED_DEFAULT, false);
803            // remove visibility permissions for everybody on temporary file if possible
804            if (cms.hasPermissions(tempFile, CmsPermissionSet.ACCESS_CONTROL)) {
805                cms.chacc(
806                    temporaryFilename,
807                    I_CmsPrincipal.PRINCIPAL_GROUP,
808                    OpenCms.getDefaultUsers().getGroupUsers(),
809                    "-v");
810            }
811        } finally {
812            // switch back to current project
813            cms.getRequestContext().setCurrentProject(cms.readProject(currentProjectId));
814        }
815
816        return temporaryFilename;
817    }
818
819    /**
820     * Flushes the cached workplace messages.<p>
821     */
822    public void flushMessageCache() {
823
824        // clear the cached message objects
825        m_messages = new HashMap<Locale, CmsWorkplaceMessages>();
826        if (LOG.isDebugEnabled()) {
827            try {
828                throw new RuntimeException("Tracing exception");
829            } catch (Exception e) {
830                LOG.info("Tracing call to CmsWorkplaceManager.flushMessageCache method.", e);
831            }
832        }
833    }
834
835    /**
836     * Gets the value of the acacia-unlock configuration option (null if not set explicitly).<p>
837     *
838     * @return the value of the acacia-unlock configuration option
839     */
840    public String getAcaciaUnlock() {
841
842        return m_acaciaUnlock;
843    }
844
845    /**
846     * Returns the account infos.<p>
847     *
848     * @return the account infos
849     */
850    public List<CmsAccountInfo> getAccountInfos() {
851
852        if (m_accountInfos == null) {
853            return Collections.unmodifiableList(Arrays.asList(DEFAULT_ACCOUNT_INFOS));
854        } else {
855            return Collections.unmodifiableList(m_accountInfos);
856        }
857    }
858
859    /**
860     * Gets the additional log folder configuration.<p>
861     *
862     * @return the additional log folder configuration
863     */
864    public CmsAdditionalLogFolderConfig getAdditionalLogFolderConfiguration() {
865
866        return m_logFolderConfig;
867    }
868
869    /**
870     * Returns the name of the local category folder(s).<p>
871     *
872     * @return the name of the local category folder(s)
873     */
874    public String getCategoryFolder() {
875
876        return m_categoryFolder;
877    }
878
879    /**
880     * Returns the configured account infos.<p>
881     *
882     * @return the configured account infos
883     */
884    public List<CmsAccountInfo> getConfiguredAccountInfos() {
885
886        return m_accountInfos;
887    }
888
889    /**
890     * Gets the access object of the type settings.<p>
891     *
892     * @return access object of the type settings
893     */
894    public CmsExplorerTypeAccess getDefaultAccess() {
895
896        return m_defaultAccess;
897    }
898
899    /**
900     * Returns the Workplace default locale.<p>
901     *
902     * @return  the Workplace default locale
903     */
904    public Locale getDefaultLocale() {
905
906        return m_defaultLocale;
907    }
908
909    /**
910     * Gets the default name pattern for the given type.<p>
911     *
912     * @param type the type name
913     * @return the default name pattern for the type
914     */
915    public String getDefaultNamePattern(String type) {
916
917        CmsExplorerTypeSettings settings = getExplorerTypeSetting(type);
918        if ((settings != null) && (settings.getNamePattern() != null)) {
919            return settings.getNamePattern();
920        }
921        if (type.equals("sitemap_config") || type.equals("module_config")) {
922            return ".config%(number)";
923        }
924        if (type.equals("content_folder")) {
925            return ".content%(number)";
926        }
927        return "new_" + type + "%(number)";
928    }
929
930    /**
931     * Returns the Workplace default user settings.<p>
932     *
933     * @return  the Workplace default user settings
934     */
935    public CmsDefaultUserSettings getDefaultUserSettings() {
936
937        return m_defaultUserSettings;
938    }
939
940    /**
941     * Returns all instantiated dialog handlers for the workplace.<p>
942     *
943     * @return all instantiated dialog handlers for the workplace
944     */
945    public Map<String, I_CmsDialogHandler> getDialogHandler() {
946
947        return m_dialogHandler;
948    }
949
950    /**
951     * Returns the instantiated dialog handler class for the key or null, if there is no mapping for the key.<p>
952     *
953     * @param key the key whose associated value is to be returned
954     *
955     * @return the instantiated dialog handler class for the key
956     */
957    public I_CmsDialogHandler getDialogHandler(String key) {
958
959        return m_dialogHandler.get(key);
960    }
961
962    /**
963     * Returns a new instance of the configured direct edit provider.<p>
964     *
965     * @return a new instance of the configured direct edit provider
966     */
967    public I_CmsDirectEditProvider getDirectEditProvider() {
968
969        return m_directEditProvider.newInstance();
970    }
971
972    /**
973     * Returns the instantiated editor action handler class.<p>
974     *
975     * @return the instantiated editor action handler class
976     */
977    public I_CmsEditorActionHandler getEditorActionHandler() {
978
979        return m_editorAction;
980    }
981
982    /**
983     * Returns the instantiated editor CSS handler classes.<p>
984     *
985     * @return the instantiated editor CSS handler classes
986     */
987    public List<I_CmsEditorCssHandler> getEditorCssHandlers() {
988
989        return m_editorCssHandlers;
990    }
991
992    /**
993     * Returns the instantiated editor display option class.<p>
994     *
995     * @return the instantiated editor display option class
996     */
997    public CmsEditorDisplayOptions getEditorDisplayOptions() {
998
999        return m_editorDisplayOptions;
1000    }
1001
1002    /**
1003     * Returns the instantiated editor handler class.<p>
1004     *
1005     * @return the instantiated editor handler class
1006     */
1007    public I_CmsEditorHandler getEditorHandler() {
1008
1009        return m_editorHandler;
1010    }
1011
1012    /**
1013     * Returns the element delete mode.<p>
1014     *
1015     * @return the element delete mode
1016     */
1017    public ElementDeleteMode getElementDeleteMode() {
1018
1019        return m_elementDeleteMode;
1020    }
1021
1022    /**
1023     * Returns the configured workplace encoding.<p>
1024     *
1025     * @return the configured workplace encoding
1026     */
1027    public String getEncoding() {
1028
1029        return m_encoding;
1030    }
1031
1032    /**
1033     * Returns the explorer type settings for the specified resource type.<p>
1034     *
1035     * @param type the resource type for which the settings are required
1036     *
1037     * @return the explorer type settings for the specified resource type
1038     */
1039    public CmsExplorerTypeSettings getExplorerTypeSetting(String type) {
1040
1041        return m_explorerTypeSettingsMap.get(type);
1042    }
1043
1044    /**
1045     * Returns the list of explorer type settings.<p>
1046     *
1047     * These settings provide information for the new resource dialog and the context menu appearance.<p>
1048     *
1049     * @return the list of explorer type settings
1050     */
1051    public List<CmsExplorerTypeSettings> getExplorerTypeSettings() {
1052
1053        if (m_explorerTypeSettings == null) {
1054            // initialize all explorer type settings if not already done
1055            initExplorerTypeSettings();
1056        }
1057
1058        return m_explorerTypeSettings;
1059    }
1060
1061    /**
1062     * Gets the explorer types for the given view name.<p>
1063     *
1064     * @param viewName the view name
1065     *
1066     * @return the explorer names for the given view names
1067     */
1068    public List<CmsExplorerTypeSettings> getExplorerTypesForView(String viewName) {
1069
1070        List<CmsExplorerTypeSettings> result = Lists.newArrayList();
1071        for (CmsExplorerTypeSettings explorerType : getExplorerTypeSettings()) {
1072
1073            String currentViewName = explorerType.getElementView();
1074            if (currentViewName == null) {
1075                currentViewName = getDefaultView(explorerType.getName());
1076            }
1077            if ((currentViewName != null) && currentViewName.equals(viewName)) {
1078                if (OpenCms.getResourceManager().hasResourceType(explorerType.getName())) {
1079                    result.add(explorerType);
1080                }
1081            } else if (CmsResourceTypeFolder.getStaticTypeName().equals(explorerType.getName())
1082                && "view_folders|view_basic".contains(viewName)) {
1083                result.add(explorerType);
1084            }
1085
1086        }
1087        return result;
1088    }
1089
1090    /**
1091     * Gets the element views generated from explorer types.<p>
1092     *
1093     * @return the map of element views from the explorer types
1094     */
1095    public Map<CmsUUID, CmsElementView> getExplorerTypeViews() {
1096
1097        return Collections.unmodifiableMap(m_explorerTypeViews);
1098
1099    }
1100
1101    /**
1102     * Returns the set of configured export points for the workplace.<p>
1103     *
1104     * @return the set of configured export points for the workplace
1105     */
1106    public Set<CmsExportPoint> getExportPoints() {
1107
1108        return m_exportPoints;
1109    }
1110
1111    /**
1112     * Returns the value (in bytes) for the maximum file upload size of the current user.<p>
1113     *
1114     * @param cms the initialized CmsObject
1115     *
1116     * @return the value (in bytes) for the maximum file upload size
1117     */
1118    public long getFileBytesMaxUploadSize(CmsObject cms) {
1119
1120        int maxFileSize = getFileMaxUploadSize();
1121        long maxFileSizeBytes = maxFileSize * 1024;
1122        // check if current user belongs to Admin group, if so no file upload limit
1123        if ((maxFileSize <= 0) || OpenCms.getRoleManager().hasRole(cms, CmsRole.VFS_MANAGER)) {
1124            maxFileSizeBytes = -1;
1125        }
1126        return maxFileSizeBytes;
1127    }
1128
1129    /**
1130     * Returns the value (in kb) for the maximum file upload size.<p>
1131     *
1132     * @return the value (in kb) for the maximum file upload size
1133     */
1134    public int getFileMaxUploadSize() {
1135
1136        return m_fileMaxUploadSize;
1137    }
1138
1139    /**
1140     * Returns the system-wide file view settings for the workplace.<p>
1141     *
1142     * Note that this instance may not modified (invocation of setters) directly or a
1143     * <code>{@link org.opencms.main.CmsRuntimeException}</code> will be thrown.<p>
1144     *
1145     * It has to be cloned first and then may be written back to the workplace settings using
1146     * method {@link #setFileViewSettings(CmsObject, org.opencms.util.CmsRfsFileViewer)}.<p>
1147     *
1148     * @return the system-wide file view settings for the workplace
1149     */
1150    public CmsRfsFileViewer getFileViewSettings() {
1151
1152        return m_fileViewSettings;
1153    }
1154
1155    /**
1156     * Returns a collection of all available galleries.<p>
1157     *
1158     * The Map has the gallery type name as key and an instance of the
1159     * gallery class (not completely initialized) as value.<p>
1160     *
1161     * @return a collection of all available galleries
1162     */
1163    public Map<String, A_CmsAjaxGallery> getGalleries() {
1164
1165        return m_galleries;
1166    }
1167
1168    /**
1169     * Returns the gallery default scope.<p>
1170     *
1171     * @return the gallery default scope
1172     */
1173    public CmsGallerySearchScope getGalleryDefaultScope() {
1174
1175        CmsGallerySearchScope result = CmsGallerySearchScope.siteShared;
1176        if (m_galleryDefaultScope != null) {
1177            try {
1178                result = CmsGallerySearchScope.valueOf(m_galleryDefaultScope);
1179            } catch (Throwable t) {
1180                // ignore
1181            }
1182        }
1183        return result;
1184    }
1185
1186    /**
1187     * Gets the configured gallery default scope as a string.<p>
1188     *
1189     * @return the gallery default scope as a string
1190     */
1191    public String getGalleryDefaultScopeString() {
1192
1193        return m_galleryDefaultScope;
1194    }
1195
1196    /**
1197     * Returns the object used for translating group names.<p>
1198     *
1199     * @return the group name translator
1200     */
1201    public I_CmsGroupNameTranslation getGroupNameTranslation() {
1202
1203        if (m_groupNameTranslation != null) {
1204            return m_groupNameTranslation;
1205        }
1206        if (m_groupTranslationClass != null) {
1207            try {
1208                m_groupNameTranslation = (I_CmsGroupNameTranslation)Class.forName(
1209                    m_groupTranslationClass).newInstance();
1210                return m_groupNameTranslation;
1211            } catch (ClassNotFoundException e) {
1212                LOG.error(e.getLocalizedMessage(), e);
1213            } catch (IllegalAccessException e) {
1214                LOG.error(e.getLocalizedMessage(), e);
1215            } catch (InstantiationException e) {
1216                LOG.error(e.getLocalizedMessage(), e);
1217            } catch (ClassCastException e) {
1218                LOG.error(e.getLocalizedMessage(), e);
1219            }
1220            m_groupNameTranslation = getDefaultGroupNameTranslation();
1221            return m_groupNameTranslation;
1222        } else {
1223            m_groupNameTranslation = getDefaultGroupNameTranslation();
1224            return m_groupNameTranslation;
1225        }
1226    }
1227
1228    /**
1229     * Returns the configured class name for translating group names.<p>
1230     *
1231     * @return the group translation class name
1232     */
1233    public String getGroupTranslationClass() {
1234
1235        return m_groupTranslationClass;
1236    }
1237
1238    /**
1239     * @see org.opencms.i18n.I_CmsLocaleHandler#getI18nInfo(javax.servlet.http.HttpServletRequest, org.opencms.file.CmsUser, org.opencms.file.CmsProject, java.lang.String)
1240     */
1241    public CmsI18nInfo getI18nInfo(HttpServletRequest req, CmsUser user, CmsProject project, String resource) {
1242
1243        Locale locale = null;
1244        // try to read locale from session
1245        if (req != null) {
1246            // set the request character encoding
1247            try {
1248                req.setCharacterEncoding(m_encoding);
1249            } catch (UnsupportedEncodingException e) {
1250                // should not ever really happen
1251                LOG.error(Messages.get().getBundle().key(Messages.LOG_UNSUPPORTED_ENCODING_SET_1, m_encoding), e);
1252            }
1253            // read workplace settings
1254            HttpSession session = req.getSession(false);
1255            if (session != null) {
1256                CmsWorkplaceSettings settings = (CmsWorkplaceSettings)session.getAttribute(
1257                    CmsWorkplaceManager.SESSION_WORKPLACE_SETTINGS);
1258                if (settings != null) {
1259                    locale = settings.getUserSettings().getLocale();
1260                }
1261            }
1262        }
1263
1264        if (locale == null) {
1265            // no session available, try to read the locale form the user additional info
1266            if (!user.isGuestUser()) {
1267                // check user settings only for "real" users
1268                CmsUserSettings settings = new CmsUserSettings(user);
1269                locale = settings.getLocale();
1270
1271            }
1272            if (req != null) {
1273                List<Locale> acceptedLocales = (new CmsAcceptLanguageHeaderParser(
1274                    req,
1275                    getDefaultLocale())).getAcceptedLocales();
1276                if ((locale != null) && (!acceptedLocales.contains(locale))) {
1277                    acceptedLocales.add(0, locale);
1278                }
1279                locale = OpenCms.getLocaleManager().getFirstMatchingLocale(acceptedLocales, m_locales);
1280            }
1281
1282            // if no locale was found, use the default
1283            if (locale == null) {
1284                locale = getDefaultLocale();
1285            }
1286        }
1287
1288        return new CmsI18nInfo(locale, m_encoding);
1289    }
1290
1291    /**
1292     * Returns a list of site folders which generate labeled links.<p>
1293     *
1294     * @return a list of site folders which generate labeled links
1295     */
1296    public List<String> getLabelSiteFolders() {
1297
1298        return m_labelSiteFolders;
1299    }
1300
1301    /**
1302     * Returns the list of available workplace locales, sorted ascending.<p>
1303     *
1304     * Please note: Be careful not to modify the returned Set as it is not a clone.<p>
1305     *
1306     * @return the set of available workplace locales
1307     */
1308    public List<Locale> getLocales() {
1309
1310        return m_locales;
1311    }
1312
1313    /**
1314     * Returns the configured list of localized workplace folders.<p>
1315     *
1316     * @return the configured list of localized workplace folders
1317     */
1318    public List<String> getLocalizedFolders() {
1319
1320        return m_localizedFolders;
1321    }
1322
1323    /**
1324     * Returns the {@link CmsWorkplaceMessages} for the given locale.<p>
1325     *
1326     * The workplace messages are a collection of resource bundles, containing the messages
1327     * for all OpenCms core bundles and of all initialized modules.<p>
1328     *
1329     * Please note that the message objects are cached internally.
1330     * The returned message object should therefore never be modified directly in any way.<p>
1331     *
1332     * @param locale the locale to get the messages for
1333     *
1334     * @return the {@link CmsWorkplaceMessages} for the given locale
1335     */
1336    public CmsWorkplaceMessages getMessages(Locale locale) {
1337
1338        CmsWorkplaceMessages result = m_messages.get(locale);
1339        if (result != null) {
1340            // messages have already been read
1341            return result;
1342        }
1343
1344        // messages have not been read so far
1345        synchronized (this) {
1346            // check again
1347            result = m_messages.get(locale);
1348            if (result == null) {
1349                result = new CmsWorkplaceMessages(locale);
1350                m_messages.put(locale, result);
1351            }
1352        }
1353        return result;
1354    }
1355
1356    /**
1357     * Returns the post upload handler.<p>
1358     *
1359     * @return the post upload handler
1360     */
1361    public I_CmsPostUploadDialogHandler getPostUploadHandler() {
1362
1363        return m_postUploadHandler;
1364    }
1365
1366    /**
1367     * Returns the condition definition for the given resource type that is triggered before opening the editor.<p>
1368     *
1369     * @param resourceType the resource type
1370     *
1371     * @return the condition definition for the given resource type class name or null if none is found
1372     */
1373    public I_CmsPreEditorActionDefinition getPreEditorConditionDefinition(I_CmsResourceType resourceType) {
1374
1375        Iterator<I_CmsPreEditorActionDefinition> i = m_preEditorConditionDefinitions.iterator();
1376        I_CmsPreEditorActionDefinition result = null;
1377        int matchResult = -1;
1378        while (i.hasNext()) {
1379            I_CmsPreEditorActionDefinition currentDefinition = i.next();
1380            if (resourceType.getClass().isInstance(currentDefinition.getResourceType())) {
1381                // now determine the match count...
1382                int matchDistance = 0;
1383                Class<?> superClass = resourceType.getClass();
1384                while (true) {
1385                    // check if a super class is present
1386                    if (superClass == null) {
1387                        break;
1388                    }
1389                    if (superClass.getName().equals(currentDefinition.getResourceType().getClass().getName())) {
1390                        break;
1391                    }
1392                    matchDistance += 1;
1393                    superClass = superClass.getSuperclass();
1394                }
1395                if (matchResult != -1) {
1396                    if (matchDistance < matchResult) {
1397                        matchResult = matchDistance;
1398                        result = currentDefinition;
1399                    }
1400                } else {
1401                    matchResult = matchDistance;
1402                    result = currentDefinition;
1403                }
1404            }
1405        }
1406        return result;
1407    }
1408
1409    /**
1410     * Returns the condition definitions for the different resource
1411     * types which are triggered before opening the editor.<p>
1412     *
1413     * @return the condition definitions
1414     */
1415    public List<I_CmsPreEditorActionDefinition> getPreEditorConditionDefinitions() {
1416
1417        return m_preEditorConditionDefinitions;
1418    }
1419
1420    /**
1421     * Returns the repository folder handler.<p>
1422     *
1423     * @return the repository folder handler
1424     */
1425    public I_CmsRepositoryFolderHandler getRepositoryFolderHandler() {
1426
1427        if (m_repositoryFolderHandler == null) {
1428            // handler has not been configured, use the default one
1429            m_repositoryFolderHandler = new CmsRepositoryFolderHandler();
1430        }
1431        return m_repositoryFolderHandler;
1432    }
1433
1434    /**
1435     * Gets the name of the role necessary for editing the sitemap configuration.
1436     *
1437     * @return the name of the role necessary for editing the sitemap configuration
1438     */
1439    public String getSitemapConfigEditRole() {
1440
1441        return m_sitemapConfigEditRole;
1442    }
1443
1444    /**
1445     * Returns Regex patterns that should be excluded from synchronization.<p>
1446     *
1447     * @return the exclude patterns
1448     */
1449    public ArrayList<Pattern> getSynchronizeExcludePatterns() {
1450
1451        return m_synchronizeExcludePatterns;
1452    }
1453
1454    /**
1455     * Returns the id of the temporary file project required by the editors.<p>
1456     *
1457     * @return the id of the temporary file project required by the editors
1458     */
1459    public CmsUUID getTempFileProjectId() {
1460
1461        if (m_tempFileProject != null) {
1462            return m_tempFileProject.getUuid();
1463        } else {
1464            return null;
1465        }
1466    }
1467
1468    /**
1469     * Returns the tool manager.<p>
1470     *
1471     * @return the tool manager
1472     */
1473    public CmsToolManager getToolManager() {
1474
1475        if (m_toolManager == null) {
1476            m_toolManager = new CmsToolManager();
1477        }
1478        return m_toolManager;
1479    }
1480
1481    /**
1482     * Gets the upload hook URI which should be opened for an upload to a given folder.<p>
1483     * This method will return null if no upload hook should be used for the given upload folder.<p>
1484     *
1485     * The API for this upload hook is as follows:
1486     *
1487     * The upload hook will be called with the following parameters:
1488     *
1489     * resources (required): a comma separated list of the structure ids of the uploaded resources
1490     *                       if this is omitted
1491     * closelink (optional): a link which should be opened once the upload hook has finished whatever
1492     *                       it is doing
1493     *
1494     * @param cms the current CMS context
1495     * @param uploadFolder the folder for which the upload hook should be found
1496     *
1497     * @return the URI of the upload hook or null
1498     */
1499    public String getUploadHook(CmsObject cms, String uploadFolder) {
1500
1501        if (m_postUploadHandler != null) {
1502            return m_postUploadHandler.getUploadHook(cms, uploadFolder);
1503        }
1504        I_CmsDialogHandler handler = getDialogHandler(CmsDialogSelector.DIALOG_PROPERTY);
1505        if ((handler != null) && (handler instanceof I_CmsPostUploadDialogHandler)) {
1506            return ((I_CmsPostUploadDialogHandler)handler).getUploadHook(cms, uploadFolder);
1507        } else {
1508            return null;
1509        }
1510    }
1511
1512    /**
1513     * Gets the upload restriction.
1514     *
1515     * @return the upload restriction
1516     */
1517    public I_CmsUploadRestriction getUploadRestriction() {
1518
1519        return m_uploadRestriction;
1520    }
1521
1522    /**
1523     * Returns the user additional information configuration Manager.<p>
1524     *
1525     * @return the user additional information configuration manager
1526     */
1527    public CmsWorkplaceUserInfoManager getUserInfoManager() {
1528
1529        return m_userInfoManager;
1530    }
1531
1532    /**
1533     * Returns the user list mode as a string.<p>
1534     *
1535     * @return the user list mode as a string
1536     */
1537    public String getUserListModeString() {
1538
1539        return m_userListMode;
1540    }
1541
1542    /**
1543     * Returns the map of configured workplace views.<p>
1544     *
1545     * @return the map of configured workplace views
1546     */
1547    public List<CmsWorkplaceView> getViews() {
1548
1549        return m_views;
1550    }
1551
1552    /**
1553     * Returns the instantiated workplace editor manager class.<p>
1554     *
1555     * @return the instantiated workplace editor manager class
1556     */
1557    public CmsWorkplaceEditorManager getWorkplaceEditorManager() {
1558
1559        return m_editorManager;
1560    }
1561
1562    /**
1563     * Returns the list of explorer type settings configured in the opencms-workplace.xml file.<p>
1564     *
1565     * @return the list of explorer type settings
1566     */
1567    public List<CmsExplorerTypeSettings> getWorkplaceExplorerTypeSettings() {
1568
1569        return Collections.unmodifiableList(m_explorerTypeSettingsFromXml);
1570    }
1571
1572    /**
1573     * Returns the workplace locale from the current user's settings.<p>
1574     *
1575     * @param cms the current cms object
1576     *
1577     * @return the workplace locale
1578     */
1579    public Locale getWorkplaceLocale(CmsObject cms) {
1580
1581        return getWorkplaceLocale(cms.getRequestContext());
1582    }
1583
1584    /**
1585     * Gets the workplace locale for the given request context.<p>
1586     *
1587     * @param requestContext the request context
1588     *
1589     * @return the workplace locale for the request context
1590     */
1591    public Locale getWorkplaceLocale(CmsRequestContext requestContext) {
1592
1593        Locale wpLocale = new CmsUserSettings(requestContext.getCurrentUser()).getLocale();
1594        if (wpLocale == null) {
1595            // fall back
1596            wpLocale = getDefaultLocale();
1597            if (wpLocale == null) {
1598                // fall back
1599                wpLocale = requestContext.getLocale();
1600            }
1601        }
1602        return wpLocale;
1603
1604    }
1605
1606    /**
1607     * Returns the workplace locale for the user.
1608     * @param user the user to get the workplace locale for.
1609     * @return the workplace locale for the user.
1610     */
1611    public Locale getWorkplaceLocale(CmsUser user) {
1612
1613        Locale wpLocale = new CmsUserSettings(user).getLocale();
1614        if (wpLocale == null) {
1615            // fall back
1616            wpLocale = OpenCms.getWorkplaceManager().getDefaultLocale();
1617            if (wpLocale == null) {
1618                // fall back
1619                wpLocale = CmsLocaleManager.MASTER_LOCALE;
1620            }
1621        }
1622        return wpLocale;
1623
1624    }
1625
1626    /**
1627     * @see org.opencms.i18n.I_CmsLocaleHandler#initHandler(org.opencms.file.CmsObject)
1628     */
1629    public void initHandler(CmsObject cms) {
1630
1631        // initialize the workplace locale set
1632        m_locales = initWorkplaceLocales(cms);
1633    }
1634
1635    /**
1636     * Initializes the workplace manager with the OpenCms system configuration.<p>
1637     *
1638     * @param cms an OpenCms context object that must have been initialized with "Admin" permissions
1639     *
1640     * @throws CmsRoleViolationException if the provided OpenCms user context does
1641     *      not have <code>{@link CmsRole#WORKPLACE_MANAGER}</code> role permissions
1642     * @throws CmsException if something goes wrong
1643     */
1644    public synchronized void initialize(CmsObject cms) throws CmsException, CmsRoleViolationException {
1645
1646        try {
1647            // ensure that the current user has permissions to initialize the workplace
1648            OpenCms.getRoleManager().checkRole(cms, CmsRole.WORKPLACE_MANAGER);
1649
1650            // set the workplace encoding
1651            try {
1652                // workplace encoding is set on the workplace parent folder /system/workplace/
1653                CmsResource wpFolderRes = cms.readResource(CmsWorkplace.VFS_PATH_WORKPLACE);
1654                m_encoding = CmsLocaleManager.getResourceEncoding(cms, wpFolderRes);
1655            } catch (CmsVfsResourceNotFoundException e) {
1656                // workplace parent folder could not be read - use configured default encoding
1657                m_encoding = OpenCms.getSystemInfo().getDefaultEncoding();
1658            }
1659
1660            // configure direct edit provider with default if not available
1661            if (m_directEditProvider == null) {
1662                m_directEditProvider = new CmsDirectEditDefaultProvider();
1663            }
1664
1665            // throw away all currently configured module explorer types
1666            m_explorerTypeSettingsFromModules.clear();
1667            // now add the additional explorer types found in the modules
1668            CmsModuleManager moduleManager = OpenCms.getModuleManager();
1669            Iterator<String> moduleNameIterator = moduleManager.getModuleNames().iterator();
1670            while (moduleNameIterator.hasNext()) {
1671                CmsModule module = moduleManager.getModule(moduleNameIterator.next());
1672                if (module != null) {
1673                    addExplorerTypeSettings(module);
1674                }
1675            }
1676            // initialize the explorer type settings
1677            initExplorerTypeSettings();
1678            // initialize the workplace views
1679            initWorkplaceViews(cms);
1680            // initialize the workplace editor manager
1681            m_editorManager = new CmsWorkplaceEditorManager(cms);
1682            // initialize the locale handler
1683            initHandler(cms);
1684
1685            if (CmsLog.INIT.isInfoEnabled()) {
1686                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_ACCESS_INITIALIZED_0));
1687            }
1688            try {
1689                // read the temporary file project
1690                m_tempFileProject = cms.readProject(I_CmsProjectDriver.TEMP_FILE_PROJECT_NAME);
1691            } catch (CmsException e) {
1692                // during initial setup of OpenCms the temp file project does not yet exist...
1693                LOG.error(Messages.get().getBundle().key(Messages.LOG_NO_TEMP_FILE_PROJECT_0));
1694            }
1695            // create an instance of editor display options
1696            m_editorDisplayOptions = new CmsEditorDisplayOptions();
1697
1698            // throw away all current gallery settings
1699            m_galleries.clear();
1700            // read out the configured gallery classes
1701            Iterator<I_CmsResourceType> typesIterator = OpenCms.getResourceManager().getResourceTypes().iterator();
1702            while (typesIterator.hasNext()) {
1703                I_CmsResourceType resourceType = typesIterator.next();
1704                if (resourceType instanceof CmsResourceTypeFolderExtended) {
1705                    // found a configured extended folder resource type
1706                    CmsResourceTypeFolderExtended galleryType = (CmsResourceTypeFolderExtended)resourceType;
1707                    String folderClassName = galleryType.getFolderClassName();
1708                    if (CmsStringUtil.isNotEmpty(folderClassName)) {
1709                        // only process this as a gallery if the folder name is not empty
1710                        try {
1711                            // check, if the folder class is a subclass of A_CmsGallery
1712                            if (A_CmsAjaxGallery.class.isAssignableFrom(Class.forName(folderClassName))) {
1713                                // create gallery class instance
1714                                A_CmsAjaxGallery galleryInstance = (A_CmsAjaxGallery)Class.forName(
1715                                    folderClassName).newInstance();
1716                                // set gallery folder resource type
1717                                galleryInstance.setResourceType(galleryType);
1718                                // store the gallery class instance with the type name as lookup key
1719                                m_galleries.put(galleryType.getTypeName(), galleryInstance);
1720                            }
1721                        } catch (ClassNotFoundException e) {
1722                            LOG.error(e.getLocalizedMessage());
1723                        } catch (InstantiationException e) {
1724                            LOG.error(e.getLocalizedMessage());
1725                        } catch (IllegalAccessException e) {
1726                            LOG.error(e.getLocalizedMessage());
1727                        }
1728                    }
1729                }
1730            }
1731
1732            getDefaultUserSettings().initPreferences(this);
1733
1734            // configures the tool manager
1735            getToolManager().configure(cms);
1736
1737            flushMessageCache();
1738            getUploadRestriction().setAdminCmsObject(cms);
1739
1740            // register this object as event listener
1741            OpenCms.addCmsEventListener(this, new int[] {I_CmsEventListener.EVENT_CLEAR_CACHES});
1742        } catch (CmsException e) {
1743            if (LOG.isErrorEnabled()) {
1744                LOG.error(e.getLocalizedMessage(), e);
1745            }
1746            throw new CmsException(Messages.get().container(Messages.ERR_INITIALIZE_WORKPLACE_0));
1747        }
1748        m_adminCms = cms;
1749    }
1750
1751    /**
1752     * Returns the default property editing mode on resources.<p>
1753     *
1754     * @return the default property editing mode on resources
1755     */
1756    public boolean isDefaultPropertiesOnStructure() {
1757
1758        return m_defaultPropertiesOnStructure;
1759    }
1760
1761    /**
1762     * Returns a flag, indicating if the categories should be displayed separated by repository in the category selection dialog.
1763     *
1764     * @return a flag, indicating if the categories should be displayed separated by repository in the category selection dialog.
1765     */
1766    public boolean isDisplayCategoriesByRepository() {
1767
1768        return m_displayCategoriesByRepository;
1769    }
1770
1771    /**
1772     * Returns a flag, indicating if the category selection dialog should have all entries completely collapsed when opened.
1773     *
1774     * @return a flag, indicating if the category selection dialog should have all entries completely collapsed when opened.
1775     */
1776    public boolean isDisplayCategorySelectionCollapsed() {
1777
1778        return m_displayCategorySelectionCollapsed;
1779    }
1780
1781    /**
1782     * Returns if tabs in the advanced property dialog are enabled.<p>
1783     *
1784     * @return <code>true</code> if tabs should be enabled, otherwise <code>false</code>
1785     */
1786    public boolean isEnableAdvancedPropertyTabs() {
1787
1788        return m_enableAdvancedPropertyTabs;
1789    }
1790
1791    /**
1792     * Returns true if "keep alive" mode is active.
1793     *
1794     * @return true if the session should be kept alive
1795     */
1796    public boolean isKeepAlive() {
1797
1798        return isKeepAlive(true).booleanValue();
1799    }
1800
1801    /**
1802     * Returns true if the session should be kept alive.<p>
1803     *
1804     * @param useDefault if true, the default value will be returned if the "keep alive" setting is not explicitly configured
1805     *
1806     * @return True if the "keep alive" mode is active
1807     */
1808    public Boolean isKeepAlive(boolean useDefault) {
1809
1810        if (m_keepAlive != null) {
1811            return m_keepAlive;
1812        }
1813        if (useDefault) {
1814            return Boolean.TRUE;
1815        } else {
1816            return null;
1817        }
1818
1819    }
1820
1821    /**
1822     * Returns if XML content is automatically corrected when opened with the editor.<p>
1823     *
1824     * @return <code>true</code> if XML content is automatically corrected when opened with the editor, otherwise <code>false</code>
1825     */
1826    public boolean isXmlContentAutoCorrect() {
1827
1828        return m_xmlContentAutoCorrect;
1829    }
1830
1831    /**
1832     * Returns if lazy user lists are enabled.<p>
1833     *
1834     * @return <code>true</code> if lazy user lists are enabled
1835     */
1836    public boolean lazyUserListsEnabled() {
1837
1838        return true;
1839    }
1840
1841    /**
1842     * Removes the list of explorer type settings from the given module.<p>
1843     *
1844     * @param module the module witch contains the explorer type settings to remove
1845     */
1846    public void removeExplorerTypeSettings(CmsModule module) {
1847
1848        List<CmsExplorerTypeSettings> explorerTypes = module.getExplorerTypes();
1849        if ((explorerTypes != null) && (explorerTypes.size() > 0)) {
1850            Iterator<CmsExplorerTypeSettings> i = explorerTypes.iterator();
1851            while (i.hasNext()) {
1852                CmsExplorerTypeSettings settings = i.next();
1853                if (m_explorerTypeSettingsFromModules.contains(settings)) {
1854                    m_explorerTypeSettingsFromModules.remove(settings);
1855                    if (CmsLog.INIT.isInfoEnabled()) {
1856                        CmsLog.INIT.info(
1857                            Messages.get().getBundle().key(
1858                                Messages.INIT_REMOVE_EXPLORER_TYPE_SETTING_1,
1859                                settings.getName()));
1860                    }
1861                }
1862            }
1863            // reset the list of all explorer type settings
1864            initExplorerTypeSettings();
1865        }
1866    }
1867
1868    /**
1869     * Sets the value of the acacia-unlock configuration option.<p>
1870     *
1871     * @param value the value of the acacia-unlock configuration option
1872     */
1873    public void setAcaciaUnlock(String value) {
1874
1875        m_acaciaUnlock = value;
1876
1877    }
1878
1879    /**
1880     * Sets the additional log folder configuration.<p>
1881     *
1882     * @param logConfig the additional log folder configuration
1883     */
1884    public void setAdditionalLogFolderConfiguration(CmsAdditionalLogFolderConfig logConfig) {
1885
1886        m_logFolderConfig = logConfig;
1887    }
1888
1889    /**
1890     * Sets if the autolock resources feature is enabled.<p>
1891     *
1892     * @param value <code>"true"</code> if the autolock resources feature is enabled, otherwise false
1893     */
1894    public void setAutoLock(String value) {
1895
1896        m_autoLockResources = Boolean.valueOf(value).booleanValue();
1897        if (CmsLog.INIT.isInfoEnabled()) {
1898            CmsLog.INIT.info(
1899                Messages.get().getBundle().key(
1900                    m_autoLockResources ? Messages.INIT_AUTO_LOCK_ENABLED_0 : Messages.INIT_AUTO_LOCK_DISABLED_0));
1901        }
1902    }
1903
1904    /**
1905     * Sets the category display options that affect how the category selection dialog is shown.
1906     *
1907     * @param displayCategoriesByRepository if true, the categories are shown separated by repository.
1908     * @param displayCategorySelectionCollapsed if true, the selection dialog opens showing only the top-level categories
1909     *              (or the various repositories) in collapsed state.
1910     */
1911    public void setCategoryDisplayOptions(
1912        String displayCategoriesByRepository,
1913        String displayCategorySelectionCollapsed) {
1914
1915        m_displayCategoriesByRepository = Boolean.parseBoolean(displayCategoriesByRepository);
1916        m_displayCategorySelectionCollapsed = Boolean.parseBoolean(displayCategorySelectionCollapsed);
1917    }
1918
1919    /**
1920     * Sets the name of the local category folder(s).<p>
1921     *
1922     * @param categoryFolder the name of the local category folder(s)
1923     */
1924    public void setCategoryFolder(String categoryFolder) {
1925
1926        m_categoryFolder = categoryFolder;
1927    }
1928
1929    /**
1930     * Sets the access object of the type settings.<p>
1931     *
1932     * @param access access object
1933     */
1934    public void setDefaultAccess(CmsExplorerTypeAccess access) {
1935
1936        m_defaultAccess = access;
1937    }
1938
1939    /**
1940     * Sets the Workplace default locale.<p>
1941     *
1942     * @param locale the locale to set
1943     */
1944    public void setDefaultLocale(String locale) {
1945
1946        try {
1947            m_defaultLocale = CmsLocaleManager.getLocale(locale);
1948        } catch (Exception e) {
1949            if (CmsLog.INIT.isWarnEnabled()) {
1950                CmsLog.INIT.warn(Messages.get().getBundle().key(Messages.INIT_NONCRIT_ERROR_0), e);
1951            }
1952        }
1953        if (CmsLog.INIT.isInfoEnabled()) {
1954            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DEFAULT_LOCALE_1, m_defaultLocale));
1955        }
1956    }
1957
1958    /**
1959     * Sets the default property editing mode on resources.<p>
1960     *
1961     * @param defaultPropertiesOnStructure the default property editing mode on resources
1962     */
1963    public void setDefaultPropertiesOnStructure(String defaultPropertiesOnStructure) {
1964
1965        m_defaultPropertiesOnStructure = Boolean.valueOf(defaultPropertiesOnStructure).booleanValue();
1966        if (CmsLog.INIT.isInfoEnabled()) {
1967            CmsLog.INIT.info(
1968                Messages.get().getBundle().key(
1969                    m_defaultPropertiesOnStructure
1970                    ? Messages.INIT_PROP_ON_STRUCT_TRUE_0
1971                    : Messages.INIT_PROP_ON_STRUCT_FALSE_0));
1972        }
1973    }
1974
1975    /**
1976     * Sets the Workplace default user settings.<p>
1977     *
1978     * @param defaultUserSettings the user settings to set
1979     */
1980    public void setDefaultUserSettings(CmsDefaultUserSettings defaultUserSettings) {
1981
1982        m_defaultUserSettings = defaultUserSettings;
1983
1984        if (CmsLog.INIT.isInfoEnabled()) {
1985            CmsLog.INIT.info(
1986                Messages.get().getBundle().key(
1987                    Messages.INIT_DEFAULT_USER_SETTINGS_1,
1988                    m_defaultUserSettings.getClass().getName()));
1989        }
1990    }
1991
1992    /**
1993     * Sets the direct edit provider.<p>
1994     *
1995     * @param clazz the direct edit provider to set
1996     */
1997    public void setDirectEditProvider(I_CmsDirectEditProvider clazz) {
1998
1999        m_directEditProvider = clazz;
2000        if (CmsLog.INIT.isInfoEnabled()) {
2001            CmsLog.INIT.info(
2002                Messages.get().getBundle().key(
2003                    Messages.INIT_DIRECT_EDIT_PROVIDER_1,
2004                    m_directEditProvider.getClass().getName()));
2005        }
2006    }
2007
2008    /**
2009     * Sets the editor action class.<p>
2010     *
2011     * @param clazz the editor action class to set
2012     */
2013    public void setEditorAction(I_CmsEditorActionHandler clazz) {
2014
2015        m_editorAction = clazz;
2016        if (CmsLog.INIT.isInfoEnabled()) {
2017            CmsLog.INIT.info(
2018                Messages.get().getBundle().key(
2019                    Messages.INIT_EDITOR_ACTION_CLASS_1,
2020                    m_editorAction.getClass().getName()));
2021        }
2022    }
2023
2024    /**
2025     * Sets the editor display option class.<p>
2026     *
2027     * @param clazz the editor display option class to set
2028     */
2029    public void setEditorDisplayOptions(CmsEditorDisplayOptions clazz) {
2030
2031        m_editorDisplayOptions = clazz;
2032        if (CmsLog.INIT.isInfoEnabled()) {
2033            CmsLog.INIT.info(
2034                Messages.get().getBundle().key(
2035                    Messages.INIT_EDITOR_DISPLAY_OPTS_1,
2036                    m_editorAction.getClass().getName()));
2037        }
2038    }
2039
2040    /**
2041     * Sets the editor handler class.<p>
2042     *
2043     * @param clazz the editor handler class to set
2044     */
2045    public void setEditorHandler(I_CmsEditorHandler clazz) {
2046
2047        m_editorHandler = clazz;
2048        if (CmsLog.INIT.isInfoEnabled()) {
2049            CmsLog.INIT.info(
2050                Messages.get().getBundle().key(
2051                    Messages.INIT_EDITOR_HANDLER_CLASS_1,
2052                    m_editorHandler.getClass().getName()));
2053        }
2054    }
2055
2056    /**
2057     * Sets the element delete mode.<p>
2058     *
2059     * @param deleteMode the element delete mode
2060     */
2061    public void setElementDeleteMode(String deleteMode) {
2062
2063        try {
2064            m_elementDeleteMode = ElementDeleteMode.valueOf(deleteMode);
2065        } catch (Throwable t) {
2066            m_elementDeleteMode = ElementDeleteMode.askDelete;
2067        }
2068    }
2069
2070    /**
2071     * Sets if tabs in the advanced property dialog are enabled.<p>
2072     *
2073     * @param enableAdvancedPropertyTabs true if tabs should be enabled, otherwise false
2074     */
2075    public void setEnableAdvancedPropertyTabs(String enableAdvancedPropertyTabs) {
2076
2077        m_enableAdvancedPropertyTabs = Boolean.valueOf(enableAdvancedPropertyTabs).booleanValue();
2078        if (CmsLog.INIT.isInfoEnabled()) {
2079            CmsLog.INIT.info(
2080                Messages.get().getBundle().key(
2081                    m_enableAdvancedPropertyTabs
2082                    ? Messages.INIT_ADV_PROP_DIALOG_SHOW_TABS_0
2083                    : Messages.INIT_ADV_PROP_DIALOG_HIDE_TABS_0));
2084        }
2085    }
2086
2087    /**
2088     * Sets the value (in kb) for the maximum file upload size.<p>
2089     *
2090     * @param value the value (in kb) for the maximum file upload size
2091     */
2092    public void setFileMaxUploadSize(String value) {
2093
2094        try {
2095            m_fileMaxUploadSize = Integer.valueOf(value).intValue();
2096        } catch (NumberFormatException e) {
2097            // can usually be ignored
2098            if (LOG.isInfoEnabled()) {
2099                LOG.info(e.getLocalizedMessage());
2100            }
2101            m_fileMaxUploadSize = -1;
2102        }
2103        if (CmsLog.INIT.isInfoEnabled()) {
2104            if (m_fileMaxUploadSize > 0) {
2105                CmsLog.INIT.info(
2106                    Messages.get().getBundle().key(
2107                        Messages.INIT_MAX_FILE_UPLOAD_SIZE_1,
2108                        new Integer(m_fileMaxUploadSize)));
2109            } else {
2110                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_MAX_FILE_UPLOAD_SIZE_UNLIMITED_0));
2111            }
2112
2113        }
2114    }
2115
2116    /**
2117     * Sets the system-wide file view settings for the workplace.<p>
2118     *
2119     * @param cms the CmsObject for ensuring security constraints.
2120     *
2121     * @param fileViewSettings the system-wide file view settings for the workplace to set
2122     *
2123     * @throws CmsRoleViolationException if the current user does not own the administrator role ({@link CmsRole#ROOT_ADMIN})
2124     * */
2125    public void setFileViewSettings(CmsObject cms, CmsRfsFileViewer fileViewSettings) throws CmsRoleViolationException {
2126
2127        if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) {
2128            OpenCms.getRoleManager().checkRole(cms, CmsRole.ROOT_ADMIN);
2129        }
2130        m_fileViewSettings = fileViewSettings;
2131        // disallow modifications of this "new original"
2132        m_fileViewSettings.setFrozen(true);
2133    }
2134
2135    /**
2136     * Sets the gallery default scope.<p>
2137     *
2138     * @param galleryDefaultScope the gallery default scope
2139     */
2140    public void setGalleryDefaultScope(String galleryDefaultScope) {
2141
2142        m_galleryDefaultScope = galleryDefaultScope;
2143        try {
2144            CmsGallerySearchScope.valueOf(galleryDefaultScope);
2145        } catch (Throwable t) {
2146            LOG.warn(t.getLocalizedMessage(), t);
2147        }
2148    }
2149
2150    /**
2151     * Sets the group translation class name.<p>
2152     *
2153     * @param translationClassName the group translation class name
2154     */
2155    public void setGroupTranslationClass(String translationClassName) {
2156
2157        m_groupTranslationClass = translationClassName;
2158    }
2159
2160    /**
2161     * Sets the "keep alive" mode.<p>
2162     *
2163     * @param keepAlive the keep-alive mode
2164     */
2165    public void setKeepAlive(String keepAlive) {
2166
2167        m_keepAlive = Boolean.valueOf(keepAlive);
2168    }
2169
2170    /**
2171     * Sets the post upload dialog handler.<p>
2172     *
2173     * @param uploadHandler the post upload handler
2174     */
2175    public void setPostUploadHandler(I_CmsPostUploadDialogHandler uploadHandler) {
2176
2177        m_postUploadHandler = uploadHandler;
2178    }
2179
2180    /**
2181     * Sets the repository folder handler.<p>
2182     *
2183     * @param clazz the repository folder handler
2184     */
2185    public void setRepositoryFolderHandler(I_CmsRepositoryFolderHandler clazz) {
2186
2187        m_repositoryFolderHandler = clazz;
2188        if (CmsLog.INIT.isInfoEnabled()) {
2189            CmsLog.INIT.info(
2190                org.opencms.configuration.Messages.get().getBundle().key(
2191                    org.opencms.configuration.Messages.INIT_REPOSITORY_FOLDER_1,
2192                    m_repositoryFolderHandler.getClass().getName()));
2193        }
2194    }
2195
2196    /**
2197     * Sets the name of the role necessary for editing the sitemap configuration.
2198     *
2199     * @param roleName the name of the role necessary for editing the sitemap configuration
2200     */
2201    public void setSitemapConfigEditRole(String roleName) {
2202
2203        m_sitemapConfigEditRole = roleName;
2204    }
2205
2206    /**
2207     * Sets the tool Manager object.<p>
2208     *
2209     * @param toolManager the tool Manager object to set
2210     */
2211    public void setToolManager(CmsToolManager toolManager) {
2212
2213        m_toolManager = toolManager;
2214    }
2215
2216    /**
2217     * Sets the upload restriciton.
2218     *
2219     * @param uploadRestriction the upload restriction
2220     */
2221    public void setUploadRestriction(I_CmsUploadRestriction uploadRestriction) {
2222
2223        if (m_uploadRestrictionSet) {
2224            throw new IllegalStateException("Upload restriction has already been set.");
2225        }
2226        m_uploadRestriction = uploadRestriction;
2227        m_uploadRestrictionSet = true;
2228    }
2229
2230    /**
2231     * Sets the user additional information configuration manager.<p>
2232     *
2233     * @param userInfoManager the manager to set
2234     */
2235    public void setUserInfoManager(CmsWorkplaceUserInfoManager userInfoManager) {
2236
2237        m_userInfoManager = userInfoManager;
2238    }
2239
2240    /**
2241     * Sets the user list mode.<p>
2242     *
2243     * @param mode the user list mode
2244     */
2245    public void setUserListMode(String mode) {
2246
2247        m_userListMode = mode;
2248    }
2249
2250    /**
2251     * Controls if the user/group icon in the administration view should be shown.<p>
2252     *
2253     * @param value <code>"true"</code> if the user/group icon in the administration view should be shown, otherwise false
2254     */
2255    public void setUserManagementEnabled(String value) {
2256
2257        m_showUserGroupIcon = Boolean.valueOf(value).booleanValue();
2258        if (CmsLog.INIT.isInfoEnabled()) {
2259            if (m_showUserGroupIcon) {
2260                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_USER_MANAGEMENT_ICON_ENABLED_0));
2261            } else {
2262                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_USER_MANAGEMENT_ICON_DISABLED_0));
2263            }
2264        }
2265    }
2266
2267    /**
2268     * Sets the auto correction of XML contents when they are opened with the editor.<p>
2269     *
2270     * @param xmlContentAutoCorrect if "true", the content will be corrected without notification, otherwise a confirmation is needed
2271     */
2272    public void setXmlContentAutoCorrect(String xmlContentAutoCorrect) {
2273
2274        m_xmlContentAutoCorrect = Boolean.valueOf(xmlContentAutoCorrect).booleanValue();
2275        if (CmsLog.INIT.isInfoEnabled()) {
2276            CmsLog.INIT.info(
2277                Messages.get().getBundle().key(
2278                    m_xmlContentAutoCorrect
2279                    ? Messages.INIT_XMLCONTENT_AUTOCORRECT_ENABLED_0
2280                    : Messages.INIT_XMLCONTENT_AUTOCORRECT_DISABLED_0));
2281        }
2282    }
2283
2284    /**
2285     * Returns true if the Acacia editor in standalone mode should automatically unlock resources.<p>
2286     *
2287     * @return true if resources should be automatically unlocked in standalone mode
2288     */
2289    public boolean shouldAcaciaUnlock() {
2290
2291        if (m_acaciaUnlock == null) {
2292            return true;
2293        } else {
2294            return Boolean.parseBoolean(m_acaciaUnlock);
2295        }
2296    }
2297
2298    /**
2299     * Returns if the user/group icon in the administration view should be shown.<p>
2300     *
2301     * @return true if the user/group icon in the administration view should be shown, otherwise false
2302     */
2303    public boolean showUserGroupIcon() {
2304
2305        return m_showUserGroupIcon;
2306    }
2307
2308    /**
2309     * Returns true if lazy user lists should be used.<p>
2310     *
2311     * @return true if lazy user lists should be used
2312     */
2313    public boolean supportsLazyUserLists() {
2314
2315        boolean result = "lazy".equalsIgnoreCase(m_userListMode);
2316        if (org.opencms.db.mssql.CmsUserDriver.isInstantiated()) {
2317            LOG.warn("Lazy user lists currently not supported on MSSQL, using classic user list mode as a fallback.");
2318            result = false;
2319        }
2320        return result;
2321
2322    }
2323
2324    /**
2325     * Translates a group name using the configured {@link I_CmsGroupNameTranslation}.<p>
2326     *
2327     * @param groupName the group name
2328     * @param keepOu if true, the OU will be appended to the translated name
2329     *
2330     * @return the translated group name
2331     */
2332    public String translateGroupName(String groupName, boolean keepOu) {
2333
2334        I_CmsGroupNameTranslation translation = getGroupNameTranslation();
2335        return translation.translateGroupName(groupName, keepOu);
2336    }
2337
2338    /**
2339     * Gets the default view name ( = explorer type) for the given type.<p>
2340     *
2341     * @param typeName a resource type name
2342     * @return the default view for the given type
2343     */
2344    String getDefaultView(String typeName) {
2345
2346        String result = m_defaultViewRules.getViewForType(typeName);
2347        if (result == null) {
2348            result = "view_other";
2349            try {
2350                if (OpenCms.getResourceManager().hasResourceType(typeName)
2351                    && OpenCms.getResourceManager().getResourceType(typeName).isFolder()) {
2352                    result = "view_folders";
2353                }
2354            } catch (CmsLoaderException e) {
2355                LOG.error(e.getLocalizedMessage(), e);
2356            }
2357        }
2358        return result;
2359    }
2360
2361    /**
2362     * Creates a copy of the admin cms object which is initialize with the data of the current cms object.<p>
2363     *
2364     * @param cms the current cms object
2365     * @return the new admin cms object
2366     *
2367     * @throws CmsException if something goes wrong
2368     */
2369    private CmsObject getAdminCms(CmsObject cms) throws CmsException {
2370
2371        CmsObject adminCms = OpenCms.initCmsObject(m_adminCms);
2372        adminCms.getRequestContext().setSiteRoot(cms.getRequestContext().getSiteRoot());
2373        adminCms.getRequestContext().setRequestTime(cms.getRequestContext().getRequestTime());
2374        adminCms.getRequestContext().setCurrentProject(cms.getRequestContext().getCurrentProject());
2375        adminCms.getRequestContext().setEncoding(cms.getRequestContext().getEncoding());
2376        adminCms.getRequestContext().setUri(cms.getRequestContext().getUri());
2377        return adminCms;
2378    }
2379
2380    /**
2381     * Returns a dummy group name translation which leaves the group names unchanged.<p>
2382     *
2383     * @return a dummy group name translation
2384     */
2385    private I_CmsGroupNameTranslation getDefaultGroupNameTranslation() {
2386
2387        return new I_CmsGroupNameTranslation() {
2388
2389            public String translateGroupName(String group, boolean keepOu) {
2390
2391                return keepOu ? group : CmsOrganizationalUnit.getSimpleName(group);
2392            }
2393        };
2394    }
2395
2396    /**
2397     * Initializes the configured explorer type settings.<p>
2398     */
2399    private synchronized void initExplorerTypeSettings() {
2400
2401        Map<String, CmsExplorerTypeSettings> explorerTypeSettingsMap = new HashMap<String, CmsExplorerTypeSettings>();
2402        List<CmsExplorerTypeSettings> explorerTypeSettings = new ArrayList<CmsExplorerTypeSettings>();
2403
2404        if (m_defaultAccess.getAccessControlList() == null) {
2405            try {
2406                // initialize the default access control configuration
2407                m_defaultAccess.createAccessControlList(CmsExplorerTypeAccess.PRINCIPAL_DEFAULT);
2408            } catch (CmsException e) {
2409                if (CmsLog.INIT.isInfoEnabled()) {
2410                    CmsLog.INIT.info(
2411                        Messages.get().getBundle().key(
2412                            Messages.INIT_ADD_TYPE_SETTING_FAILED_1,
2413                            CmsExplorerTypeAccess.PRINCIPAL_DEFAULT),
2414                        e);
2415                }
2416            }
2417        }
2418
2419        explorerTypeSettings.addAll(m_explorerTypeSettingsFromXml);
2420        explorerTypeSettings.addAll(m_explorerTypeSettingsFromModules);
2421
2422        for (int i = 0; i < explorerTypeSettings.size(); i++) {
2423            CmsExplorerTypeSettings settings = explorerTypeSettings.get(i);
2424            // put the settings in the lookup map
2425            explorerTypeSettingsMap.put(settings.getName(), settings);
2426            if (getDefaultAccess() == settings.getAccess()) {
2427                continue;
2428            }
2429            try {
2430                // initialize the access control configuration of the explorer type
2431                settings.getAccess().createAccessControlList(settings.getName());
2432            } catch (CmsException e) {
2433                if (CmsLog.INIT.isInfoEnabled()) {
2434                    CmsLog.INIT.info(
2435                        Messages.get().getBundle().key(Messages.INIT_ADD_TYPE_SETTING_FAILED_1, settings.getName()),
2436                        e);
2437                }
2438            }
2439        }
2440        // sort the explorer type settings
2441        Collections.sort(explorerTypeSettings);
2442        // make the settings unmodifiable and store them in the global variables
2443        m_explorerTypeSettings = Collections.unmodifiableList(explorerTypeSettings);
2444        m_explorerTypeSettingsMap = Collections.unmodifiableMap(explorerTypeSettingsMap);
2445
2446        m_explorerTypeViews = Maps.newHashMap();
2447        Set<String> explorerTypeViews = Sets.newHashSet();
2448        for (CmsExplorerTypeSettings explorerType : getExplorerTypeSettings()) {
2449            if (explorerType.isView()) {
2450                explorerTypeViews.add(explorerType.getName());
2451            }
2452        }
2453
2454        for (String typeName : explorerTypeViews) {
2455            CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(typeName);
2456            CmsElementView elemView = new CmsElementView(explorerType);
2457            m_explorerTypeViews.put(elemView.getId(), elemView);
2458        }
2459
2460    }
2461
2462    /**
2463     * Initializes the workplace locale set.<p>
2464     *
2465     * Currently, this is defined by the existence of a special folder
2466     * <code>/system/workplace/locales/{locale-name}/</code>.
2467     * This is likely to change in future implementations.<p>
2468     *
2469     * @param cms an OpenCms context object that must have been initialized with "Admin" permissions
2470     *
2471     * @return the workplace locale set
2472     */
2473    private List<Locale> initWorkplaceLocales(CmsObject cms) {
2474
2475        Set<Locale> locales = new HashSet<Locale>();
2476
2477        // collect locales from the VFS
2478        if (cms.existsResource(CmsWorkplace.VFS_PATH_LOCALES)) {
2479            List<CmsResource> localeFolders;
2480            try {
2481                localeFolders = cms.getSubFolders(CmsWorkplace.VFS_PATH_LOCALES);
2482            } catch (CmsException e) {
2483                LOG.warn(
2484                    Messages.get().getBundle().key(
2485                        Messages.LOG_WORKPLACE_INIT_NO_LOCALES_1,
2486                        CmsWorkplace.VFS_PATH_LOCALES),
2487                    e);
2488                // can not throw exception here since then OpenCms would not even start in shell mode (runlevel 2)
2489                localeFolders = new ArrayList<CmsResource>();
2490            }
2491            Iterator<CmsResource> i = localeFolders.iterator();
2492            while (i.hasNext()) {
2493                CmsFolder folder = (CmsFolder)i.next();
2494                Locale locale = CmsLocaleManager.getLocale(folder.getName());
2495                // add locale
2496                locales.add(locale);
2497                // add less specialized locale
2498                locales.add(new Locale(locale.getLanguage(), locale.getCountry()));
2499                // add even less specialized locale
2500                locales.add(new Locale(locale.getLanguage()));
2501            }
2502        }
2503        // collect locales from JAR manifests
2504        try {
2505            Enumeration<URL> resources = getClass().getClassLoader().getResources(MANIFEST_RESOURCE_NAME);
2506
2507            while (resources.hasMoreElements()) {
2508                URL resUrl = resources.nextElement();
2509                try {
2510                    Manifest manifest = new Manifest(resUrl.openStream());
2511                    String localeString = manifest.getMainAttributes().getValue(LOCALIZATION_ATTRIBUTE_NAME);
2512                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(localeString)) {
2513                        Locale locale = CmsLocaleManager.getLocale(localeString);
2514                        // add locale
2515                        locales.add(locale);
2516                        // add less specialized locale
2517                        locales.add(new Locale(locale.getLanguage(), locale.getCountry()));
2518                        // add even less specialized locale
2519                        locales.add(new Locale(locale.getLanguage()));
2520                    }
2521                } catch (IOException e) {
2522                    LOG.warn(
2523                        "Error reading manifest from " + resUrl + " while evaluating available workplace localization.",
2524                        e);
2525                }
2526            }
2527        } catch (IOException e) {
2528            LOG.error("Error evaluating available workplace localization from JAR manifests.", e);
2529        }
2530
2531        // sort the result
2532        ArrayList<Locale> result = new ArrayList<Locale>();
2533        result.addAll(locales);
2534        Collections.sort(result, CmsLocaleComparator.getComparator());
2535        return result;
2536    }
2537
2538    /**
2539     * Initializes the available workplace views.<p>
2540     *
2541     * Currently, this is defined by iterating the subfolder of the folder
2542     * <code>/system/workplace/views/</code>.
2543     * These subfolders must have the properties NavPos, NavText and default-file set.<p>
2544     *
2545     * @param cms an OpenCms context object that must have been initialized with "Admin" permissions
2546     * @return the available workplace views
2547     */
2548    private List<CmsWorkplaceView> initWorkplaceViews(CmsObject cms) {
2549
2550        List<CmsResource> viewFolders;
2551        try {
2552            // get the subfolders of the "views" folder
2553            viewFolders = cms.getSubFolders(CmsWorkplace.VFS_PATH_VIEWS);
2554        } catch (CmsException e) {
2555            if ((OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) && LOG.isInfoEnabled()) {
2556                LOG.info(
2557                    Messages.get().getBundle().key(Messages.LOG_WORKPLACE_INIT_NO_VIEWS_1, CmsWorkplace.VFS_PATH_VIEWS),
2558                    e);
2559            }
2560            // can not throw exception here since then OpenCms would not even start in shell mode (runlevel 2)
2561            viewFolders = new ArrayList<CmsResource>();
2562        }
2563        m_views = new ArrayList<CmsWorkplaceView>(viewFolders.size());
2564        for (int i = 0; i < viewFolders.size(); i++) {
2565            // loop through all view folders
2566            CmsFolder folder = (CmsFolder)viewFolders.get(i);
2567            String folderPath = cms.getSitePath(folder);
2568            try {
2569                // get view information from folder properties
2570                String order = cms.readPropertyObject(
2571                    folderPath,
2572                    CmsPropertyDefinition.PROPERTY_NAVPOS,
2573                    false).getValue();
2574                String key = cms.readPropertyObject(
2575                    folderPath,
2576                    CmsPropertyDefinition.PROPERTY_NAVTEXT,
2577                    false).getValue();
2578                String viewUri = cms.readPropertyObject(
2579                    folderPath,
2580                    CmsPropertyDefinition.PROPERTY_DEFAULT_FILE,
2581                    false).getValue();
2582                if (viewUri == null) {
2583                    // no view URI found
2584                    viewUri = folderPath;
2585                } else if (!viewUri.startsWith("/")) {
2586                    // default file is in current view folder, create absolute path to view URI
2587                    viewUri = folderPath + viewUri;
2588                }
2589                if (order == null) {
2590                    // no valid NavPos property value found, use loop count as order value
2591                    order = "" + i;
2592                }
2593                Float orderValue;
2594                try {
2595                    // create Float order object
2596                    orderValue = Float.valueOf(order);
2597                } catch (NumberFormatException e) {
2598                    // String was not formatted correctly, use loop counter
2599                    orderValue = Float.valueOf(i);
2600                }
2601                if (key == null) {
2602                    // no language key found, use default String to avoid NullPointerException
2603                    key = "View " + i;
2604                    // if no navtext is given do not display the view
2605                    continue;
2606                }
2607                // create new view object
2608                CmsWorkplaceView view = new CmsWorkplaceView(key, viewUri, orderValue);
2609                m_views.add(view);
2610                // log the view
2611                if (CmsLog.INIT.isInfoEnabled()) {
2612                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_WORKPLACE_VIEW_1, view.getUri()));
2613                }
2614            } catch (CmsException e) {
2615                // should usually never happen
2616                LOG.error(Messages.get().getBundle().key(Messages.LOG_READING_VIEW_FOLDER_FAILED_1, folderPath), e);
2617            }
2618        }
2619        // sort the views by their order number
2620        Collections.sort(m_views);
2621        return m_views;
2622    }
2623}