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