org.opencms.loader.CmsResourceManager Maven / Gradle / Ivy
Show all versions of opencms-core Show documentation
/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH & Co. KG (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 & Co. KG, 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.loader;
import org.opencms.cache.CmsVfsMemoryObjectCache;
import org.opencms.configuration.CmsConfigurationException;
import org.opencms.configuration.CmsVfsConfiguration;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.collectors.I_CmsResourceCollector;
import org.opencms.file.types.CmsResourceTypeBinary;
import org.opencms.file.types.CmsResourceTypeFolder;
import org.opencms.file.types.CmsResourceTypePlain;
import org.opencms.file.types.CmsResourceTypeUnknownFile;
import org.opencms.file.types.CmsResourceTypeUnknownFolder;
import org.opencms.file.types.CmsResourceTypeXmlContent;
import org.opencms.file.types.I_CmsResourceType;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.module.CmsModule;
import org.opencms.module.CmsModuleManager;
import org.opencms.relations.CmsRelationType;
import org.opencms.security.CmsRole;
import org.opencms.security.CmsRoleViolationException;
import org.opencms.util.CmsDefaultSet;
import org.opencms.util.CmsHtmlConverter;
import org.opencms.util.CmsHtmlConverterJTidy;
import org.opencms.util.CmsHtmlConverterOption;
import org.opencms.util.CmsResourceTranslator;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.I_CmsHtmlConverter;
import org.opencms.workplace.CmsWorkplace;
import org.opencms.xml.CmsXmlContentDefinition;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
/**
* Collects all available resource loaders, resource types and resource collectors at startup and provides
* methods to access them during OpenCms runtime.
*
* @since 6.0.0
*/
public class CmsResourceManager {
/**
* Bean containing a template resource and the name of the template.
*/
public static class NamedTemplate {
/** The template name. */
private String m_name;
/** The template resource. */
private CmsResource m_resource;
/**
* Creates a new instance.
*
* @param resource the template resource
* @param name the template name
*/
public NamedTemplate(CmsResource resource, String name) {
m_resource = resource;
m_name = name;
}
/**
* Gets the template name.
*
* @return the template name
*/
public String getName() {
return m_name;
}
/**
* Gets the template resource.
*
* @return the template resource
*/
public CmsResource getResource() {
return m_resource;
}
}
/**
* Contains the part of the resource manager configuration that can be changed
* during runtime by the import / deletion of a module.
*
* A module can add resource types and extension mappings to resource types.
*/
static final class CmsResourceManagerConfiguration {
/** The mappings of file extensions to resource types. */
protected Map m_extensionMappings;
/** A list that contains all initialized resource types. */
protected List m_resourceTypeList;
/** A list that contains all initialized resource types, plus configured types for "unknown" resources. */
protected List m_resourceTypeListWithUnknown;
/** A map that contains all initialized resource types mapped to their type id. */
private Map m_resourceTypeIdMap;
/** A map that contains all initialized resource types mapped to their type name. */
private Map m_resourceTypeNameMap;
/**
* Creates a new resource manager data storage.
*/
protected CmsResourceManagerConfiguration() {
m_resourceTypeIdMap = new HashMap(128);
m_resourceTypeNameMap = new HashMap(128);
m_extensionMappings = new HashMap(128);
m_resourceTypeList = new ArrayList(32);
}
/**
* Adds a resource type to the list of configured resource types.
*
* @param type the resource type to add
*/
protected void addResourceType(I_CmsResourceType type) {
m_resourceTypeIdMap.put(Integer.valueOf(type.getTypeId()), type);
m_resourceTypeNameMap.put(type.getTypeName(), type);
m_resourceTypeList.add(type);
}
/**
* Freezes the current configuration by making all data structures unmodifiable
* that can be accessed form outside this class.
*
* @param restypeUnknownFolder the configured default resource type for unknown folders
* @param restypeUnknownFile the configured default resource type for unknown files
*/
protected void freeze(I_CmsResourceType restypeUnknownFolder, I_CmsResourceType restypeUnknownFile) {
// generate the resource type list with unknown resource types
m_resourceTypeListWithUnknown = new ArrayList(m_resourceTypeList.size() + 2);
if (restypeUnknownFolder != null) {
m_resourceTypeListWithUnknown.add(restypeUnknownFolder);
}
if (restypeUnknownFile != null) {
m_resourceTypeListWithUnknown.add(restypeUnknownFile);
}
m_resourceTypeListWithUnknown.addAll(m_resourceTypeList);
// freeze the current configuration
m_resourceTypeListWithUnknown = Collections.unmodifiableList(m_resourceTypeListWithUnknown);
m_resourceTypeList = Collections.unmodifiableList(m_resourceTypeList);
m_extensionMappings = Collections.unmodifiableMap(m_extensionMappings);
}
/**
* Returns the configured resource type with the matching type id, or null
* if a resource type with that id is not configured.
*
* @param typeId the type id to get the resource type for
*
* @return the configured resource type with the matching type id, or null
*/
protected I_CmsResourceType getResourceTypeById(int typeId) {
return m_resourceTypeIdMap.get(Integer.valueOf(typeId));
}
/**
* Returns the configured resource type with the matching type name, or null
* if a resource type with that name is not configured.
*
* @param typeName the type name to get the resource type for
*
* @return the configured resource type with the matching type name, or null
*/
protected I_CmsResourceType getResourceTypeByName(String typeName) {
return m_resourceTypeNameMap.get(typeName);
}
}
/** The path to the default template. */
public static final String DEFAULT_TEMPLATE = CmsWorkplace.VFS_PATH_COMMONS + "template/default.jsp";
/** The MIME type "text/html"
. */
public static final String MIMETYPE_HTML = "text/html";
/** The MIME type "text/plain"
. */
public static final String MIMETYPE_TEXT = "text/plain";
/** The log object for this class. */
private static final Log LOG = CmsLog.getLog(CmsResourceManager.class);
/** The map for all configured collector names, mapped to their collector class. */
private Map m_collectorNameMappings;
/** The list of all currently configured content collector instances. */
private List m_collectors;
/** The current resource manager configuration. */
private CmsResourceManagerConfiguration m_configuration;
/** The list of all configured HTML converters. */
private List m_configuredHtmlConverters;
/** The list of all configured MIME types. */
private List m_configuredMimeTypes;
/** The list of all configured relation types. */
private List m_configuredRelationTypes;
/** Filename translator, used only for the creation of new files. */
private CmsResourceTranslator m_fileTranslator;
/** Folder translator, used to translate all accesses to resources. */
private CmsResourceTranslator m_folderTranslator;
/** Indicates if the configuration is finalized (frozen). */
private boolean m_frozen;
/** The OpenCms map of configured HTML converters. */
private Map m_htmlConverters;
/** A list that contains all initialized resource loaders. */
private List m_loaderList;
/** All initialized resource loaders, mapped to their id. */
private I_CmsResourceLoader[] m_loaders;
/** The OpenCms map of configured MIME types. */
private Map m_mimeTypes;
/** The URL name generator for XML contents. */
private I_CmsFileNameGenerator m_nameGenerator = new CmsDefaultFileNameGenerator();
/** A list that contains all resource types added from the XML configuration. */
private List m_resourceTypesFromXml;
/** The configured default type for files when the resource type is missing. */
private I_CmsResourceType m_restypeUnknownFile;
/** The configured default type for folders when the resource type is missing. */
private I_CmsResourceType m_restypeUnknownFolder;
/** Cache for template names. */
private CmsVfsMemoryObjectCache m_templateNameCache = new CmsVfsMemoryObjectCache();
/** XSD translator, used to translate all accesses to XML schemas from Strings. */
private CmsResourceTranslator m_xsdTranslator;
/**
* Creates a new instance for the resource manager,
* will be called by the VFS configuration manager.
*/
public CmsResourceManager() {
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_STARTING_LOADER_CONFIG_0));
}
m_resourceTypesFromXml = new ArrayList();
m_loaders = new I_CmsResourceLoader[16];
m_loaderList = new ArrayList();
m_configuredMimeTypes = new ArrayList();
m_configuredRelationTypes = new ArrayList();
m_configuredHtmlConverters = new ArrayList();
}
/**
* Adds a given content collector class to the type manager.
*
* @param className the name of the class to add
* @param order the order number for this collector
*
* @return the created content collector instance
*
* @throws CmsConfigurationException in case the collector could not be properly initialized
*/
public synchronized I_CmsResourceCollector addContentCollector(String className, String order)
throws CmsConfigurationException {
Class> classClazz;
// init class for content collector
try {
classClazz = Class.forName(className);
} catch (ClassNotFoundException e) {
LOG.error(Messages.get().getBundle().key(Messages.LOG_CONTENT_COLLECTOR_CLASS_NOT_FOUND_1, className), e);
return null;
}
I_CmsResourceCollector collector;
try {
collector = (I_CmsResourceCollector)classClazz.newInstance();
} catch (InstantiationException e) {
throw new CmsConfigurationException(
Messages.get().container(Messages.ERR_INVALID_COLLECTOR_NAME_1, className));
} catch (IllegalAccessException e) {
throw new CmsConfigurationException(
Messages.get().container(Messages.ERR_INVALID_COLLECTOR_NAME_1, className));
} catch (ClassCastException e) {
throw new CmsConfigurationException(
Messages.get().container(Messages.ERR_INVALID_COLLECTOR_NAME_1, className));
}
// set the configured order for the collector
int ord = 0;
try {
ord = Integer.valueOf(order).intValue();
} catch (NumberFormatException e) {
LOG.error(Messages.get().getBundle().key(Messages.LOG_COLLECTOR_BAD_ORDER_NUMBER_1, className), e);
}
collector.setOrder(ord);
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_COLLECTOR_CLASS_2, className, order));
}
// extend or init the current list of configured collectors
if (m_collectors != null) {
m_collectors = new ArrayList(m_collectors);
m_collectorNameMappings = new HashMap(m_collectorNameMappings);
} else {
m_collectors = new ArrayList();
m_collectorNameMappings = new HashMap();
}
if (!m_collectors.contains(collector)) {
// this is a collector not currently configured
m_collectors.add(collector);
Iterator i = collector.getCollectorNames().iterator();
while (i.hasNext()) {
String name = i.next();
if (m_collectorNameMappings.containsKey(name)) {
// this name is already configured, check the order of the collector
I_CmsResourceCollector otherCollector = m_collectorNameMappings.get(name);
if (collector.getOrder() > otherCollector.getOrder()) {
// new collector has a greater order than the old collector in the Map
m_collectorNameMappings.put(name, collector);
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_COLLECTOR_REPLACED_1, name));
}
} else {
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(
Messages.get().getBundle().key(Messages.INIT_DUPLICATE_COLLECTOR_SKIPPED_1, name));
}
}
} else {
m_collectorNameMappings.put(name, collector);
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_COLLECTOR_1, name));
}
}
}
}
// ensure list is unmodifiable to avoid potential misuse or accidental changes
Collections.sort(m_collectors);
m_collectors = Collections.unmodifiableList(m_collectors);
m_collectorNameMappings = Collections.unmodifiableMap(m_collectorNameMappings);
// return the created collector instance
return collector;
}
/**
* Adds a new HTML converter class to internal list of loaded converter classes.
*
* @param name the name of the option that should trigger the HTML converter class
* @param className the name of the class to add
*
* @return the created HTML converter instance
*
* @throws CmsConfigurationException in case the HTML converter could not be properly initialized
*/
public I_CmsHtmlConverter addHtmlConverter(String name, String className) throws CmsConfigurationException {
// check if new conversion option can still be added
if (m_frozen) {
throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0));
}
Class> classClazz;
// init class for content converter
try {
classClazz = Class.forName(className);
} catch (ClassNotFoundException e) {
LOG.error(Messages.get().getBundle().key(Messages.LOG_HTML_CONVERTER_CLASS_NOT_FOUND_1, className), e);
return null;
}
I_CmsHtmlConverter converter;
try {
converter = (I_CmsHtmlConverter)classClazz.newInstance();
} catch (InstantiationException e) {
throw new CmsConfigurationException(
Messages.get().container(Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, className));
} catch (IllegalAccessException e) {
throw new CmsConfigurationException(
Messages.get().container(Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, className));
} catch (ClassCastException e) {
throw new CmsConfigurationException(
Messages.get().container(Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, className));
}
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_HTML_CONVERTER_CLASS_2, className, name));
}
m_configuredHtmlConverters.add(new CmsHtmlConverterOption(name, className));
return converter;
}
/**
* Adds a new loader to the internal list of loaded loaders.
*
* @param loader the loader to add
* @throws CmsConfigurationException in case the resource manager configuration is already initialized
*/
public void addLoader(I_CmsResourceLoader loader) throws CmsConfigurationException {
// check if new loaders can still be added
if (m_frozen) {
throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0));
}
// add the loader to the internal list of loaders
int pos = loader.getLoaderId();
if (pos >= m_loaders.length) {
I_CmsResourceLoader[] buffer = new I_CmsResourceLoader[pos * 2];
System.arraycopy(m_loaders, 0, buffer, 0, m_loaders.length);
m_loaders = buffer;
}
m_loaders[pos] = loader;
m_loaderList.add(loader);
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(
Messages.get().getBundle().key(
Messages.INIT_ADD_LOADER_2,
loader.getClass().getName(),
new Integer(pos)));
}
}
/**
* Adds a new MIME type from the XML configuration to the internal list of MIME types.
*
* @param extension the MIME type extension
* @param type the MIME type description
*
* @return the created MIME type instance
*
* @throws CmsConfigurationException in case the resource manager configuration is already initialized
*/
public CmsMimeType addMimeType(String extension, String type) throws CmsConfigurationException {
// check if new mime types can still be added
if (m_frozen) {
throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0));
}
CmsMimeType mimeType = new CmsMimeType(extension, type);
m_configuredMimeTypes.add(mimeType);
return mimeType;
}
/**
* Adds a new relation type from the XML configuration to the list of user defined relation types.
*
* @param name the name of the relation type
* @param type the type of the relation type, weak or strong
*
* @return the new created relation type instance
*
* @throws CmsConfigurationException in case the resource manager configuration is already initialized
*/
public CmsRelationType addRelationType(String name, String type) throws CmsConfigurationException {
// check if new relation types can still be added
if (m_frozen) {
throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0));
}
CmsRelationType relationType = new CmsRelationType(m_configuredRelationTypes.size(), name, type);
m_configuredRelationTypes.add(relationType);
return relationType;
}
/**
* Adds a new resource type from the XML configuration to the internal list of loaded resource types.
*
* Resource types can also be added from a module.
*
* @param resourceType the resource type to add
* @throws CmsConfigurationException in case the resource manager configuration is already initialized
*/
public void addResourceType(I_CmsResourceType resourceType) throws CmsConfigurationException {
// check if new resource types can still be added
if (m_frozen) {
throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0));
}
I_CmsResourceType conflictingType = null;
if (resourceType.getTypeId() == CmsResourceTypeUnknownFile.RESOURCE_TYPE_ID) {
// default unknown file resource type
if (m_restypeUnknownFile != null) {
// error: already set
conflictingType = m_restypeUnknownFile;
} else {
m_restypeUnknownFile = resourceType;
return;
}
} else if (resourceType.getTypeId() == CmsResourceTypeUnknownFolder.RESOURCE_TYPE_ID) {
// default unknown folder resource type
if (m_restypeUnknownFolder != null) {
// error: already set
conflictingType = m_restypeUnknownFolder;
} else {
m_restypeUnknownFolder = resourceType;
return;
}
} else {
// normal resource types
int conflictIndex = m_resourceTypesFromXml.indexOf(resourceType);
if (conflictIndex >= 0) {
conflictingType = m_resourceTypesFromXml.get(conflictIndex);
}
}
if (conflictingType != null) {
// configuration problem: the resource type (or at least the id or the name) is already configured
throw new CmsConfigurationException(
Messages.get().container(
Messages.ERR_CONFLICTING_RESOURCE_TYPES_4,
new Object[] {
resourceType.getTypeName(),
new Integer(resourceType.getTypeId()),
conflictingType.getTypeName(),
new Integer(conflictingType.getTypeId())}));
}
m_resourceTypesFromXml.add(resourceType);
}
/**
* Gets the map of forbidden contexts for resource types.
*
* @param cms the current CMS context
* @return the map from resource types to the forbidden contexts
*/
public Map> getAllowedContextMap(CmsObject cms) {
Map> result = new HashMap>();
for (I_CmsResourceType resType : getResourceTypes()) {
if (resType instanceof CmsResourceTypeXmlContent) {
String schema = null;
try {
schema = ((CmsResourceTypeXmlContent)resType).getSchema();
if (schema != null) {
CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema);
CmsDefaultSet allowedContexts = contentDefinition.getContentHandler().getAllowedTemplates();
result.put(resType.getTypeName(), allowedContexts);
} else {
LOG.info(
"No schema for XML type " + resType.getTypeName() + " / " + resType.getClass().getName());
}
} catch (Exception e) {
LOG.error(
"Error in getAllowedContextMap, schema="
+ schema
+ ", type="
+ resType.getTypeName()
+ ", "
+ e.getLocalizedMessage(),
e);
}
}
}
return result;
}
/**
* Returns the configured content collector with the given name, or null
if
* no collector with this name is configured.
*
* @param collectorName the name of the collector to get
* @return the configured content collector with the given name
*/
public I_CmsResourceCollector getContentCollector(String collectorName) {
return m_collectorNameMappings.get(collectorName);
}
/**
* Returns the default resource type for the given resource name, using the
* configured resource type file extensions.
*
* In case the given name does not map to a configured resource type,
* {@link CmsResourceTypePlain} is returned.
*
* This is only required (and should not be used otherwise) when
* creating a new resource automatically during file upload or synchronization.
* Only in this case, the file type for the new resource is determined using this method.
* Otherwise the resource type is always stored as part of the resource,
* and is not related to the file name.
*
* @param resourcename the resource name to look up the resource type for
*
* @return the default resource type for the given resource name
*
* @throws CmsException if something goes wrong
*/
public I_CmsResourceType getDefaultTypeForName(String resourcename) throws CmsException {
String typeName = null;
String suffix = null;
if (CmsStringUtil.isNotEmpty(resourcename)) {
int pos = resourcename.lastIndexOf('.');
if (pos >= 0) {
suffix = resourcename.substring(pos);
if (CmsStringUtil.isNotEmpty(suffix)) {
suffix = suffix.toLowerCase();
typeName = m_configuration.m_extensionMappings.get(suffix);
}
}
}
if (typeName == null) {
// use default type "plain"
typeName = CmsResourceTypePlain.getStaticTypeName();
}
if (CmsLog.INIT.isDebugEnabled()) {
CmsLog.INIT.debug(Messages.get().getBundle().key(Messages.INIT_GET_RESTYPE_2, typeName, suffix));
}
// look up and return the resource type
return getResourceType(typeName);
}
/**
* Returns the file extensions (suffixes) mappings to resource types.
*
* @return a Map with all known file extensions as keys and their resource types as values.
*/
public Map getExtensionMapping() {
return m_configuration.m_extensionMappings;
}
/**
* Returns the file translator.
*
* @return the file translator
*/
public CmsResourceTranslator getFileTranslator() {
return m_fileTranslator;
}
/**
* Returns the folder translator.
*
* @return the folder translator
*/
public CmsResourceTranslator getFolderTranslator() {
return m_folderTranslator;
}
/**
* Returns the matching HTML converter class name for the specified option name.
*
* @param name the name of the option that should trigger the HTML converter class
*
* @return the matching HTML converter class name for the specified option name or null
if no match is found
*/
public String getHtmlConverter(String name) {
return m_htmlConverters.get(name);
}
/**
* Returns an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects.
*
* @return an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects
*/
public List getHtmlConverters() {
return m_configuredHtmlConverters;
}
/**
* Returns the loader class instance for a given resource.
*
* @param resource the resource
* @return the appropriate loader class instance
* @throws CmsLoaderException if something goes wrong
*/
public I_CmsResourceLoader getLoader(CmsResource resource) throws CmsLoaderException {
return getLoader(getResourceType(resource.getTypeId()).getLoaderId());
}
/**
* Returns the loader class instance for the given loader id.
*
* @param id the id of the loader to return
* @return the loader class instance for the given loader id
*/
public I_CmsResourceLoader getLoader(int id) {
return m_loaders[id];
}
/**
* Returns the (unmodifiable array) list with all initialized resource loaders.
*
* @return the (unmodifiable array) list with all initialized resource loaders
*/
public List getLoaders() {
return m_loaderList;
}
/**
* Returns the MIME type for a specified file name.
*
* If an encoding parameter that is not null
is provided,
* the returned MIME type is extended with a ; charset={encoding}
setting.
*
* If no MIME type for the given filename can be determined, the
* default {@link #MIMETYPE_HTML}
is used.
*
* @param filename the file name to check the MIME type for
* @param encoding the default encoding (charset) in case of MIME types is of type "text"
*
* @return the MIME type for a specified file
*/
public String getMimeType(String filename, String encoding) {
return getMimeType(filename, encoding, MIMETYPE_HTML);
}
/**
* Returns the MIME type for a specified file name.
*
* If an encoding parameter that is not null
is provided,
* the returned MIME type is extended with a ; charset={encoding}
setting.
*
* If no MIME type for the given filename can be determined, the
* provided default is used.
*
* @param filename the file name to check the MIME type for
* @param encoding the default encoding (charset) in case of MIME types is of type "text"
* @param defaultMimeType the default MIME type to use if no matching type for the filename is found
*
* @return the MIME type for a specified file
*/
public String getMimeType(String filename, String encoding, String defaultMimeType) {
String mimeType = null;
int lastDot = filename.lastIndexOf('.');
// check the MIME type for the file extension
if ((lastDot > 0) && (lastDot < (filename.length() - 1))) {
mimeType = m_mimeTypes.get(filename.substring(lastDot).toLowerCase(Locale.ENGLISH));
}
if (mimeType == null) {
mimeType = defaultMimeType;
if (mimeType == null) {
// no default MIME type was provided
return null;
}
}
StringBuffer result = new StringBuffer(mimeType);
if ((encoding != null)
&& (mimeType.startsWith("text") || mimeType.endsWith("javascript"))
&& (mimeType.indexOf("charset") == -1)) {
result.append("; charset=");
result.append(encoding);
}
return result.toString();
}
/**
* Returns an unmodifiable List of the configured {@link CmsMimeType} objects.
*
* @return an unmodifiable List of the configured {@link CmsMimeType} objects
*/
public List getMimeTypes() {
return m_configuredMimeTypes;
}
/**
* Returns the name generator for XML content file names.
*
* @return the name generator for XML content file names.
*/
public I_CmsFileNameGenerator getNameGenerator() {
return m_nameGenerator;
}
/**
* Returns an (unmodifiable) list of class names of all currently registered content collectors
* ({@link I_CmsResourceCollector} objects).
*
* @return an (unmodifiable) list of class names of all currently registered content collectors
* ({@link I_CmsResourceCollector} objects)
*/
public List getRegisteredContentCollectors() {
return m_collectors;
}
/**
* Returns an unmodifiable List of the configured {@link CmsRelationType} objects.
*
* @return an unmodifiable List of the configured {@link CmsRelationType} objects
*/
public List getRelationTypes() {
return m_configuredRelationTypes;
}
/**
* Convenience method to get the initialized resource type instance for the given resource,
* with a fall back to special "unknown" resource types in case the resource type is not configured.
*
* @param resource the resource to get the type for
*
* @return the initialized resource type instance for the given resource
*/
public I_CmsResourceType getResourceType(CmsResource resource) {
I_CmsResourceType result = m_configuration.getResourceTypeById(resource.getTypeId());
if (result == null) {
// this resource type is unknown, return the default files instead
if (resource.isFolder()) {
// resource is a folder
if (m_restypeUnknownFolder != null) {
result = m_restypeUnknownFolder;
} else {
result = m_configuration.getResourceTypeByName(CmsResourceTypeFolder.getStaticTypeName());
}
} else {
// resource is a file
if (m_restypeUnknownFile != null) {
result = m_restypeUnknownFile;
} else {
result = m_configuration.getResourceTypeByName(CmsResourceTypeBinary.getStaticTypeName());
}
}
}
return result;
}
/**
* Returns the initialized resource type instance for the given id.
*
* @param typeId the id of the resource type to get
*
* @return the initialized resource type instance for the given id
*
* @throws CmsLoaderException if no resource type is available for the given id
*/
public I_CmsResourceType getResourceType(int typeId) throws CmsLoaderException {
I_CmsResourceType result = m_configuration.getResourceTypeById(typeId);
if (result == null) {
throw new CmsLoaderException(
Messages.get().container(Messages.ERR_UNKNOWN_RESTYPE_ID_REQ_1, new Integer(typeId)));
}
return result;
}
/**
* Returns the initialized resource type instance for the given resource type name.
*
* @param typeName the name of the resource type to get
*
* @return the initialized resource type instance for the given name
*
* @throws CmsLoaderException if no resource type is available for the given name
*/
public I_CmsResourceType getResourceType(String typeName) throws CmsLoaderException {
I_CmsResourceType result = m_configuration.getResourceTypeByName(typeName);
if (result != null) {
return result;
}
throw new CmsLoaderException(Messages.get().container(Messages.ERR_UNKNOWN_RESTYPE_NAME_REQ_1, typeName));
}
/**
* Returns the (unmodifiable) list with all initialized resource types.
*
* @return the (unmodifiable) list with all initialized resource types
*/
public List getResourceTypes() {
return m_configuration.m_resourceTypeList;
}
/**
* Returns the (unmodifiable) list with all initialized resource types including unknown types.
*
* @return the (unmodifiable) list with all initialized resource types including unknown types
*/
public List getResourceTypesWithUnknown() {
return m_configuration.m_resourceTypeListWithUnknown;
}
/**
* The configured default type for files when the resource type is missing.
*
* @return the configured default type for files
*/
public I_CmsResourceType getResTypeUnknownFile() {
return m_restypeUnknownFile;
}
/**
* The configured default type for folders when the resource type is missing.
*
* @return The configured default type for folders
*/
public I_CmsResourceType getResTypeUnknownFolder() {
return m_restypeUnknownFolder;
}
/**
* Returns a template loader facade for the given file.
* @param cms the current OpenCms user context
* @param resource the requested file
* @param templateProperty the property to read for the template
*
* @return a resource loader facade for the given file
* @throws CmsException if something goes wrong
*/
public CmsTemplateLoaderFacade getTemplateLoaderFacade(CmsObject cms, CmsResource resource, String templateProperty)
throws CmsException {
return getTemplateLoaderFacade(cms, null, resource, templateProperty);
}
/**
* Returns a template loader facade for the given file.
* @param cms the current OpenCms user context
* @param request the current request
* @param resource the requested file
* @param templateProperty the property to read for the template
*
* @return a resource loader facade for the given file
* @throws CmsException if something goes wrong
*/
public CmsTemplateLoaderFacade getTemplateLoaderFacade(
CmsObject cms,
HttpServletRequest request,
CmsResource resource,
String templateProperty)
throws CmsException {
String templateProp = cms.readPropertyObject(resource, templateProperty, true).getValue();
CmsTemplateContext templateContext = null;
String templateName = null;
if (templateProp == null) {
// use default template, if template is not set
templateProp = DEFAULT_TEMPLATE;
NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp);
if (namedTemplate == null) {
// no template property defined, this is a must for facade loaders
throw new CmsLoaderException(
Messages.get().container(Messages.ERR_NONDEF_PROP_2, templateProperty, cms.getSitePath(resource)));
}
templateName = namedTemplate.getName();
} else {
if (CmsTemplateContextManager.hasPropertyPrefix(templateProp)) {
templateContext = OpenCms.getTemplateContextManager().getTemplateContext(
templateProp,
cms,
request,
resource);
if (templateContext != null) {
templateProp = templateContext.getTemplatePath();
}
}
NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp);
if (namedTemplate == null) {
namedTemplate = readTemplateWithName(cms, DEFAULT_TEMPLATE);
if (namedTemplate != null) {
templateProp = DEFAULT_TEMPLATE;
templateName = namedTemplate.getName();
}
} else {
templateName = namedTemplate.getName();
}
}
CmsResource template = cms.readFile(templateProp, CmsResourceFilter.IGNORE_EXPIRATION);
CmsTemplateLoaderFacade result = new CmsTemplateLoaderFacade(getLoader(template), resource, template);
result.setTemplateContext(templateContext);
result.setTemplateName(templateName);
return result;
}
/**
* Returns the XSD translator.
*
* @return the XSD translator
*/
public CmsResourceTranslator getXsdTranslator() {
return m_xsdTranslator;
}
/**
* Checks if an initialized resource type instance equal to the given resource type is available.
*
* @param type the resource type to check
* @return true
if such a resource type has been configured, false
otherwise
*
* @see #getResourceType(String)
* @see #getResourceType(int)
*/
public boolean hasResourceType(I_CmsResourceType type) {
return hasResourceType(type.getTypeName());
}
/**
* Checks if an initialized resource type instance for the given resource type is is available.
*
* @param typeId the id of the resource type to check
* @return true
if such a resource type has been configured, false
otherwise
*
* @see #getResourceType(int)
*
* @deprecated
* Use {@link #hasResourceType(I_CmsResourceType)} or {@link #hasResourceType(I_CmsResourceType)} instead.
* Resource types should always be referenced either by its type class (preferred) or by type name.
* Use of int based resource type references will be discontinued in a future OpenCms release.
*/
@Deprecated
public boolean hasResourceType(int typeId) {
return m_configuration.getResourceTypeById(typeId) != null;
}
/**
* Checks if an initialized resource type instance for the given resource type name is available.
*
* @param typeName the name of the resource type to check
* @return true
if such a resource type has been configured, false
otherwise
*
* @see #getResourceType(String)
*/
public boolean hasResourceType(String typeName) {
return m_configuration.getResourceTypeByName(typeName) != null;
}
/**
* @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration()
*
* @throws CmsConfigurationException in case of duplicate resource types in the configuration
*/
public void initConfiguration() throws CmsConfigurationException {
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0));
}
m_resourceTypesFromXml = Collections.unmodifiableList(m_resourceTypesFromXml);
m_loaderList = Collections.unmodifiableList(m_loaderList);
Collections.sort(m_configuredMimeTypes);
m_configuredMimeTypes = Collections.unmodifiableList(m_configuredMimeTypes);
m_configuredRelationTypes = Collections.unmodifiableList(m_configuredRelationTypes);
// initialize the HTML converters
initHtmlConverters();
m_configuredHtmlConverters = Collections.unmodifiableList(m_configuredHtmlConverters);
// initialize the resource types
initResourceTypes();
// initialize the MIME types
initMimeTypes();
}
/**
* Initializes all additional resource types stored in the modules.
*
* @param cms an initialized OpenCms user context with "module manager" role permissions
*
* @throws CmsRoleViolationException in case the provided OpenCms user context did not have "module manager" role permissions
* @throws CmsConfigurationException in case of duplicate resource types in the configuration
*/
public synchronized void initialize(CmsObject cms) throws CmsRoleViolationException, CmsConfigurationException {
if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_1_CORE_OBJECT) {
// some simple test cases don't require this check
OpenCms.getRoleManager().checkRole(cms, CmsRole.DATABASE_MANAGER);
}
// initialize the resource types
initResourceTypes();
// call initialize method on all resource types
Iterator i = m_configuration.m_resourceTypeList.iterator();
while (i.hasNext()) {
I_CmsResourceType type = i.next();
type.initialize(cms);
}
// This only sets the CmsObject the first time it's called
m_nameGenerator.setAdminCms(cms);
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0));
}
}
/**
* Loads the requested resource and writes the contents to the response stream.
*
* @param req the current HTTP request
* @param res the current HTTP response
* @param cms the current OpenCms user context
* @param resource the requested resource
* @throws ServletException if something goes wrong
* @throws IOException if something goes wrong
* @throws CmsException if something goes wrong
*/
public void loadResource(CmsObject cms, CmsResource resource, HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException, CmsException {
res.setContentType(getMimeType(resource.getName(), cms.getRequestContext().getEncoding()));
I_CmsResourceLoader loader = getLoader(resource);
loader.load(cms, resource, req, res);
}
/**
* Checks if there is a resource type with a given name whose id matches the given id.
*
* This will return 'false' if no resource type with the given name is registered.
*
* @param name a resource type name
* @param id a resource type id
*
* @return true if a matching resource type with the given name and id was found
*/
public boolean matchResourceType(String name, int id) {
if (hasResourceType(name)) {
try {
return getResourceType(name).getTypeId() == id;
} catch (Exception e) {
// should never happen because we already checked with hasResourceType, still have to
// catch it so the compiler is happy
LOG.error(e.getLocalizedMessage(), e);
return false;
}
} else {
return false;
}
}
/**
* Configures the URL name generator for XML contents.
*
* @param nameGenerator the configured name generator class
*
* @throws CmsConfigurationException if something goes wrong
*/
public void setNameGenerator(I_CmsFileNameGenerator nameGenerator) throws CmsConfigurationException {
if (m_frozen) {
throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0));
}
m_nameGenerator = nameGenerator;
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(
Messages.get().getBundle().key(Messages.INIT_SET_NAME_GENERATOR_1, nameGenerator.getClass().getName()));
}
}
/**
* Sets the folder, the file and the XSD translator.
*
* @param folderTranslator the folder translator to set
* @param fileTranslator the file translator to set
* @param xsdTranslator the XSD translator to set
*/
public void setTranslators(
CmsResourceTranslator folderTranslator,
CmsResourceTranslator fileTranslator,
CmsResourceTranslator xsdTranslator) {
m_folderTranslator = folderTranslator;
m_fileTranslator = fileTranslator;
m_xsdTranslator = xsdTranslator;
}
/**
* Shuts down this resource manage instance.
*
* @throws Exception in case of errors during shutdown
*/
public synchronized void shutDown() throws Exception {
Iterator it = m_loaderList.iterator();
while (it.hasNext()) {
// destroy all resource loaders
I_CmsResourceLoader loader = it.next();
loader.destroy();
}
m_loaderList = null;
m_loaders = null;
m_collectorNameMappings = null;
m_mimeTypes = null;
m_configuredMimeTypes = null;
m_configuredRelationTypes = null;
m_configuredHtmlConverters = null;
m_htmlConverters = null;
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SHUTDOWN_1, this.getClass().getName()));
}
}
/**
* Gets the template name for a template resource, using a cache for efficiency.
*
* @param cms the current CMS context
* @param resource the template resource
* @return the template name
*
* @throws CmsException if something goes wrong
*/
private String getTemplateName(CmsObject cms, CmsResource resource) throws CmsException {
String templateName = (String)(m_templateNameCache.getCachedObject(cms, resource.getRootPath()));
if (templateName == null) {
CmsProperty nameProperty = cms.readPropertyObject(
resource,
CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
false);
String nameFromProperty = "";
if (!nameProperty.isNullProperty()) {
nameFromProperty = nameProperty.getValue();
}
m_templateNameCache.putCachedObject(cms, resource.getRootPath(), nameFromProperty);
return nameFromProperty;
} else {
return templateName;
}
}
/**
* Initialize the HTML converters.
*
* HTML converters are configured in the OpenCms opencms-vfs.xml
configuration file.
*
* For legacy reasons, the default JTidy HTML converter has to be loaded if no explicit HTML converters
* are configured in the configuration file.
*/
private void initHtmlConverters() {
// check if any HTML converter configuration were found
if (m_configuredHtmlConverters.size() == 0) {
// no converters configured, add default JTidy converter configuration
String classJTidy = CmsHtmlConverterJTidy.class.getName();
m_configuredHtmlConverters.add(
new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_ENABLED, classJTidy, true));
m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_XHTML, classJTidy, true));
m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_WORD, classJTidy, true));
m_configuredHtmlConverters.add(
new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_REPLACE_PARAGRAPHS, classJTidy, true));
}
// initialize lookup map of configured HTML converters
m_htmlConverters = new HashMap(m_configuredHtmlConverters.size());
for (Iterator i = m_configuredHtmlConverters.iterator(); i.hasNext();) {
CmsHtmlConverterOption converterOption = i.next();
m_htmlConverters.put(converterOption.getName(), converterOption.getClassName());
}
}
/**
* Initialize the MIME types.
*
* MIME types are configured in the OpenCms opencms-vfs.xml
configuration file.
*
* For legacy reasons, the MIME types are also read from a file "mimetypes.properties"
* that must be located in the default "classes"
folder of the web application.
*/
private void initMimeTypes() {
// legacy MIME type initialization: try to read properties file
Properties mimeTypes = new Properties();
try {
// first try: read MIME types from default package
mimeTypes.load(getClass().getClassLoader().getResourceAsStream("mimetypes.properties"));
} catch (Throwable t) {
try {
// second try: read MIME types from loader package (legacy reasons, there are no types by default)
mimeTypes.load(
getClass().getClassLoader().getResourceAsStream("org/opencms/loader/mimetypes.properties"));
} catch (Throwable t2) {
if (LOG.isInfoEnabled()) {
LOG.info(
Messages.get().getBundle().key(
Messages.LOG_READ_MIMETYPES_FAILED_2,
"mimetypes.properties",
"org/opencms/loader/mimetypes.properties"));
}
}
}
// initialize the Map with all available MIME types
List combinedMimeTypes = new ArrayList(
mimeTypes.size() + m_configuredMimeTypes.size());
// first add all MIME types from the configuration
combinedMimeTypes.addAll(m_configuredMimeTypes);
// now add the MIME types from the properties
Iterator> i = mimeTypes.entrySet().iterator();
while (i.hasNext()) {
Map.Entry