blob: b1960e05044d1c09c4af1baea5145ada5439ca65 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sling.servlets.get.impl;
import java.io.IOException;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceNotFoundException;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.commons.osgi.OsgiUtil;
import org.apache.sling.servlets.get.impl.helpers.HtmlRendererServlet;
import org.apache.sling.servlets.get.impl.helpers.JsonRendererServlet;
import org.apache.sling.servlets.get.impl.helpers.PlainTextRendererServlet;
import org.apache.sling.servlets.get.impl.helpers.StreamRendererServlet;
import org.apache.sling.servlets.get.impl.helpers.XMLRendererServlet;
import org.apache.sling.servlets.get.impl.helpers.HeadServletResponse;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A SlingSafeMethodsServlet that renders the current Resource as simple HTML
*/
@Component(immediate=true, metatype=true, name="org.apache.sling.servlets.get.DefaultGetServlet", label="%servlet.get.name", description="%servlet.get.description")
@Service(Servlet.class)
@Properties({
@Property(name="service.description", value="Default GET Servlet"),
@Property(name="service.vendor", value="The Apache Software Foundation"),
// Use this as a default servlet for Sling
@Property(name="sling.servlet.resourceTypes", value="sling/servlet/default", propertyPrivate=true),
@Property(name="sling.servlet.prefix", intValue=-1, propertyPrivate=true),
// Generic handler for all get requests
@Property(name="sling.servlet.methods", value={"GET", "HEAD"}, propertyPrivate=true)
})
public class DefaultGetServlet extends SlingSafeMethodsServlet {
private static final long serialVersionUID = -5815904221043005085L;
private final Logger logger = LoggerFactory.getLogger(getClass());
private Map<String, Servlet> rendererMap = new HashMap<String, Servlet>();
private Servlet streamerServlet;
@Property
private static final String ALIAS_PROPERTY = "aliases";
private static final boolean DEFAULT_INDEX_PROPERTY = false;
@Property(boolValue=DEFAULT_INDEX_PROPERTY)
private static final String INDEX_PROPERTY = "index";
private static final String[] DEFAULT_INDEX_FILES_PROPERTY = { "index",
"index.html" };
@Property(value={ "index", "index.html" })
private static final String INDEX_FILES_PROPERTY = "index.files";
/** Default value for renderer selection (value is "true"). */
private static final boolean DEFAULT_RENDERER_PROPERTY = true;
@Property(boolValue=DEFAULT_RENDERER_PROPERTY)
private static final String HTML_RENDERER_PROPERTY = "enable.html";
@Property(boolValue=DEFAULT_RENDERER_PROPERTY)
private static final String TXT_RENDERER_PROPERTY = "enable.txt";
@Property(boolValue=DEFAULT_RENDERER_PROPERTY)
private static final String JSON_RENDERER_PROPERTY = "enable.json";
@Property(boolValue=DEFAULT_RENDERER_PROPERTY)
private static final String XML_RENDERER_PROPERTY = "enable.xml";
/** Default value for the maximum amount of results that should be returned by the jsonResourceWriter */
public static final int DEFAULT_JSON_RENDERER_MAXIMUM_RESULTS = 200;
@Property(intValue=DEFAULT_JSON_RENDERER_MAXIMUM_RESULTS)
public static final String JSON_RENDERER_MAXIMUM_RESULTS_PROPERTY = "json.maximumresults";
private int jsonMaximumResults;
/** Additional aliases. */
private String[] aliases;
/** Whether to support automatic index rendering */
private boolean index;
/** The names of index rendering children */
private String[] indexFiles;
private boolean enableHtml;
private boolean enableTxt;
private boolean enableJson;
private boolean enableXml;
protected void activate(ComponentContext ctx) {
Dictionary<?, ?> props = ctx.getProperties();
this.aliases = OsgiUtil.toStringArray(props.get(ALIAS_PROPERTY));
this.index = OsgiUtil.toBoolean(props.get(INDEX_PROPERTY),
DEFAULT_INDEX_PROPERTY);
this.indexFiles = OsgiUtil.toStringArray(
props.get(INDEX_FILES_PROPERTY), DEFAULT_INDEX_FILES_PROPERTY);
this.enableHtml = OsgiUtil.toBoolean(props.get(HTML_RENDERER_PROPERTY),
DEFAULT_RENDERER_PROPERTY);
this.enableTxt = OsgiUtil.toBoolean(props.get(TXT_RENDERER_PROPERTY),
DEFAULT_RENDERER_PROPERTY);
this.enableJson = OsgiUtil.toBoolean(props.get(JSON_RENDERER_PROPERTY),
DEFAULT_RENDERER_PROPERTY);
this.enableXml = OsgiUtil.toBoolean(props.get(XML_RENDERER_PROPERTY),
DEFAULT_RENDERER_PROPERTY);
this.jsonMaximumResults = OsgiUtil.toInteger(props.get(JSON_RENDERER_MAXIMUM_RESULTS_PROPERTY),
DEFAULT_JSON_RENDERER_MAXIMUM_RESULTS);
}
protected void deactivate(ComponentContext ctx) {
this.aliases = null;
this.index = false;
this.indexFiles = null;
}
@Override
public void init() throws ServletException {
super.init();
// Register renderer servlets
setupServlet(rendererMap, StreamRendererServlet.EXT_RES,
new StreamRendererServlet(index, indexFiles));
if (enableHtml) {
setupServlet(rendererMap, HtmlRendererServlet.EXT_HTML,
new HtmlRendererServlet());
}
if (enableTxt) {
setupServlet(rendererMap, PlainTextRendererServlet.EXT_TXT,
new PlainTextRendererServlet());
}
if (enableJson) {
setupServlet(rendererMap, JsonRendererServlet.EXT_JSON,
new JsonRendererServlet(jsonMaximumResults));
}
if (enableXml) {
setupServlet(rendererMap, XMLRendererServlet.EXT_XML,
new XMLRendererServlet());
}
// use the servlet for rendering StreamRendererServlet.EXT_RES as the
// streamer servlet
streamerServlet = rendererMap.get(StreamRendererServlet.EXT_RES);
// check additional aliases
if (this.aliases != null) {
for (final String m : aliases) {
final int pos = m.indexOf(':');
if (pos != -1) {
final String type = m.substring(0, pos);
final Servlet servlet = rendererMap.get(type);
if (servlet != null) {
final String extensions = m.substring(pos + 1);
final StringTokenizer st = new StringTokenizer(
extensions, ",");
while (st.hasMoreTokens()) {
final String ext = st.nextToken();
rendererMap.put(ext, servlet);
}
}
}
}
}
}
/**
* @throws ResourceNotFoundException if the resource of the request is a non
* existing resource.
*/
@Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
// cannot handle the request for missing resources
if (ResourceUtil.isNonExistingResource(request.getResource())) {
throw new ResourceNotFoundException(
request.getResource().getPath(), "No resource found");
}
Servlet rendererServlet;
String ext = request.getRequestPathInfo().getExtension();
if (ext == null) {
rendererServlet = streamerServlet;
} else {
rendererServlet = rendererMap.get(ext);
}
// fail if we should not just stream or we cannot support the ext.
if (rendererServlet == null) {
request.getRequestProgressTracker().log(
"No renderer for extension " + ext);
// if this is an included request, sendError() would fail
// as the response is already committed, in this case we just
// do nothing (but log an error message)
if (response.isCommitted()
|| request.getAttribute(SlingConstants.ATTR_REQUEST_SERVLET) != null) {
logger.error(
"No renderer for extension {}, cannot render resource {}",
ext, request.getResource());
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
return;
}
request.getRequestProgressTracker().log(
"Using " + rendererServlet.getClass().getName()
+ " to render for extension=" + ext);
rendererServlet.service(request, response);
}
@Override
protected void doHead(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
response = new HeadServletResponse(response);
doGet(request, response);
}
@Override
public void destroy() {
for (Servlet servlet : rendererMap.values()) {
try {
servlet.destroy();
} catch (Throwable t) {
logger.error("Error while destroying servlet " + servlet, t);
}
}
streamerServlet = null;
rendererMap.clear();
super.destroy();
}
private void setupServlet(Map<String, Servlet> rendererMap, String key,
Servlet servlet) {
try {
servlet.init(getServletConfig());
rendererMap.put(key, servlet);
} catch (Throwable t) {
logger.error("Error while initializing servlet " + servlet, t);
}
}
}