/*
* Weblounge: Web Content Management System
* Copyright (c) 2003 - 2011 The Weblounge Team
* http://entwinemedia.com/weblounge
*
* This program 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
* of the License, or (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package ch.entwine.weblounge.kernel.site;
import ch.entwine.weblounge.common.impl.util.WebloungeDateFormat;
import ch.entwine.weblounge.common.impl.util.config.ConfigurationUtils;
import ch.entwine.weblounge.common.repository.ContentRepository;
import ch.entwine.weblounge.common.security.SecurityService;
import ch.entwine.weblounge.common.site.Action;
import ch.entwine.weblounge.common.site.Environment;
import ch.entwine.weblounge.common.site.Module;
import ch.entwine.weblounge.common.site.Site;
import ch.entwine.weblounge.common.site.SiteListener;
import ch.entwine.weblounge.common.url.PathUtils;
import ch.entwine.weblounge.common.url.UrlUtils;
import ch.entwine.weblounge.dispatcher.ActionRequestHandler;
import ch.entwine.weblounge.dispatcher.DispatcherConfiguration;
import ch.entwine.weblounge.dispatcher.SharedHttpContext;
import ch.entwine.weblounge.dispatcher.SiteDispatcherService;
import ch.entwine.weblounge.kernel.http.WebXml;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
import org.osgi.service.prefs.PreferencesService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.WeakHashMap;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
/**
* The site dispatcher watches sites coming and going and registers them with
* the weblounge dispatcher.
*/
public class SiteDispatcherServiceImpl implements SiteDispatcherService, SiteListener, SiteServiceListener, ManagedService {
/** Logging facility */
private static final Logger logger = LoggerFactory.getLogger(SiteDispatcherServiceImpl.class);
/** Default value for the <code>WEBAPP_CONTEXT_ROOT</code> property */
public static final String DEFAULT_WEBAPP_CONTEXT_ROOT = "/";
/** Default value for the <code>BUNDLE_ROOT_URI</code> property */
public static final String DEFAULT_BUNDLE_CONTEXT_ROOT_URI = "/weblounge-sites";
/** Service pid, used to look up the service configuration */
public static final String SERVICE_PID = "ch.entwine.weblounge.sitedispatcher";
/** Configuration key prefix for jsp precompilation */
public static final String OPT_PRECOMPILE = "precompile";
/** Configuration key prefix for jsp precompilation logging */
public static final String OPT_PRECOMPILE_LOGGING = "precompile.logerrors";
/** Configuration key prefix for jasper configuration values */
public static final String OPT_JASPER_PREFIX = "jasper.";
/** Configuration option for jasper's scratch directory */
public static final String OPT_JASPER_SCRATCHDIR = "scratchdir";
/** Default value for jasper's <code>scratchDir</code> compiler context */
public static final String DEFAULT_JASPER_SCRATCH_DIR = "jasper";
/** Prefix for the precompilation date */
public static final String X_COMPILE_PREFIX = "X-COMPILE-";
/** Path to the scratch directory */
private String jasperScratchDir = null;
/** The action request handler */
private ActionRequestHandler actionRequestHandler = null;
/** The site manager */
private SiteManager siteManager = null;
/** The default environment */
private Environment environment = Environment.Production;
/** Init parameters for jetty */
private final TreeMap<String, String> jasperConfig = new TreeMap<String, String>();
/** Maps sites to site servlets */
private final Map<Site, SiteServlet> siteServlets = new HashMap<Site, SiteServlet>();
/** The site servlet registrations */
private Map<Site, ServiceRegistration> servletRegistrations = null;
/** The security service */
private SecurityService securityService = null;
/** The preferences service */
private PreferencesService preferencesService = null;
/** The precompiler for java server pages */
private boolean precompile = true;
/** Shutdown flag for running threads */
private boolean shutdown = false;
/** List of precompilers */
private final WeakHashMap<Site, Precompiler> precompilers = new WeakHashMap<Site, Precompiler>();
/** True to log errors that appear during precompilation */
private boolean logCompileErrors = false;
/**
* Callback for OSGi's declarative services component activation.
*
* @param context
* the component context
* @throws IOException
* if reading from the configuration admin service fails
* @throws ConfigurationException
* if service configuration fails
*/
void activate(ComponentContext context) throws IOException,
ConfigurationException {
BundleContext bundleContext = context.getBundleContext();
logger.info("Starting site dispatcher");
// Configure the jasper work directory where compiled java classes go
String tmpDir = System.getProperty("java.io.tmpdir");
jasperScratchDir = PathUtils.concat(tmpDir, DEFAULT_JASPER_SCRATCH_DIR);
jasperConfig.put(OPT_JASPER_SCRATCHDIR, jasperScratchDir);
// Try to get hold of the service configuration
ServiceReference configAdminRef = bundleContext.getServiceReference(ConfigurationAdmin.class.getName());
if (configAdminRef != null) {
ConfigurationAdmin configAdmin = (ConfigurationAdmin) bundleContext.getService(configAdminRef);
Dictionary<?, ?> config = configAdmin.getConfiguration(SERVICE_PID).getProperties();
if (config != null) {
configure(config);
} else {
logger.debug("No customized configuration for site dispatcher found");
}
} else {
logger.debug("No configuration admin service found while looking for site dispatcher configuration");
}
servletRegistrations = new HashMap<Site, ServiceRegistration>();
logger.debug("Site dispatcher activated");
// Register for changing sites
siteManager.addSiteListener(this);
// Process sites that have already been registered
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (Iterator<Site> si = siteManager.sites(); si.hasNext();) {
addSite(si.next());
}
}
});
t.setDaemon(true);
t.start();
}
/**
* Callback for OSGi's declarative services component dactivation.
*
* @param context
* the component context
* @throws Exception
* if component inactivation fails
*/
void deactivate(ComponentContext context) {
logger.debug("Deactivating site dispatcher");
// Don't listen to new sites anymore
siteManager.removeSiteListener(this);
// Tell everyone to finish their work
shutdown = true;
synchronized (servletRegistrations) {
servletRegistrations.notifyAll();
}
// Stop precompilers
for (Precompiler compiler : precompilers.values()) {
if (compiler.isRunning()) {
compiler.stop();
} else if (preferencesService != null) {
Preferences preferences = preferencesService.getSystemPreferences();
String date = WebloungeDateFormat.formatStatic(new Date());
preferences.put(compiler.getCompilerKey(), date);
try {
preferences.flush();
} catch (BackingStoreException e) {
logger.warn("Failed to store precompiler results: {}", e.getMessage());
}
} else if (preferencesService == null) {
logger.warn("Unable to store precompiler results: preference service unavailable");
}
}
logger.info("Site dispatcher stopped");
}
/**
* {@inheritDoc}
*
* @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
*/
public void updated(Dictionary properties) throws ConfigurationException {
if (properties == null)
return;
configure(properties);
}
/**
* Configures this service using the given configuration properties.
*
* @param config
* the service configuration
* @throws ConfigurationException
* if configuration fails
*/
private boolean configure(Dictionary<?, ?> config)
throws ConfigurationException {
logger.debug("Configuring the site registration service");
boolean configurationChanged = true;
// Activate precompilation?
String precompileSetting = StringUtils.trimToNull((String) config.get(OPT_PRECOMPILE));
precompile = precompileSetting == null || ConfigurationUtils.isTrue(precompileSetting);
logger.debug("Jsp precompilation {}", precompile ? "activated" : "deactivated");
// Log compilation errors?
String logPrecompileErrors = StringUtils.trimToNull((String) config.get(OPT_PRECOMPILE_LOGGING));
logCompileErrors = logPrecompileErrors != null && ConfigurationUtils.isTrue(logPrecompileErrors);
logger.debug("Precompilation errors will {} logged", logCompileErrors ? "be" : "not be");
// Store the jasper configuration keys
Enumeration<?> keys = config.keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
if (key.startsWith(OPT_JASPER_PREFIX) && key.length() > OPT_JASPER_PREFIX.length()) {
String value = (String) config.get(key);
if (StringUtils.trimToNull(value) == null)
continue;
value = ConfigurationUtils.processTemplate(value);
key = key.substring(OPT_JASPER_PREFIX.length());
boolean optionChanged = value.equalsIgnoreCase(jasperConfig.get(key));
configurationChanged |= !optionChanged;
if (optionChanged)
logger.debug("Jetty jsp parameter '{}' configured to '{}'", key, value);
jasperConfig.put(key, value);
// This is a work around for jasper's horrible implementation of the
// compiler context configuration. Some keys are camel case, others are
// lower case.
jasperConfig.put(key.toLowerCase(), value);
}
}
return configurationChanged;
}
/**
* Callback from the OSGi environment which registers the request handler with
* the site observer.
*
* @param handler
* the action request handler
*/
void setActionRequestHandler(ActionRequestHandler handler) {
logger.debug("Registering {}", handler);
this.actionRequestHandler = handler;
if (siteManager == null)
return;
for (Iterator<Site> si = siteManager.sites(); si.hasNext();) {
for (Module module : si.next().getModules()) {
for (Action action : module.getActions()) {
actionRequestHandler.register(action);
}
}
}
}
/**
* Callback from the OSGi environment which removes the action request handler
* from the site observer.
*
* @param handler
* the action request handler
*/
void removeActionRequestHandler(ActionRequestHandler handler) {
logger.debug("Unregistering {}", handler);
if (siteManager == null)
return;
for (Iterator<Site> si = siteManager.sites(); si.hasNext();) {
for (Module module : si.next().getModules()) {
for (Action action : module.getActions()) {
actionRequestHandler.unregister(action);
}
}
}
this.actionRequestHandler = null;
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.dispatcher.SiteDispatcherService#getSiteServlet(ch.entwine.weblounge.common.site.Site)
*/
public Servlet getSiteServlet(Site site) {
return siteServlets.get(site);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.dispatcher.SiteDispatcherService#findSiteByIdentifier(java.lang.String)
*/
public Site findSiteByIdentifier(String identifier) {
return siteManager.findSiteByIdentifier(identifier);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.dispatcher.SiteDispatcherService#findSiteByURL(java.lang.String)
*/
public Site findSiteByURL(URL siteURL) {
return siteManager.findSiteByURL(siteURL);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.dispatcher.SiteDispatcherService#findSiteByRequest(javax.servlet.http.HttpServletRequest)
*/
public Site findSiteByRequest(HttpServletRequest request) {
if (request == null)
throw new IllegalArgumentException("Request must not be null");
return findSiteByURL(UrlUtils.toURL(request, false, false));
}
/**
* Adds a new site.
*
* This method may be long-running and therefore is executed in its own
* thread.
*
* @param site
* the site
*/
private void addSite(final Site site) {
Thread t = new Thread(new Runnable() {
public void run() {
Bundle siteBundle = siteManager.getSiteBundle(site);
WebXml webXml = createWebXml(site, siteBundle);
Properties initParameters = new Properties();
// Prepare the init parameters
// initParameters.put("load-on-startup", Integer.toString(1));
initParameters.putAll(webXml.getContextParams());
initParameters.putAll(jasperConfig);
// Create the site URI
String contextRoot = webXml.getContextParam(DispatcherConfiguration.WEBAPP_CONTEXT_ROOT, DEFAULT_WEBAPP_CONTEXT_ROOT);
String bundleURI = webXml.getContextParam(DispatcherConfiguration.BUNDLE_URI, site.getIdentifier());
String siteContextURI = webXml.getContextParam(DispatcherConfiguration.BUNDLE_CONTEXT_ROOT_URI, DEFAULT_BUNDLE_CONTEXT_ROOT_URI);
String siteRoot = UrlUtils.concat(contextRoot, siteContextURI, bundleURI);
// Prepare the Jasper work directory
String scratchDirPath = PathUtils.concat(jasperConfig.get(OPT_JASPER_SCRATCHDIR), site.getIdentifier());
File scratchDir = new File(scratchDirPath);
boolean jasperArtifactsExist = scratchDir.isDirectory() && scratchDir.list().length > 0;
try {
FileUtils.forceMkdir(scratchDir);
logger.debug("Temporary jsp source files and classes go to {}", scratchDirPath);
} catch (IOException e) {
logger.warn("Unable to create jasper scratch directory at {}: {}", scratchDirPath, e.getMessage());
}
try {
// Create and register the site servlet
SiteServlet siteServlet = new SiteServlet(site, siteBundle, environment);
siteServlet.setSecurityService(securityService);
Dictionary<String, String> servletRegistrationProperties = new Hashtable<String, String>();
servletRegistrationProperties.put(Site.class.getName().toLowerCase(), site.getIdentifier());
servletRegistrationProperties.put(SharedHttpContext.ALIAS, siteRoot);
servletRegistrationProperties.put(SharedHttpContext.SERVLET_NAME, site.getIdentifier());
servletRegistrationProperties.put(SharedHttpContext.CONTEXT_ID, SharedHttpContext.WEBLOUNGE_CONTEXT_ID);
servletRegistrationProperties.put(SharedHttpContext.INIT_PREFIX + OPT_JASPER_SCRATCHDIR, scratchDirPath);
ServiceRegistration servletRegistration = siteBundle.getBundleContext().registerService(Servlet.class.getName(), siteServlet, servletRegistrationProperties);
servletRegistrations.put(site, servletRegistration);
// We are using the Whiteboard pattern to register servlets. Wait for
// the http service to pick up the servlet and initialize it
synchronized (servletRegistrations) {
boolean warnedOnce = false;
while (!siteServlet.isInitialized()) {
if (!warnedOnce) {
logger.info("Waiting for site '{}' to be online", site.getIdentifier());
warnedOnce = true;
}
logger.debug("Waiting for http service to pick up {}", siteServlet);
servletRegistrations.wait(500);
if (shutdown) {
logger.info("Giving up waiting for registration of site '{}'");
servletRegistrations.remove(site);
return;
}
}
}
siteServlets.put(site, siteServlet);
logger.info("Site '{}' is online and registered under site://{}", site, siteRoot);
// Did we already miss the "siteStarted()" event? If so, we trigger it
// for ourselves, so the modules are being started.
site.addSiteListener(SiteDispatcherServiceImpl.this);
if (site.isOnline()) {
siteStarted(site);
}
// Start the precompiler if requested
if (precompile) {
String compilationKey = X_COMPILE_PREFIX + siteBundle.getBundleId();
Date compileDate = null;
boolean needsCompilation = true;
// Check if this site has been precompiled already
if (preferencesService != null) {
Preferences preferences = preferencesService.getSystemPreferences();
String compileDateString = preferences.get(compilationKey, null);
if (compileDateString != null) {
compileDate = WebloungeDateFormat.parseStatic(compileDateString);
needsCompilation = false;
logger.info("Site '{}' has already been precompiled on {}", site.getIdentifier(), compileDate);
}
} else {
logger.info("Precompilation status cannot be determined, consider deploying a preferences service implementation");
}
// Does the scratch dir exist?
if (!jasperArtifactsExist) {
needsCompilation = true;
logger.info("Precompiled artifacts for '{}' have been removed", site.getIdentifier());
}
// Let's do the work anyways
if (needsCompilation) {
Precompiler precompiler = new Precompiler(compilationKey, siteServlet, environment, securityService, logCompileErrors);
precompilers.put(site, precompiler);
precompiler.precompile();
}
}
logger.debug("Site '{}' registered under site://{}", site, siteRoot);
} catch (Throwable t) {
logger.error("Error setting up site '{}' for http requests: {}", new Object[] {
site,
t.getMessage() });
logger.error(t.getMessage(), t);
}
}
});
t.setDaemon(true);
t.start();
}
/**
* Removes a site from the dispatcher.
*
* @param site
* the site to remove
*/
private void removeSite(Site site) {
// Remove site dispatcher servlet
ServiceRegistration servletRegistration = servletRegistrations.remove(site);
try {
servletRegistration.unregister();
} catch (IllegalStateException e) {
// Never mind, the service has been unregistered already
} catch (Throwable t) {
logger.error("Unregistering site '{}' failed: {}", site.getIdentifier(), t.getMessage());
}
// We are no longer interested in site events
site.removeSiteListener(this);
// Stop the site's precompiler
Precompiler compiler = precompilers.get(site);
if (compiler != null) {
if (compiler.isRunning()) {
compiler.stop();
} else if (preferencesService != null) {
Preferences preferences = preferencesService.getSystemPreferences();
String date = WebloungeDateFormat.formatStatic(new Date());
preferences.put(compiler.getCompilerKey(), date);
try {
preferences.flush();
} catch (BackingStoreException e) {
logger.warn("Failed to store precompiler results: {}", e.getMessage());
}
} else if (preferencesService == null) {
logger.warn("Unable to store precompiler results: preference service unavailable");
}
}
siteServlets.remove(site);
// TODO: unregister site dispatcher
logger.debug("Site {} unregistered", site);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.site.SiteListener#siteStarted(ch.entwine.weblounge.common.site.Site)
*/
public void siteStarted(Site site) {
if (actionRequestHandler != null) {
for (Module module : site.getModules()) {
for (Action action : module.getActions()) {
actionRequestHandler.register(action);
}
}
}
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.site.SiteListener#siteStopped(ch.entwine.weblounge.common.site.Site)
*/
public void siteStopped(Site site) {
if (actionRequestHandler != null) {
for (Module module : site.getModules()) {
for (Action action : module.getActions()) {
actionRequestHandler.unregister(action);
}
}
}
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.site.SiteListener#repositoryConnected(ch.entwine.weblounge.common.site.Site,
* ch.entwine.weblounge.common.repository.ContentRepository)
*/
public void repositoryConnected(Site site, ContentRepository repository) {
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.common.site.SiteListener#repositoryDisconnected(ch.entwine.weblounge.common.site.Site,
* ch.entwine.weblounge.common.repository.ContentRepository)
*/
public void repositoryDisconnected(Site site, ContentRepository repository) {
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.kernel.site.SiteServiceListener#siteAppeared(ch.entwine.weblounge.common.site.Site,
* org.osgi.framework.ServiceReference)
*/
public void siteAppeared(Site site, ServiceReference reference) {
addSite(site);
}
/**
* {@inheritDoc}
*
* @see ch.entwine.weblounge.kernel.site.SiteServiceListener#siteDisappeared(ch.entwine.weblounge.common.site.Site)
*/
public void siteDisappeared(Site site) {
removeSite(site);
}
/**
* Returns the <code>web.xml</code> representation that is used to register
* the site dispatcher servlets with the <code>HttpService</code>.
* <p>
* The method registers the following init parameters in the
* <code>web.xml</code> with appropriate default values:
* <ul>
* <li>weblounge.http.WEBAPP_CONTEXT_ROOT</li>
* <li>weblounge.http.BUNDLE_CONTEXT_ROOT</li>
* <li>weblounge.http.BUNDLE_CONTEXT_ROOT_URI</li>
* <li>weblounge.http.BUNDLE_NAME</li>
* <li>weblounge.http.BUNDLE_ROOT</li>
* <li>weblounge.http.BUNDLE_URI</li>
* <li>weblounge.http.BUNDLE_ENTRY</li>
* </ul>
* <p>
* <b>Note:</b> almost all of these properties can be overwritten using either
* the system properties or the service properties.
*/
public WebXml createWebXml(Site site, Bundle siteBundle) {
ServiceReference reference = null;
ServiceReference[] references = siteBundle.getRegisteredServices();
for (ServiceReference ref : references) {
if (site.equals(siteBundle.getBundleContext().getService(ref))) {
reference = ref;
break;
}
}
WebXml webXml = new WebXml();
webXml.addContextParam(DispatcherConfiguration.BUNDLE_NAME, siteBundle.getSymbolicName());
webXml.addContextParam(DispatcherConfiguration.BUNDLE_ENTRY, Site.BUNDLE_PATH);
// Webapp context root
String webappRoot = null;
if (reference != null && reference.getProperty(DispatcherConfiguration.WEBAPP_CONTEXT_ROOT) != null)
webappRoot = (String) reference.getProperty(DispatcherConfiguration.WEBAPP_CONTEXT_ROOT);
else if (System.getProperty(DispatcherConfiguration.WEBAPP_CONTEXT_ROOT) != null)
webappRoot = System.getProperty(DispatcherConfiguration.WEBAPP_CONTEXT_ROOT);
if (webappRoot == null)
webappRoot = DEFAULT_WEBAPP_CONTEXT_ROOT;
if (!webappRoot.startsWith("/"))
webappRoot = "/" + webappRoot;
webXml.addContextParam(DispatcherConfiguration.WEBAPP_CONTEXT_ROOT, webappRoot);
// Bundle name
webXml.addContextParam(DispatcherConfiguration.BUNDLE_NAME, siteBundle.getSymbolicName().toLowerCase());
// Bundle context root uri
String sitesRoot = null;
if (reference != null && reference.getProperty(DispatcherConfiguration.BUNDLE_CONTEXT_ROOT_URI) != null)
sitesRoot = (String) reference.getProperty(DispatcherConfiguration.BUNDLE_CONTEXT_ROOT_URI);
else if (System.getProperty(DispatcherConfiguration.BUNDLE_CONTEXT_ROOT_URI) != null)
sitesRoot = System.getProperty(DispatcherConfiguration.BUNDLE_CONTEXT_ROOT_URI);
if (sitesRoot == null)
sitesRoot = DEFAULT_BUNDLE_CONTEXT_ROOT_URI;
if (!sitesRoot.startsWith("/"))
sitesRoot = "/" + sitesRoot;
webXml.addContextParam(DispatcherConfiguration.BUNDLE_CONTEXT_ROOT_URI, sitesRoot);
// Bundle context root
sitesRoot = UrlUtils.concat(webappRoot, sitesRoot);
webXml.addContextParam(DispatcherConfiguration.BUNDLE_CONTEXT_ROOT, sitesRoot);
// Bundle uri
webXml.addContextParam(DispatcherConfiguration.BUNDLE_URI, site.getIdentifier());
// Bundle root
String bundleRoot = UrlUtils.concat(sitesRoot, site.getIdentifier());
webXml.addContextParam(DispatcherConfiguration.BUNDLE_ROOT, bundleRoot);
// Bundle entry
String bundleEntry = null;
if (reference != null && reference.getProperty(DispatcherConfiguration.BUNDLE_ENTRY) != null)
bundleEntry = (String) reference.getProperty(DispatcherConfiguration.BUNDLE_ENTRY);
else if (System.getProperty(DispatcherConfiguration.BUNDLE_ENTRY) != null)
bundleEntry = System.getProperty(DispatcherConfiguration.BUNDLE_ENTRY);
if (bundleEntry == null)
bundleEntry = Site.BUNDLE_PATH;
if (!bundleEntry.startsWith("/"))
bundleEntry = "/" + bundleEntry;
webXml.addContextParam(DispatcherConfiguration.BUNDLE_ENTRY, bundleEntry);
return webXml;
}
/**
* OSGi callback that will set the site manager.
*
* @param siteManager
* the site manager
*/
void setSiteManager(SiteManager siteManager) {
this.siteManager = siteManager;
}
/**
* OSGi callback that will unset the site manager.
*
* @param siteManager
* the site manager
*/
void removeSiteManager(SiteManager siteManager) {
this.siteManager = null;
}
/**
* Sets the default environment;
*
* @param environment
* the environment
*/
void setEnvironment(Environment environment) {
this.environment = environment;
for (SiteServlet servlet : siteServlets.values()) {
servlet.setEnvironment(environment);
}
}
/**
* Sets the security service.
*
* @param securityService
* the security service
*/
void setSecurityService(SecurityService securityService) {
this.securityService = securityService;
}
/**
* Sets the preferences service.
*
* @param preferencesService
* the OSGi preferences service
*/
void setPreferencesService(PreferencesService preferencesService) {
this.preferencesService = preferencesService;
}
}