org.opencms.site.CmsSiteManagerImpl 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.site;
import org.opencms.configuration.CmsConfigurationException;
import org.opencms.configuration.CmsSystemConfiguration;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.main.CmsContextInfo;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.CmsRuntimeException;
import org.opencms.main.OpenCms;
import org.opencms.security.CmsPermissionSet;
import org.opencms.security.CmsRole;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsStringUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import com.google.common.base.Optional;
/**
* Manages all configured sites in OpenCms.
*
* To obtain the configured site manager instance, use {@link OpenCms#getSiteManager()}.
*
* @since 7.0.2
*/
public final class CmsSiteManagerImpl {
/** The default shared folder name. */
public static final String DEFAULT_SHARED_FOLDER = "shared";
/** A placeholder for the title of the shared folder. */
public static final String SHARED_FOLDER_TITLE = "%SHARED_FOLDER%";
/** The static log object for this class. */
private static final Log LOG = CmsLog.getLog(CmsSiteManagerImpl.class);
/** The path to the "/sites/" folder. */
private static final String SITES_FOLDER = "/sites/";
/** The length of the "/sites/" folder plus 1. */
private static final int SITES_FOLDER_POS = SITES_FOLDER.length() + 1;
/** A list of additional site roots, that is site roots that are not below the "/sites/" folder. */
private List m_additionalSiteRoots;
/**
* The list of aliases for the site that is configured at the moment,
* needed for the sites added during configuration. */
private List m_aliases;
/** The default site root. */
private CmsSite m_defaultSite;
/** The default URI. */
private String m_defaultUri;
/** Indicates if the configuration is finalized (frozen). */
private boolean m_frozen;
/** The shared folder name. */
private String m_sharedFolder;
/** Contains all configured site matchers in a list for direct access. */
private List m_siteMatchers;
/** Maps site matchers to sites. */
private Map m_siteMatcherSites;
/** Temporary store for site parameter values. */
private SortedMap m_siteParams;
/** Maps site roots to sites. */
private Map m_siteRootSites;
/** The workplace site matchers. */
private List m_workplaceMatchers;
/** The workpace servers. */
private List m_workplaceServers;
/**
* Creates a new CmsSiteManager.
*
*/
public CmsSiteManagerImpl() {
m_siteMatcherSites = new HashMap();
m_siteRootSites = new HashMap();
m_aliases = new ArrayList();
m_siteParams = new TreeMap();
m_additionalSiteRoots = new ArrayList();
m_workplaceServers = new ArrayList();
m_workplaceMatchers = new ArrayList();
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_START_SITE_CONFIG_0));
}
}
/**
* Adds an alias to the currently configured site.
*
* @param alias the URL of the alias server
* @param offset the optional time offset for this alias
*/
public void addAliasToConfigSite(String alias, String offset) {
long timeOffset = 0;
try {
timeOffset = Long.parseLong(offset);
} catch (Throwable e) {
// ignore
}
CmsSiteMatcher siteMatcher = new CmsSiteMatcher(alias, timeOffset);
m_aliases.add(siteMatcher);
}
/**
* Adds a parameter to the currently configured site.
*
* @param name the parameter name
* @param value the parameter value
*/
public void addParamToConfigSite(String name, String value) {
m_siteParams.put(name, value);
}
/**
* Adds a site.
*
* @param cms the CMS object
* @param site the site to add
*
* @throws CmsException if something goes wrong
*/
public void addSite(CmsObject cms, CmsSite site) throws CmsException {
// check permissions
if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_1_CORE_OBJECT) {
// simple unit tests will have runlevel 1 and no CmsObject
OpenCms.getRoleManager().checkRole(cms, CmsRole.DATABASE_MANAGER);
}
// un-freeze
m_frozen = false;
// set aliases and parameters, they will be used in the addSite method
// this is necessary because of a digester workaround
m_siteParams = site.getParameters();
m_aliases = site.getAliases();
String secureUrl = null;
if (site.hasSecureServer()) {
secureUrl = site.getSecureUrl();
}
// add the site
addSite(
site.getUrl(),
site.getSiteRoot(),
site.getTitle(),
Float.toString(site.getPosition()),
site.getErrorPage(),
Boolean.toString(site.isWebserver()),
secureUrl,
Boolean.toString(site.isExclusiveUrl()),
Boolean.toString(site.isExclusiveError()),
Boolean.toString(site.usesPermanentRedirects()));
// re-initialize, will freeze the state when finished
initialize(cms);
OpenCms.writeConfiguration(CmsSystemConfiguration.class);
}
/**
* Adds a new CmsSite to the list of configured sites,
* this is only allowed during configuration.
*
* If this method is called after the configuration is finished,
* a RuntimeException
is thrown.
*
* @param server the Server
* @param uri the VFS path
* @param title the display title for this site
* @param position the display order for this site
* @param errorPage the URI to use as error page for this site
* @param webserver indicates whether to write the web server configuration for this site or not
* @param secureServer a secure server, can be null
* @param exclusive if set to true
, secure resources will only be available using the configured secure url
* @param error if exclusive, and set to true
will generate a 404 error,
* if set to false
will redirect to secure URL
* @param usePermanentRedirects if set to "true", permanent redirects should be used when redirecting to the secure URL
*
* @throws CmsConfigurationException if the site contains a server name, that is already assigned
*/
public void addSite(
String server,
String uri,
String title,
String position,
String errorPage,
String webserver,
String secureServer,
String exclusive,
String error,
String usePermanentRedirects)
throws CmsConfigurationException {
if (m_frozen) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_FROZEN_0));
}
if (getSiteRoots().contains(uri)) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SITE_ALREADY_CONFIGURED_1, uri));
}
if (CmsStringUtil.isEmptyOrWhitespaceOnly(server)) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_EMPTY_SERVER_URL_0));
}
// create a new site object
CmsSiteMatcher matcher = new CmsSiteMatcher(server);
CmsSite site = new CmsSite(uri, matcher);
// set the title
site.setTitle(title);
// set the position
if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(position)) {
float pos = Float.MAX_VALUE;
try {
pos = Float.parseFloat(position);
} catch (Throwable e) {
// m_position will have Float.MAX_VALUE, so this site will appear last
}
site.setPosition(pos);
}
// set the error page
site.setErrorPage(errorPage);
site.setWebserver(Boolean.valueOf(webserver).booleanValue());
// add the server(s)
addServer(matcher, site);
if (CmsStringUtil.isNotEmpty(secureServer)) {
matcher = new CmsSiteMatcher(secureServer);
site.setSecureServer(matcher);
site.setExclusiveUrl(Boolean.valueOf(exclusive).booleanValue());
site.setExclusiveError(Boolean.valueOf(error).booleanValue());
site.setUsePermanentRedirects(Boolean.valueOf(usePermanentRedirects).booleanValue());
addServer(matcher, site);
}
// note that Digester first calls the addAliasToConfigSite method.
// therefore, the aliases are already set
site.setAliases(m_aliases);
Iterator i = m_aliases.iterator();
while (i.hasNext()) {
matcher = i.next();
addServer(matcher, site);
}
m_aliases = new ArrayList();
site.setParameters(m_siteParams);
m_siteParams = new TreeMap();
m_siteRootSites = new HashMap(m_siteRootSites);
m_siteRootSites.put(site.getSiteRoot(), site);
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SITE_ROOT_ADDED_1, site.toString()));
}
}
/**
* Adds a workplace server, this is only allowed during configuration.
*
* @param workplaceServer the workplace server
*/
public void addWorkplaceServer(String workplaceServer) {
if (m_frozen) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_FROZEN_0));
}
if (!m_workplaceServers.contains(workplaceServer)) {
m_workplaceServers.add(workplaceServer);
}
}
/**
* Returns a list of all sites available (visible) for the current user.
*
* @param cms the current OpenCms user context
* @param workplaceMode if true, the root and current site is included for the admin user
* and the view permission is required to see the site root
*
* @return a list of all sites available for the current user
*/
public List getAvailableSites(CmsObject cms, boolean workplaceMode) {
return getAvailableSites(cms, workplaceMode, cms.getRequestContext().getOuFqn());
}
/**
* Returns a list of all {@link CmsSite} instances that are compatible to the given organizational unit.
*
* @param cms the current OpenCms user context
* @param workplaceMode if true, the root and current site is included for the admin user
* and the view permission is required to see the site root
* @param showShared if the shared folder should be shown
* @param ouFqn the organizational unit
*
* @return a list of all site available for the current user
*/
public List getAvailableSites(CmsObject cms, boolean workplaceMode, boolean showShared, String ouFqn) {
List siteroots = new ArrayList(m_siteMatcherSites.size() + 1);
Map siteServers = new HashMap(m_siteMatcherSites.size() + 1);
List result = new ArrayList(m_siteMatcherSites.size() + 1);
Iterator i;
// add site list
i = m_siteMatcherSites.keySet().iterator();
while (i.hasNext()) {
CmsSite site = m_siteMatcherSites.get(i.next());
String folder = CmsFileUtil.addTrailingSeparator(site.getSiteRoot());
if (!siteroots.contains(folder)) {
siteroots.add(folder);
siteServers.put(folder, site.getSiteMatcher());
}
}
// add default site
if (workplaceMode && (m_defaultSite != null)) {
String folder = CmsFileUtil.addTrailingSeparator(m_defaultSite.getSiteRoot());
if (!siteroots.contains(folder)) {
siteroots.add(folder);
}
}
String storedSiteRoot = cms.getRequestContext().getSiteRoot();
try {
// for all operations here we need no context
cms.getRequestContext().setSiteRoot("/");
if (workplaceMode && OpenCms.getRoleManager().hasRole(cms, CmsRole.VFS_MANAGER)) {
if (!siteroots.contains("/")) {
// add the root site if the user is in the workplace and has the required role
siteroots.add("/");
}
if (!siteroots.contains(CmsFileUtil.addTrailingSeparator(storedSiteRoot))) {
siteroots.add(CmsFileUtil.addTrailingSeparator(storedSiteRoot));
}
}
// add the shared site
String shared = OpenCms.getSiteManager().getSharedFolder();
if (showShared && (shared != null) && !siteroots.contains(shared)) {
siteroots.add(shared);
}
List resources;
try {
resources = OpenCms.getOrgUnitManager().getResourcesForOrganizationalUnit(cms, ouFqn);
} catch (CmsException e) {
return Collections.emptyList();
}
Collections.sort(siteroots); // sort by resource name
Iterator roots = siteroots.iterator();
while (roots.hasNext()) {
String folder = roots.next();
boolean compatible = false;
Iterator itResources = resources.iterator();
while (itResources.hasNext()) {
CmsResource resource = itResources.next();
if (resource.getRootPath().startsWith(folder) || folder.startsWith(resource.getRootPath())) {
compatible = true;
break;
}
}
// select only sites compatibles to the given organizational unit
if (compatible) {
try {
CmsResource res = cms.readResource(folder);
if (!workplaceMode
|| cms.hasPermissions(
res,
CmsPermissionSet.ACCESS_VIEW,
false,
CmsResourceFilter.ONLY_VISIBLE)) {
// get the title and the position from the system configuration first
CmsSite configuredSite = m_siteRootSites.get(CmsFileUtil.removeTrailingSeparator(folder));
// get the title
String title = null;
if ((configuredSite != null)
&& CmsStringUtil.isNotEmptyOrWhitespaceOnly(configuredSite.getTitle())) {
title = configuredSite.getTitle();
}
if (title == null) {
title = getSiteTitle(cms, res);
}
// get the position
String position = null;
if ((configuredSite != null) && (configuredSite.getPosition() != Float.MAX_VALUE)) {
position = Float.toString(configuredSite.getPosition());
}
if (position == null) {
// not found, use the 'NavPos' property
position = cms.readPropertyObject(
res,
CmsPropertyDefinition.PROPERTY_NAVPOS,
false).getValue();
}
if (configuredSite != null) {
float pos = Float.MAX_VALUE;
try {
pos = Float.parseFloat(position);
} catch (Throwable e) {
// m_position will have Float.MAX_VALUE, so this site will appear last
}
CmsSite clone = (CmsSite)configuredSite.clone();
clone.setPosition(pos);
clone.setTitle(title);
result.add(clone);
} else {
// add the site to the result
result.add(
new CmsSite(
folder,
res.getStructureId(),
title,
siteServers.get(folder),
position));
}
}
} catch (CmsException e) {
// user probably has no read access to the folder, ignore and continue iterating
}
}
}
// sort and ensure that the shared folder is the last element in the list
Collections.sort(result, new Comparator() {
public int compare(CmsSite o1, CmsSite o2) {
if (isSharedFolder(o1.getSiteRoot())) {
return +1;
}
if (isSharedFolder(o2.getSiteRoot())) {
return -1;
}
return o1.compareTo(o2);
}
});
} catch (Throwable t) {
LOG.error(Messages.get().getBundle().key(Messages.LOG_READ_SITE_PROP_FAILED_0), t);
} finally {
// restore the user's current context
cms.getRequestContext().setSiteRoot(storedSiteRoot);
}
return result;
}
/**
* Returns a list of all {@link CmsSite} instances that are compatible to the given organizational unit.
*
* @param cms the current OpenCms user context
* @param workplaceMode if true, the root and current site is included for the admin user
* and the view permission is required to see the site root
* @param ouFqn the organizational unit
*
* @return a list of all site available for the current user
*/
public List getAvailableSites(CmsObject cms, boolean workplaceMode, String ouFqn) {
return getAvailableSites(cms, workplaceMode, workplaceMode, ouFqn);
}
/**
* Returns the current site for the provided OpenCms user context object.
*
* In the unlikely case that no site matches with the provided OpenCms user context,
* the default site is returned.
*
* @param cms the OpenCms user context object to check for the site
*
* @return the current site for the provided OpenCms user context object
*/
public CmsSite getCurrentSite(CmsObject cms) {
CmsSite site = getSiteForSiteRoot(cms.getRequestContext().getSiteRoot());
return (site == null) ? m_defaultSite : site;
}
/**
* Returns the default site.
*
* @return the default site
*/
public CmsSite getDefaultSite() {
return m_defaultSite;
}
/**
* Returns the defaultUri.
*
* @return the defaultUri
*/
public String getDefaultUri() {
return m_defaultUri;
}
/**
* Returns the shared folder path.
*
* @return the shared folder path
*/
public String getSharedFolder() {
return m_sharedFolder;
}
/**
* Returns the site for the given resource path, using the fall back site root
* in case the resource path is no root path.
*
* In case neither the given resource path, nor the given fall back site root
* matches any configured site, the default site is returned.
*
* Usually the fall back site root should be taken from {@link org.opencms.file.CmsRequestContext#getSiteRoot()},
* in which case a site for the site root should always exist.
*
* This is the same as first calling {@link #getSiteForRootPath(String)} with the
* resourcePath
parameter, and if this fails calling
* {@link #getSiteForSiteRoot(String)} with the fallbackSiteRoot
parameter,
* and if this fails calling {@link #getDefaultSite()}.
*
* @param rootPath the resource root path to get the site for
* @param fallbackSiteRoot site root to use in case the resource path is no root path
*
* @return the site for the given resource path, using the fall back site root
* in case the resource path is no root path
*
* @see #getSiteForRootPath(String)
*/
public CmsSite getSite(String rootPath, String fallbackSiteRoot) {
CmsSite result = getSiteForRootPath(rootPath);
if (result == null) {
result = getSiteForSiteRoot(fallbackSiteRoot);
if (result == null) {
result = getDefaultSite();
}
}
return result;
}
/**
* Gets the site which is mapped to the default uri, or the 'absent' value of no such site exists.
*
* @return the optional site mapped to the default uri
*/
public Optional getSiteForDefaultUri() {
String defaultUri = getDefaultUri();
CmsSite candidate = m_siteRootSites.get(CmsFileUtil.removeTrailingSeparator(defaultUri));
return Optional.fromNullable(candidate);
}
/**
* Returns the site for the given resources root path,
* or null
if the resources root path does not match any site.
*
* @param rootPath the root path of a resource
*
* @return the site for the given resources root path,
* or null
if the resources root path does not match any site
*
* @see #getSiteForSiteRoot(String)
* @see #getSiteRoot(String)
*/
public CmsSite getSiteForRootPath(String rootPath) {
if ((rootPath.length() > 0) && !rootPath.endsWith("/")) {
rootPath = rootPath + "/";
}
// most sites will be below the "/sites/" folder,
CmsSite result = lookupSitesFolder(rootPath);
if (result != null) {
return result;
}
// look through all folders that are not below "/sites/"
String siteRoot = lookupAdditionalSite(rootPath);
return (siteRoot != null) ? getSiteForSiteRoot(siteRoot) : null;
}
/**
* Returns the site with has the provided site root,
* or null
if no configured site has that site root.
*
* The site root must have the form:
* /sites/default
.
* That means there must be a leading, but no trailing slash.
*
* @param siteRoot the site root to look up the site for
*
* @return the site with has the provided site root,
* or null
if no configured site has that site root
*
* @see #getSiteForRootPath(String)
*/
public CmsSite getSiteForSiteRoot(String siteRoot) {
return m_siteRootSites.get(siteRoot);
}
/**
* Returns the site root part for the given resources root path,
* or null
if the given resources root path does not match any site root.
*
* The site root returned will have the form:
* /sites/default
.
* That means there will a leading, but no trailing slash.
*
* @param rootPath the root path of a resource
*
* @return the site root part of the resources root path,
* or null
if the path does not match any site root
*
* @see #getSiteForRootPath(String)
*/
public String getSiteRoot(String rootPath) {
// add a trailing slash, because the path may be the path of a site root itself
if (!rootPath.endsWith("/")) {
rootPath = rootPath + "/";
}
// most sites will be below the "/sites/" folder,
CmsSite site = lookupSitesFolder(rootPath);
if (site != null) {
return site.getSiteRoot();
}
// look through all folders that are not below "/sites/"
return lookupAdditionalSite(rootPath);
}
/**
* Returns an unmodifiable set of all configured site roots (Strings).
*
* @return an unmodifiable set of all configured site roots (Strings)
*/
public Set getSiteRoots() {
return m_siteRootSites.keySet();
}
/**
* Returns the map of configured sites, using
* {@link CmsSiteMatcher} objects as keys and {@link CmsSite} objects as values.
*
* @return the map of configured sites, using {@link CmsSiteMatcher}
* objects as keys and {@link CmsSite} objects as values
*/
public Map getSites() {
return m_siteMatcherSites;
}
/**
* Returns the site title.
*
* @param cms the cms context
* @param resource the site root resource
*
* @return the title
*
* @throws CmsException in case reading the title property fails
*/
public String getSiteTitle(CmsObject cms, CmsResource resource) throws CmsException {
String title = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
if (title == null) {
title = resource.getRootPath();
}
if (resource.getRootPath().equals(getSharedFolder())) {
title = SHARED_FOLDER_TITLE;
}
return title;
}
/**
* Returns the workplace server.
*
* @return the workplace server
*/
public String getWorkplaceServer() {
return m_workplaceServers.isEmpty() ? null : m_workplaceServers.get(0);
}
/**
* Returns the configured worklace servers.
*
* @return the workplace servers
*/
public List getWorkplaceServers() {
return Collections.unmodifiableList(m_workplaceServers);
}
/**
* Returns the site matcher that matches the workplace site.
*
* @return the site matcher that matches the workplace site
*/
public CmsSiteMatcher getWorkplaceSiteMatcher() {
return m_workplaceMatchers.isEmpty() ? null : m_workplaceMatchers.get(0);
}
/**
* Initializes the site manager with the OpenCms system configuration.
*
* @param cms an OpenCms context object that must have been initialized with "Admin" permissions
*/
public void initialize(CmsObject cms) {
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(
Messages.get().getBundle().key(
Messages.INIT_NUM_SITE_ROOTS_CONFIGURED_1,
new Integer((m_siteMatcherSites.size() + ((m_defaultUri != null) ? 1 : 0)))));
}
CmsObject clone;
try {
clone = OpenCms.initCmsObject(cms);
clone.getRequestContext().setSiteRoot("");
// check the presence of sites in VFS
for (CmsSite site : m_siteMatcherSites.values()) {
try {
CmsResource siteRes = clone.readResource(site.getSiteRoot());
// during server startup the digester can not access properties, so set the title afterwards
if (CmsStringUtil.isEmptyOrWhitespaceOnly(site.getTitle())) {
String title = clone.readPropertyObject(
siteRes,
CmsPropertyDefinition.PROPERTY_TITLE,
false).getValue();
if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(title)) {
site.setTitle(title);
}
}
} catch (Throwable t) {
if (CmsLog.INIT.isWarnEnabled()) {
CmsLog.INIT.warn(Messages.get().getBundle().key(Messages.INIT_NO_ROOT_FOLDER_1, site));
}
}
}
// check the presence of the default site in VFS
if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_defaultUri)) {
m_defaultSite = null;
} else {
m_defaultSite = new CmsSite(m_defaultUri, CmsSiteMatcher.DEFAULT_MATCHER);
try {
clone.readResource(m_defaultSite.getSiteRoot());
} catch (Throwable t) {
if (CmsLog.INIT.isWarnEnabled()) {
CmsLog.INIT.warn(
Messages.get().getBundle().key(Messages.INIT_NO_ROOT_FOLDER_DEFAULT_SITE_1, m_defaultSite));
}
}
}
if (m_defaultSite == null) {
m_defaultSite = new CmsSite("/", CmsSiteMatcher.DEFAULT_MATCHER);
}
if (CmsLog.INIT.isInfoEnabled()) {
if (m_defaultSite != null) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DEFAULT_SITE_ROOT_1, m_defaultSite));
} else {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DEFAULT_SITE_ROOT_0));
}
}
if (!m_workplaceServers.isEmpty()) {
for (String server : m_workplaceServers) {
CmsSiteMatcher matcher = new CmsSiteMatcher(server);
m_workplaceMatchers.add(matcher);
if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_WORKPLACE_SITE_1, matcher));
}
}
} else if (CmsLog.INIT.isInfoEnabled()) {
CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_WORKPLACE_SITE_0));
}
// set site lists to unmodifiable
setSiteMatcherSites(m_siteMatcherSites);
// store additional site roots to optimize lookups later
for (String root : m_siteRootSites.keySet()) {
if (!root.startsWith(SITES_FOLDER)) {
m_additionalSiteRoots.add(root);
}
}
if (m_sharedFolder == null) {
m_sharedFolder = DEFAULT_SHARED_FOLDER;
}
// initialization is done, set the frozen flag to true
m_frozen = true;
} catch (CmsException e) {
LOG.warn(e);
}
}
/**
* Returns true
if the given site matcher matches any configured site,
* which includes the workplace site.
*
* @param matcher the site matcher to match the site with
*
* @return true
if the matcher matches a site
*/
public boolean isMatching(CmsSiteMatcher matcher) {
boolean result = m_siteMatcherSites.get(matcher) != null;
if (!result) {
// try to match the workplace site
result = isWorkplaceRequest(matcher);
}
return result;
}
/**
* Returns true
if the given site matcher matches the current site.
*
* @param cms the current OpenCms user context
* @param matcher the site matcher to match the site with
*
* @return true
if the matcher matches the current site
*/
public boolean isMatchingCurrentSite(CmsObject cms, CmsSiteMatcher matcher) {
return m_siteMatcherSites.get(matcher) == getCurrentSite(cms);
}
/**
* Checks if the given path is that of a shared folder.
*
* @param name a path prefix
*
* @return true if the given prefix represents a shared folder
*/
public boolean isSharedFolder(String name) {
return (m_sharedFolder != null) && m_sharedFolder.equals(CmsStringUtil.joinPaths("/", name, "/"));
}
/**
* Checks whether a given root path is a site root.
*
* @param rootPath a root path
*
* @return true if the given path is the path of a site root
*/
public boolean isSiteRoot(String rootPath) {
String siteRoot = getSiteRoot(rootPath);
rootPath = CmsStringUtil.joinPaths(rootPath, "/");
return rootPath.equals(siteRoot);
}
/**
* Returns true
if the given site matcher matches the configured OpenCms workplace.
*
* @param matcher the site matcher to match the site with
*
* @return true
if the given site matcher matches the configured OpenCms workplace
*/
public boolean isWorkplaceRequest(CmsSiteMatcher matcher) {
return m_workplaceMatchers.contains(matcher);
}
/**
* Returns true
if the given request is against the configured OpenCms workplace.
*
* @param req the request to match
*
* @return true
if the given request is against the configured OpenCms workplace
*/
public boolean isWorkplaceRequest(HttpServletRequest req) {
if (req == null) {
// this may be true inside a static export test case scenario
return false;
}
return isWorkplaceRequest(getRequestMatcher(req));
}
/**
* Matches the given request against all configures sites and returns
* the matching site, or the default site if no sites matches.
*
* @param req the request to match
*
* @return the matching site, or the default site if no sites matches
*/
public CmsSite matchRequest(HttpServletRequest req) {
CmsSiteMatcher matcher = getRequestMatcher(req);
if (matcher.getTimeOffset() != 0) {
HttpSession session = req.getSession();
if (session != null) {
session.setAttribute(
CmsContextInfo.ATTRIBUTE_REQUEST_TIME,
new Long(System.currentTimeMillis() + matcher.getTimeOffset()));
}
}
CmsSite site = matchSite(matcher);
if (LOG.isDebugEnabled()) {
String requestServer = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort();
LOG.debug(
Messages.get().getBundle().key(
Messages.LOG_MATCHING_REQUEST_TO_SITE_2,
requestServer,
site.toString()));
}
return site;
}
/**
* Return the configured site that matches the given site matcher,
* or the default site if no sites matches.
*
* @param matcher the site matcher to match the site with
* @return the matching site, or the default site if no sites matches
*/
public CmsSite matchSite(CmsSiteMatcher matcher) {
CmsSite site = m_siteMatcherSites.get(matcher);
if (site == null) {
// return the default site (might be null as well)
site = m_defaultSite;
}
return site;
}
/**
* Removes a site from the list of configured sites.
*
* @param cms the cms object
* @param site the site to remove
*
* @throws CmsException if something goes wrong
*/
public void removeSite(CmsObject cms, CmsSite site) throws CmsException {
// check permissions
if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_1_CORE_OBJECT) {
// simple unit tests will have runlevel 1 and no CmsObject
OpenCms.getRoleManager().checkRole(cms, CmsRole.DATABASE_MANAGER);
}
// un-freeze
m_frozen = false;
// create a new map containing all existing sites without the one to remove
Map siteMatcherSites = new HashMap();
for (Map.Entry entry : m_siteMatcherSites.entrySet()) {
// iterate over the existing sites
boolean isSite = site.getUrl().equals(entry.getKey().getUrl());
boolean isSecure = site.hasSecureServer() ? site.getSecureUrl().equals(entry.getKey().getUrl()) : false;
boolean isAlias = site.getAliases().contains(entry.getKey());
if (!(isSite || isSecure || isAlias)) {
// entry not the site itself nor an alias of the site nor the secure URL of the site, so add it
siteMatcherSites.put(entry.getKey(), entry.getValue());
}
}
setSiteMatcherSites(siteMatcherSites);
// remove the site from the map holding the site roots as keys and the sites as values
Map siteRootSites = new HashMap(m_siteRootSites);
siteRootSites.remove(site.getSiteRoot());
m_siteRootSites = Collections.unmodifiableMap(siteRootSites);
// re-initialize, will freeze the state when finished
initialize(cms);
OpenCms.writeConfiguration(CmsSystemConfiguration.class);
}
/**
* Sets the default URI, this is only allowed during configuration.
*
* If this method is called after the configuration is finished,
* a RuntimeException
is thrown.
*
* @param defaultUri the defaultUri to set
*/
public void setDefaultUri(String defaultUri) {
if (m_frozen) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_FROZEN_0));
}
m_defaultUri = defaultUri;
}
/**
* Sets the shared folder path.
*
* @param sharedFolder the shared folder path
*/
public void setSharedFolder(String sharedFolder) {
if (m_frozen) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_FROZEN_0));
}
m_sharedFolder = CmsStringUtil.joinPaths("/", sharedFolder, "/");
}
/**
* Returns true if the path starts with the shared folder path.
*
* @param path the path to check
*
* @return true if the path starts with the shared folder path
*/
public boolean startsWithShared(String path) {
return (m_sharedFolder != null) && CmsFileUtil.addTrailingSeparator(path).startsWith(m_sharedFolder);
}
/**
* Updates the general settings.
*
* @param cms the cms to use
* @param defaulrUri the default URI
* @param workplaceServer the workplace server URL
* @param sharedFolder the shared folder URI
*
* @throws CmsException if something goes wrong
*/
public void updateGeneralSettings(CmsObject cms, String defaulrUri, String workplaceServer, String sharedFolder)
throws CmsException {
CmsObject clone = OpenCms.initCmsObject(cms);
clone.getRequestContext().setSiteRoot("");
// set the shared folder
if ((sharedFolder == null)
|| sharedFolder.equals("")
|| sharedFolder.equals("/")
|| !sharedFolder.startsWith("/")
|| !sharedFolder.endsWith("/")
|| sharedFolder.startsWith("/sites/")) {
throw new CmsException(
Messages.get().container(Messages.ERR_INVALID_PATH_FOR_SHARED_FOLDER_1, sharedFolder));
}
m_frozen = false;
setDefaultUri(clone.readResource(defaulrUri).getRootPath());
setSharedFolder(clone.readResource(sharedFolder).getRootPath());
m_frozen = true;
}
/**
* Updates an existing site.
*
* @param cms the CMS object
* @param oldSite the site to remove if not null
* @param newSite the site to add if not null
*
* @throws CmsException if something goes wrong
*/
public void updateSite(CmsObject cms, CmsSite oldSite, CmsSite newSite) throws CmsException {
if (oldSite != null) {
// remove the old site
removeSite(cms, oldSite);
}
if (newSite != null) {
// add the new site
addSite(cms, newSite);
}
}
/**
* Returns true if this request goes to a secure site.
*
* @param req the request to check
*
* @return true if the request goes to a secure site
*/
public boolean usesSecureSite(HttpServletRequest req) {
CmsSite site = matchRequest(req);
if (site == null) {
return false;
}
CmsSiteMatcher secureMatcher = site.getSecureServerMatcher();
boolean result = false;
if (secureMatcher != null) {
result = secureMatcher.equals(getRequestMatcher(req));
}
return result;
}
/**
* Adds a new Site matcher object to the map of server names.
*
* @param matcher the SiteMatcher of the server
* @param site the site to add
*
* @throws CmsConfigurationException if the site contains a server name, that is already assigned
*/
private void addServer(CmsSiteMatcher matcher, CmsSite site) throws CmsConfigurationException {
if (m_siteMatcherSites.containsKey(matcher)) {
throw new CmsConfigurationException(
Messages.get().container(Messages.ERR_DUPLICATE_SERVER_NAME_1, matcher.getUrl()));
}
Map siteMatcherSites = new HashMap(m_siteMatcherSites);
siteMatcherSites.put(matcher, site);
setSiteMatcherSites(siteMatcherSites);
}
/**
* Returns the site matcher for the given request.
*
* @param req the request to get the site matcher for
*
* @return the site matcher for the given request
*/
private CmsSiteMatcher getRequestMatcher(HttpServletRequest req) {
CmsSiteMatcher matcher = new CmsSiteMatcher(req.getScheme(), req.getServerName(), req.getServerPort());
// this is required to get the right configured time offset
int index = m_siteMatchers.indexOf(matcher);
if (index < 0) {
return matcher;
}
return m_siteMatchers.get(index);
}
/**
* Returns true
if the given root path matches any of the stored additional sites.
*
* @param rootPath the root path to check
*
* @return true
if the given root path matches any of the stored additional sites
*/
private String lookupAdditionalSite(String rootPath) {
for (int i = 0, size = m_additionalSiteRoots.size(); i < size; i++) {
String siteRoot = m_additionalSiteRoots.get(i);
if (rootPath.startsWith(siteRoot)) {
return siteRoot;
}
}
return null;
}
/**
* Returns the configured site if the given root path matches site in the "/sites/" folder,
* or null
otherwise.
*
* @param rootPath the root path to check
*
* @return the configured site if the given root path matches site in the "/sites/" folder,
* or null
otherwise
*/
private CmsSite lookupSitesFolder(String rootPath) {
int pos = rootPath.indexOf('/', SITES_FOLDER_POS);
if (pos > 0) {
// this assumes that the root path may likely start with something like "/sites/default/"
// just cut the first 2 directories from the root path and do a direct lookup in the internal map
return m_siteRootSites.get(rootPath.substring(0, pos));
}
return null;
}
/**
* Sets the class member variables {@link #m_siteMatcherSites} and {@link #m_siteMatchers}
* from the provided map of configured site matchers.
*
* @param siteMatcherSites the site matches to set
*/
private void setSiteMatcherSites(Map siteMatcherSites) {
m_siteMatcherSites = Collections.unmodifiableMap(siteMatcherSites);
m_siteMatchers = Collections.unmodifiableList(new ArrayList(m_siteMatcherSites.keySet()));
}
}