/*
* Weblounge: Web Content Management System
* Copyright (c) 2011 The Weblounge Team
* http://weblounge.o2it.ch
*
* 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.endpoint;
import ch.entwine.weblounge.common.impl.language.LanguageUtils;
import ch.entwine.weblounge.common.language.Language;
import ch.entwine.weblounge.common.security.SecurityService;
import ch.entwine.weblounge.common.security.User;
import ch.entwine.weblounge.common.site.Environment;
import ch.entwine.weblounge.common.site.Site;
import ch.entwine.weblounge.common.url.UrlUtils;
import ch.entwine.weblounge.kernel.runtime.RuntimeInformationProvider;
import ch.entwine.weblounge.kernel.site.SiteManager;
import org.apache.commons.lang.StringUtils;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
/**
* This service provides runtime information to users of the system, such as
* <ul>
* <li>the<code>REST</code> services available for consumption</li>
* <li>the current user</li>
* <li>the current site</li>
* <li>mountpoint of shared resources</li>
* <li>mountpoint of the ui</li>
* </ul>
* <p>
* In addition, the service offers a plugin architecture which allows other
* system components to expose runtime information through this service.
*/
@Path("/")
public class RuntimeInformationEndpoint {
/** The sites that are online */
protected transient SiteManager sites = null;
/** List of runtime information provider */
protected Map<String, RuntimeInformationProvider> runtimeInfoProviders = null;
/** The security service */
protected SecurityService securityService = null;
/** The request environment */
protected Environment environment = Environment.Production;
/** The endpoint documentation */
private String docs = null;
/**
* Creates a new instance of the runtime information endpoint.
*/
public RuntimeInformationEndpoint() {
runtimeInfoProviders = new ConcurrentHashMap<String, RuntimeInformationProvider>();
}
/**
* Returns the runtime information.
*
* @return the runtime information
*/
@GET
@Path("/")
@Produces(MediaType.TEXT_XML)
public Response getRuntimeInformation(@Context HttpServletRequest request) {
StringBuffer xml = new StringBuffer();
xml.append("<runtime>");
if (sites != null) {
Site site = getSite(request);
User user = securityService.getUser();
Language language = LanguageUtils.getPreferredLanguage(request, site);
for (Map.Entry<String, RuntimeInformationProvider> entry : runtimeInfoProviders.entrySet()) {
String component = entry.getKey();
RuntimeInformationProvider provider = entry.getValue();
String runtimeInformation = provider.getRuntimeInformation(site, user, language, environment);
if (StringUtils.isNotBlank(runtimeInformation)) {
if (StringUtils.isNotBlank(component))
xml.append("<").append(component).append(">");
xml.append(runtimeInformation);
if (StringUtils.isNotBlank(component))
xml.append("</").append(component).append(">");
}
}
}
xml.append("</runtime>");
return Response.ok(xml.toString()).build();
}
/**
* Returns the runtime information for a given component.
*
* @return the runtime information
*/
@GET
@Path("/{component}")
@Produces(MediaType.TEXT_XML)
public Response getRuntimeInformationComponent(
@Context HttpServletRequest request,
@PathParam("component") String component) {
StringBuffer xml = new StringBuffer();
xml.append("<runtime>");
if (sites != null) {
Site site = getSite(request);
User user = securityService.getExtendedUser();
Language language = LanguageUtils.getPreferredLanguage(request, site);
RuntimeInformationProvider provider = runtimeInfoProviders.get(component);
if (provider == null)
throw new WebApplicationException(Status.NOT_FOUND);
String runtimeInformation = provider.getRuntimeInformation(site, user, language, environment);
if (StringUtils.isNotBlank(runtimeInformation)) {
xml.append("<").append(component).append(">");
xml.append(runtimeInformation);
xml.append("</").append(component).append(">");
} else {
xml.append("<").append(component).append("/>");
}
}
xml.append("</runtime>");
return Response.ok(xml.toString()).build();
}
/**
* Returns the endpoint documentation.
*
* @return the endpoint documentation
*/
@GET
@Path("/docs")
@Produces(MediaType.TEXT_HTML)
public String getDocumentation(@Context HttpServletRequest request) {
if (docs == null) {
String docsPath = request.getRequestURI();
String docsPathExtension = request.getPathInfo();
String servicePath = request.getRequestURI().substring(0, docsPath.length() - docsPathExtension.length());
docs = RuntimeInformationEndpointDocs.createDocumentation(servicePath);
}
return docs;
}
/**
* Extracts the site from the request and returns it. If the site is not found
* or it's not running, a corresponding <code>WebApplicationException</code>
* is thrown.
*
* @param request
* the http request
* @return the site
* @throws WebApplicationException
* if the site is not found or is not running
*/
protected Site getSite(HttpServletRequest request)
throws WebApplicationException {
URL url = UrlUtils.toURL(request, false, false);
Site site = sites.findSiteByURL(url);
if (site == null) {
throw new WebApplicationException(Status.NOT_FOUND);
} else if (!site.isOnline()) {
throw new WebApplicationException(Status.SERVICE_UNAVAILABLE);
}
return site;
}
/**
* Callback for OSGi to set the site manager.
*
* @param siteManager
* the site manager
*/
void setSiteManager(SiteManager siteManager) {
this.sites = siteManager;
}
/**
* Callback for OSGi to remove the site manager.
*
* @param siteManager
* the site manager
*/
void removeSiteManager(SiteManager siteManager) {
this.sites = null;
}
/**
* Callback for OSGi to add a runtime information provider.
*
* @param provider
* the runtime information provider
*/
void addRuntimeInformationProvider(RuntimeInformationProvider provider) {
String component = provider.getComponentId();
if (StringUtils.isBlank(component))
throw new IllegalStateException("Runtime component identifier of " + provider + " is null");
runtimeInfoProviders.put(component, provider);
}
/**
* Callback for OSGi to remove a runtime information provider.
*
* @param provider
* the runtime information provider
*/
void removeRuntimeInformationProvider(RuntimeInformationProvider provider) {
runtimeInfoProviders.remove(provider);
}
/**
* Callback from OSGi to set the security service.
*
* @param securityService
* the security service
*/
void setSecurityService(SecurityService securityService) {
this.securityService = securityService;
}
/**
* Callback from the OSGi environment when the environment becomes published.
*
* @param environment
* the environment
*/
void setEnvironment(Environment environment) {
this.environment = environment;
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Runtime information rest endpoint";
}
}