You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2008/12/08 16:53:49 UTC
svn commit: r724385 - in /incubator/sling/trunk/servlets/get: ./
src/main/java/org/apache/sling/servlets/get/
src/main/java/org/apache/sling/servlets/get/helpers/
src/main/resources/OSGI-INF/metatype/
Author: fmeschbe
Date: Mon Dec 8 07:53:49 2008
New Revision: 724385
URL: http://svn.apache.org/viewvc?rev=724385&view=rev
Log:
SLING-723 Enhance functionality of the streamer servlet (autoindex style)
and make renderers and indexing configurable
Modified:
incubator/sling/trunk/servlets/get/pom.xml
incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/DefaultGetServlet.java
incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/helpers/StreamRendererServlet.java
incubator/sling/trunk/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties
Modified: incubator/sling/trunk/servlets/get/pom.xml
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/get/pom.xml?rev=724385&r1=724384&r2=724385&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/get/pom.xml (original)
+++ incubator/sling/trunk/servlets/get/pom.xml Mon Dec 8 07:53:49 2008
@@ -106,6 +106,11 @@
<version>2.0.3-incubator-SNAPSHOT</version>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.osgi</artifactId>
+ <version>2.0.3-incubator-SNAPSHOT</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
Modified: incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/DefaultGetServlet.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/DefaultGetServlet.java?rev=724385&r1=724384&r2=724385&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/DefaultGetServlet.java (original)
+++ incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/DefaultGetServlet.java Mon Dec 8 07:53:49 2008
@@ -17,6 +17,7 @@
package org.apache.sling.servlets.get;
import java.io.IOException;
+import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
@@ -42,9 +43,9 @@
/**
* A SlingSafeMethodsServlet that renders the current Resource as simple HTML
- *
+ *
* @scr.component immediate="true" label="%servlet.get.name"
- * description="%servlet.get.description"
+ * description="%servlet.get.description"
* @scr.service interface="javax.servlet.Servlet"
*
* @scr.property name="service.description" value="Default GET Servlet"
@@ -70,15 +71,71 @@
/** @scr.property */
private static final String ALIAS_PROPERTY = "aliases";
+ /** @scr.property valueRef="DEFAULT_INDEX_PROPERTY" type="Boolean" */
+ private static final String INDEX_PROPERTY = "index";
+
+ private static final boolean DEFAULT_INDEX_PROPERTY = false;
+
+ /** @scr.property valueRef="DEFAULT_INDEX_FILES_PROPERTY" */
+ private static final String INDEX_FILES_PROPERTY = "index.files";
+
+ private static final String[] DEFAULT_INDEX_FILES_PROPERTY = { "index",
+ "index.html" };
+
+ /** Default value for renderer selection (value is "true"). */
+ private static final boolean DEFAULT_RENDERER_PROPERTY = true;
+
+ /** @scr.property valueRef="DEFAULT_RENDERER_PROPERTY" type="Boolean" */
+ private static final String HTML_RENDERER_PROPERTY = "enable.html";
+
+ /** @scr.property valueRef="DEFAULT_RENDERER_PROPERTY" type="Boolean" */
+ private static final String TXT_RENDERER_PROPERTY = "enable.txt";
+
+ /** @scr.property valueRef="DEFAULT_RENDERER_PROPERTY" type="Boolean" */
+ private static final String JSON_RENDERER_PROPERTY = "enable.json";
+
+ /** @scr.property valueRef="DEFAULT_RENDERER_PROPERTY" type="Boolean" */
+ private static final String XML_RENDERER_PROPERTY = "enable.xml";
+
/** 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) {
- this.aliases = OsgiUtil.toStringArray(ctx.getProperties().get(ALIAS_PROPERTY));
+ 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);
}
protected void deactivate(ComponentContext ctx) {
this.aliases = null;
+ this.index = false;
+ this.indexFiles = null;
}
@Override
@@ -86,28 +143,45 @@
super.init();
// Register renderer servlets
- setupServlet(rendererMap, HtmlRendererServlet.EXT_HTML,
- new HtmlRendererServlet());
- setupServlet(rendererMap, PlainTextRendererServlet.EXT_TXT,
- new PlainTextRendererServlet());
- setupServlet(rendererMap, JsonRendererServlet.EXT_JSON,
- new JsonRendererServlet());
setupServlet(rendererMap, StreamRendererServlet.EXT_RES,
- new StreamRendererServlet());
- setupServlet(rendererMap, XMLRendererServlet.EXT_XML,
+ 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());
+ }
+
+ 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) {
+ if (this.aliases != null) {
+ for (final String m : aliases) {
final int pos = m.indexOf(':');
- if ( pos != -1 ) {
+ 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() ) {
+ 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);
}
@@ -115,9 +189,6 @@
}
}
}
- // use the servlet for rendering StreamRendererServlet.EXT_RES as the
- // streamer servlet
- streamerServlet = rendererMap.get(StreamRendererServlet.EXT_RES);
}
/**
@@ -145,13 +216,14 @@
// fail if we should not just stream or we cannot support the ext.
if (rendererServlet == null) {
- response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
- "No renderer for extension='" + ext + "'");
+ request.getRequestProgressTracker().log(
+ "No Renderer for extension " + ext);
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
- request.getRequestProgressTracker().log("Using "
- + rendererServlet.getClass().getName()
+ request.getRequestProgressTracker().log(
+ "Using " + rendererServlet.getClass().getName()
+ " to render for extension=" + ext);
rendererServlet.service(request, response);
}
Modified: incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/helpers/StreamRendererServlet.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/helpers/StreamRendererServlet.java?rev=724385&r1=724384&r2=724385&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/helpers/StreamRendererServlet.java (original)
+++ incubator/sling/trunk/servlets/get/src/main/java/org/apache/sling/servlets/get/helpers/StreamRendererServlet.java Mon Dec 8 07:53:49 2008
@@ -23,30 +23,47 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.Iterator;
+import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.request.RequestDispatcherOptions;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
/**
* The <code>StreamRendererServlet</code> streams the current resource to the
- * client on behalf of the {@link org.apache.sling.servlets.get.DefaultGetServlet}.
- * If the current resource cannot be streamed it is rendered using the
+ * client on behalf of the
+ * {@link org.apache.sling.servlets.get.DefaultGetServlet}. If the current
+ * resource cannot be streamed it is rendered using the
* {@link PlainTextRendererServlet}.
*/
-public class StreamRendererServlet extends PlainTextRendererServlet {
+public class StreamRendererServlet extends SlingSafeMethodsServlet {
public static final String EXT_RES = "res";
private static final long serialVersionUID = -1L;
+ private boolean index;
+
+ private String[] indexFiles;
+
+ public StreamRendererServlet(boolean index, String[] indexFiles) {
+ this.index = index;
+ this.indexFiles = indexFiles;
+ }
+
@Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
@@ -65,6 +82,12 @@
throw new ResourceNotFoundException("No data to render.");
}
+ // trailing slash on url means directory listing
+ if ("/".equals(request.getRequestPathInfo().getSuffix())) {
+ renderDirectory(request, response);
+ return;
+ }
+
// check the last modification time and If-Modified-Since header
ResourceMetadata meta = resource.getResourceMetadata();
long modifTime = meta.getModificationTime();
@@ -75,14 +98,60 @@
// fall back to plain text rendering if the resource has no stream
InputStream stream = resource.adaptTo(InputStream.class);
- if (stream == null) {
- super.doGet(request, response);
- return;
+ if (stream != null) {
+
+ streamResource(resource, stream, response);
+
+ } else {
+
+ // the resource is the root, do not redirect, immediately index
+ if ("/".equals(resource.getPath())) {
+
+ renderDirectory(request, response);
+
+ } else {
+
+ // redirect to this with trailing slash to render the index
+ String url = request.getResourceResolver().map(request,
+ resource.getPath())
+ + "/";
+ response.sendRedirect(url);
+
+ }
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if the request has a
+ * <code>If-Modified-Since</code> header whose date value is later than
+ * the last modification time given as <code>modifTime</code>.
+ *
+ * @param request The <code>ComponentRequest</code> checked for the
+ * <code>If-Modified-Since</code> header.
+ * @param modifTime The last modification time to compare the header to.
+ * @return <code>true</code> if the <code>modifTime</code> is less than
+ * or equal to the time of the <code>If-Modified-Since</code>
+ * header.
+ */
+ private boolean unmodified(HttpServletRequest request, long modifTime) {
+ if (modifTime > 0) {
+ long modTime = modifTime / 1000; // seconds
+ long ims = request.getDateHeader(HEADER_IF_MODIFIED_SINCE) / 1000;
+ return modTime <= ims;
}
+ // we have no modification time value, assume modified
+ return false;
+ }
+
+ private void streamResource(Resource resource, InputStream stream,
+ SlingHttpServletResponse response) throws IOException {
// finally stream the resource
try {
+ ResourceMetadata meta = resource.getResourceMetadata();
+ long modifTime = meta.getModificationTime();
+
if (modifTime > 0) {
response.setDateHeader(HEADER_LAST_MODIFIED, modifTime);
}
@@ -130,28 +199,122 @@
}
}
}
+
+ private void renderDirectory(SlingHttpServletRequest request,
+ SlingHttpServletResponse response) throws ServletException,
+ IOException {
- /**
- * Returns <code>true</code> if the request has a
- * <code>If-Modified-Since</code> header whose date value is later than
- * the last modification time given as <code>modifTime</code>.
- *
- * @param request The <code>ComponentRequest</code> checked for the
- * <code>If-Modified-Since</code> header.
- * @param modifTime The last modification time to compare the header to.
- * @return <code>true</code> if the <code>modifTime</code> is less than
- * or equal to the time of the <code>If-Modified-Since</code>
- * header.
- */
- private boolean unmodified(HttpServletRequest request, long modifTime) {
- if (modifTime > 0) {
- long modTime = modifTime / 1000; // seconds
- long ims = request.getDateHeader(HEADER_IF_MODIFIED_SINCE) / 1000;
- return modTime <= ims;
+ Resource resource = request.getResource();
+ ResourceResolver resolver = request.getResourceResolver();
+
+ // check for an index file
+ for (String index : indexFiles) {
+ Resource fileRes = resolver.getResource(resource, index);
+ if (fileRes != null && !ResourceUtil.isSyntheticResource(fileRes)) {
+
+ // include the index resource with no suffix and selectors !
+ RequestDispatcherOptions rdo = new RequestDispatcherOptions();
+ rdo.setReplaceSuffix("");
+ rdo.setReplaceSelectors("");
+
+ RequestDispatcher dispatcher;
+ if (index.indexOf('.') < 0) {
+ String filePath = fileRes.getPath() + ".html";
+ dispatcher = request.getRequestDispatcher(filePath, rdo);
+ } else {
+ dispatcher = request.getRequestDispatcher(fileRes, rdo);
+ }
+
+ dispatcher.include(request, response);
+ return;
+ }
+ }
+
+ if (index) {
+// RequestDispatcherOptions rdo = new RequestDispatcherOptions();
+// rdo.setReplaceSelectors("sling.index");
+// request.getRequestDispatcher(resource, rdo).include(request, response);
+ renderIndex(resource, response);
+ } else {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
- // we have no modification time value, assume modified
- return false;
}
+
+ private void renderIndex(Resource resource,
+ SlingHttpServletResponse response) throws IOException {
+
+ response.setContentType("text/html");
+ response.setCharacterEncoding("UTF-8");
+
+ String path = resource.getPath();
+
+ PrintWriter pw = response.getWriter();
+ pw.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">");
+ pw.println("<html>");
+ pw.println("<head>");
+ pw.println("<title>Index of " + path + "</title>");
+ pw.println("</head>");
+
+ pw.println("<body>");
+ pw.println("<h1>Index of " + path + "</h1>");
+
+ pw.println("<pre>");
+ pw.println("Name Last modified Size Description");
+ pw.println("<hr>");
+
+ if (!"/".equals(path)) {
+ pw.println("<a href='../'>../</a> - Parent");
+ }
+ // render the children
+ Iterator<Resource> children = ResourceUtil.listChildren(resource);
+ while (children.hasNext()) {
+ renderChild(pw, children.next());
+ }
+
+ pw.println("</pre>");
+ pw.println("</body>");
+ pw.println("</html>");
+
+ }
+
+ private void renderChild(PrintWriter pw, Resource resource) {
+
+ String name = ResourceUtil.getName(resource.getPath());
+
+ InputStream ins = resource.adaptTo(InputStream.class);
+ if (ins == null) {
+ name += "/";
+ } else {
+ try {
+ ins.close();
+ } catch (IOException ignore) {
+ }
+ }
+
+ String displayName = name;
+ String suffix;
+ if (displayName.length() >= 32) {
+ displayName = displayName.substring(0, 29) + "...";
+ suffix = "";
+ } else {
+ suffix = " ".substring(
+ 0, 32 - displayName.length());
+ }
+ pw.printf("<a href='%s'>%s</a>%s", name, displayName, suffix);
+
+ ResourceMetadata meta = resource.getResourceMetadata();
+ long lastModified = meta.getModificationTime();
+ pw.print(" " + new Date(lastModified) + " ");
+
+ long length = meta.getContentLength();
+ if (length > 0) {
+ pw.print(length);
+ } else {
+ pw.print('-');
+ }
+
+ pw.println();
+ }
}
\ No newline at end of file
Modified: incubator/sling/trunk/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=724385&r1=724384&r2=724385&view=diff
==============================================================================
--- incubator/sling/trunk/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ incubator/sling/trunk/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties Mon Dec 8 07:53:49 2008
@@ -26,7 +26,43 @@
servlet.get.name = Sling GET Servlet
servlet.get.description = The Sling GET Servlet is registered as the default \
servlet to handle GET requests in Sling.
+
aliases.name = Extension Aliases
aliases.description = The aliases can be used to map several extensions to a \
single servlet. For instance "xml:pdf,rtf" maps the extensions ".pdf" and \
".rtf" to the servlet helper handling the ".xml" extension.
+
+index.files.name = Index Resources
+index.files.description = List of child resources to be considered for rendering \
+ the index of a "directory". The default value is [ "index", "index.html" ]. \
+ Each entry in the list is checked and the first entry found is included to \
+ render the index. If an entry is selected, which has not extension (for \
+ example the "index" resource), the extension ".html" is appended for the \
+ inclusion to indicate the desired text/html rendering. If the resource name \
+ has an extension (as in "index.html"), no additional extension is appended \
+ for the inclusion. This configuration corresponds to the DirectoryIndex> \
+ directive of Apache HTTP Server (httpd).
+
+index.name = Auto Index
+index.description = Controls whether a simple directory index is rendered for \
+ a directory request. A directory request is a request to a resource with a \
+ trailing slash (/) character, for example http://host/apps/. If none of the \
+ index resources exists, the default GET servlet may automatically render an \
+ index listing of the child resources if this option is checked, which is the \
+ default. If this option is not checked, the request to the resource is \
+ forbidden and results in a status 403/FORBIDDEN. This configuration \
+ corresponds to the "Index" option of the Options directive of Apache HTTP \
+ Server (httpd).
+
+enable.html.name = Enable HTML
+enable.html.description = Whether the renderer for HTML of the Default GET \
+ Servlet is enabled or not. By default the HTML renderer is enabled.
+enable.txt.name = Enabled Plain Text
+enable.txt.description = Whether the renderer for plain text of the Default GET \
+ Servlet is enabled or not. By default the plain text renderer is enabled.
+enable.json.name = Enabled JSON
+enable.json.description = Whether the renderer for JSON of the Default GET \
+ Servlet is enabled or not. By default the JSON renderer is enabled.
+enable.xml.name = Enabled XML
+enable.xml.description = Whether the renderer for XML of the Default GET \
+ Servlet is enabled or not. By default the XML renderer is enabled.