/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* For further information about Alkacon Software GmbH, please see the
* company website: http://www.alkacon.com
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.opencms.workplace.editors;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResourceFilter;
import org.opencms.jsp.CmsJspActionElement;
import org.opencms.jsp.CmsJspNavBuilder;
import org.opencms.jsp.CmsJspNavElement;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.util.CmsCollectionsGenericWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
/**
* Provides methods to determine the display options of a workplace editor for the current user.<p>
*
* On the editor JSP, do the following:
* <ul>
* <li>get the object instance with <code>OpenCms.getWorkplaceManager().getEditorDisplayOptions()</code>.</li>
* <li>get the Properties for the current user with <code>getDisplayOptions(CmsJspActionElement)</code>.</li>
* <li>use <code>showElement(key, Properties)</code> to determine if an element is shown.</li>
* </ul>
*
* Define your editor display options in property files located in the VFS folder
* <code>/system/workplace/editors/configuration/</code>.<p>
*
* Set navigation position property values on the configuration files
* and use the permission system to determine which groups and users
* should use which configuration file.<p>
*
* The configuration with the most enabled options should be the first in navigation,
* followed by configurations with less enabled options, because
* the first file readable for the current user will be used for configuration.<p>
*
* If no configuration file can be found for the current user,
* all display options will be disabled by default.<p>
*
* @since 6.0.0
*/
public class CmsEditorDisplayOptions {
/** The name of the configuration folder.<p> */
public static final String FOLDER_EDITORCONFIGURATION = CmsEditor.PATH_EDITORS + "configuration/";
/** Mapping entry name that is used if no mapping is available for the user.<p> */
public static final String NO_MAPPING_FOR_USER = "na";
/** Maximum size of the stored editor configurations.<p> */
public static final int SIZE_CONFIGURATIONFILES = 12;
/** Maximum size of the user editor configuration mappings.<p> */
public static final int SIZE_USERENTRIES = 100;
/** The log object for this class. */
private static final Log LOG = CmsLog.getLog(CmsEditorDisplayOptions.class);
/** Stores all loaded editor configuration options.<p> */
private Map m_loadedConfigurations;
/** Stores the mappings of users to their configuration options to use.<p> */
private Map m_userMappings;
/**
* Constructor that initializes the editor display options for the workplace.<p>
*/
public CmsEditorDisplayOptions() {
// initialize members
m_userMappings = CmsCollectionsGenericWrapper.createLRUMap(SIZE_USERENTRIES);
m_loadedConfigurations = CmsCollectionsGenericWrapper.createLRUMap(SIZE_CONFIGURATIONFILES);
}
/**
* Clears the cached user configuration data, casing a reload off all configurations.<p>
*/
public synchronized void clearCache() {
m_userMappings.clear();
m_loadedConfigurations.clear();
}
/**
* Reads the editor configuration file valid for the current user and caches the result in a Map.<p>
*
* The configuration settings of the found file are stored in a Map holding the loaded configuration
* with the configuration file name as key.<p>
*
* The configuration file name to use for the current user is stored in another Map with the user name
* as key.<p>
*
* @param jsp the JSP action element to access the VFS and current user information
* @return the display options to use for the current user or null if no display options were found
*/
public Properties getDisplayOptions(CmsJspActionElement jsp) {
return getDisplayOptions(jsp.getCmsObject());
}
/**
* Reads the editor configuration file valid for the current user and caches the result in a Map.<p>
*
* The configuration settings of the found file are stored in a Map holding the loaded configuration
* with the configuration file name as key.<p>
*
* The configuration file name to use for the current user is stored in another Map with the user name
* as key.<p>
*
* @param cms the CmsObject to access the VFS and current user information
* @return the display options to use for the current user or null if no display options were found
*/
public Properties getDisplayOptions(CmsObject cms) {
// get the configuration file name for the current user
String mappedConfigFile = (String)m_userMappings.get(cms.getRequestContext().getCurrentUser().getName());
Properties displayOptions;
if (mappedConfigFile == null) {
// no configuration file name stored for user, get the navigation items of the configuration folder
List items = new CmsJspNavBuilder(cms).getNavigationForFolder(FOLDER_EDITORCONFIGURATION);
if (items.size() > 0) {
// get first found configuration file
CmsJspNavElement nav = (CmsJspNavElement)items.get(0);
mappedConfigFile = nav.getFileName();
synchronized (m_loadedConfigurations) {
// must sync read/write access to shared map
displayOptions = (Properties)m_loadedConfigurations.get(nav.getFileName());
if (displayOptions == null) {
// configuration file has not yet been loaded, load it
try {
// read configuration file
CmsFile optionFile = cms.readFile(
nav.getResourceName(),
CmsResourceFilter.IGNORE_EXPIRATION);
InputStream in = new ByteArrayInputStream(optionFile.getContents());
displayOptions = new Properties();
displayOptions.load(in);
// store loaded options
m_loadedConfigurations.put(nav.getFileName(), displayOptions);
} catch (CmsException e) {
// set configuration to not available
if (LOG.isInfoEnabled()) {
LOG.info(e);
}
mappedConfigFile = NO_MAPPING_FOR_USER;
} catch (IOException e) {
// set configuration to not available
if (LOG.isInfoEnabled()) {
LOG.info(e);
}
mappedConfigFile = NO_MAPPING_FOR_USER;
displayOptions = null;
}
}
}
} else {
// no configuration available for current user, store this in mapping
mappedConfigFile = NO_MAPPING_FOR_USER;
displayOptions = null;
}
if (LOG.isDebugEnabled()) {
// check which mapping has been stored
LOG.debug(Messages.get().getBundle().key(
Messages.LOG_MAP_CONFIG_FILE_TO_USER_2,
mappedConfigFile,
cms.getRequestContext().getCurrentUser().getName()));
}
// store the file name of the configuration file for the current user
m_userMappings.put(cms.getRequestContext().getCurrentUser().getName(), mappedConfigFile);
} else {
// configuration file for current user is known, get options from loaded configurations
displayOptions = (Properties)m_loadedConfigurations.get(mappedConfigFile);
}
// return the editor display options for this user
return displayOptions;
}
/**
* Returns the value for the given key from the display options.<p>
*
* @param key he element key name which should be read
* @param defaultValue the default value to use in case the property is not found
* @param displayOptions the display options for the current user
*
* @return the value for the given key from the display options
*/
public String getOptionValue(String key, String defaultValue, Properties displayOptions) {
if (displayOptions == null) {
return defaultValue;
}
return displayOptions.getProperty(key, defaultValue);
}
/**
* Determines if the given element should be shown in the editor.<p>
*
* @param key the element key name which should be displayed
* @param displayOptions the display options for the current user
*
* @return true if the element should be shown, otherwise false
*/
public boolean showElement(String key, Properties displayOptions) {
return showElement(key, null, displayOptions);
}
/**
* Determines if the given element should be shown in the editor.<p>
*
* @param key the element key name which should be displayed
* @param defaultValue the default value to use in case the property is not found, should be a boolean value as String
* @param displayOptions the display options for the current user
*
* @return true if the element should be shown, otherwise false
*/
public boolean showElement(String key, String defaultValue, Properties displayOptions) {
if (defaultValue == null) {
return ((displayOptions != null) && Boolean.valueOf(displayOptions.getProperty(key)).booleanValue());
}
if (displayOptions == null) {
return Boolean.valueOf(defaultValue).booleanValue();
}
return Boolean.valueOf(displayOptions.getProperty(key, defaultValue)).booleanValue();
}
}