Return-Path: Delivered-To: apmail-incubator-sling-commits-archive@locus.apache.org Received: (qmail 47166 invoked from network); 19 Oct 2007 13:22:04 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 19 Oct 2007 13:22:04 -0000 Received: (qmail 70627 invoked by uid 500); 19 Oct 2007 13:21:52 -0000 Delivered-To: apmail-incubator-sling-commits-archive@incubator.apache.org Received: (qmail 70585 invoked by uid 500); 19 Oct 2007 13:21:52 -0000 Mailing-List: contact sling-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: sling-dev@incubator.apache.org Delivered-To: mailing list sling-commits@incubator.apache.org Received: (qmail 70566 invoked by uid 99); 19 Oct 2007 13:21:52 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 19 Oct 2007 06:21:52 -0700 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 19 Oct 2007 13:22:03 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 811811A9838; Fri, 19 Oct 2007 06:21:43 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r586429 - /incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/StreamServlet.java Date: Fri, 19 Oct 2007 13:21:43 -0000 To: sling-commits@incubator.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20071019132143.811811A9838@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fmeschbe Date: Fri Oct 19 06:21:42 2007 New Revision: 586429 URL: http://svn.apache.org/viewvc?rev=586429&view=rev Log: SLING-70 First shot streamer servlet Added: incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/StreamServlet.java Added: incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/StreamServlet.java URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/StreamServlet.java?rev=586429&view=auto ============================================================================== --- incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/StreamServlet.java (added) +++ incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/StreamServlet.java Fri Oct 19 06:21:42 2007 @@ -0,0 +1,203 @@ +/* + * $Url: $ + * $Id: $ + * + * Copyright 1997-2005 Day Management AG + * Barfuesserplatz 6, 4001 Basel, Switzerland + * All Rights Reserved. + * + * This software is the confidential and proprietary information of + * Day Management AG, ("Confidential Information"). You shall not + * disclose such Confidential Information and shall use it only in + * accordance with the terms of the license agreement you entered into + * with Day. + */ +package org.apache.sling.microsling.slingservlets; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.jcr.Item; +import javax.jcr.ItemNotFoundException; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.PropertyType; +import javax.jcr.RepositoryException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.jackrabbit.JcrConstants; +import org.apache.sling.microsling.api.SlingRequestContext; +import org.apache.sling.microsling.api.exceptions.SlingException; +import org.apache.sling.microsling.helpers.constants.HttpConstants; +import org.apache.sling.microsling.helpers.servlets.SlingSafeMethodsServlet; + +/** + * The StreamServlet handles requests for nodes which may just be + * streamed out to the response. If the requested JCR Item is an + * nt:file whose jcr:content child node is of type + * nt:resource, the response content type, last modification time and + * charcter encoding are set according to the resource node. In addition if + * the If-Modified-Since header is set, the resource will only be + * spooled if the last modification time is later than the header. Otherwise + * a 304 (Not Modified) status code is sent. + *

+ * If the requested item is not an nt:file/nt:resource tuple, + * the item is just resolved by following the primary item trail according to + * the algorithm + *

+ *     while (item.isNode) {
+ *         item = ((Node) item).getPrimaryItem();
+ *     }
+ * 
+ * Until a property is found or the primary item is either not defined or not + * existing in which case an exception is thrown and the request fails with + * a 404 (Not Found) status. + */ +public class StreamServlet extends SlingSafeMethodsServlet { + + @Override + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + + SlingRequestContext ctx = SlingRequestContext.Accessor.getSlingRequestContext(request); + + Item item = ctx.getResource().getItem(); + + try { + // otherwise handle nt:file/nt:resource specially + Node node = (Node) item; + if (node.isNodeType("nt:file")) { + Node content = node.getNode("jcr:content"); + if (content.isNodeType("nt:resource")) { + + // check for if last modified + long ifModified = request.getDateHeader(HttpConstants.HEADER_IFMODSINCE); + long lastModified = getLastModified(content); + if (ifModified < 0 || lastModified > ifModified) { + + String contentType = getMimeType(content); + if (contentType == null) { + contentType = ctx.getResponseContentType(); + } + + spool(response, + content.getProperty(JcrConstants.JCR_DATA), + contentType, getEncoding(content), + getLastModified(content)); + } else { + response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + } + + return; + } + } + + // just spool, the property to which the item resolves through + // the primary item trail + // the item is a property, spool and forget + spool(response, findDefaultProperty(item), null, null, -1); + + } catch (ItemNotFoundException infe) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + + } catch (RepositoryException re) { + throw new SlingException(re.getMessage(), re); + } + } + + /** + * Spool the property value to the response setting the content type, + * character set, last modification data and content length header + */ + private void spool(HttpServletResponse response, Property prop, + String mimeType, String encoding, long lastModified) + throws RepositoryException, IOException { + + if (mimeType != null) { + response.setContentType(mimeType); + } + + if (encoding != null) { + response.setCharacterEncoding(encoding); + } + + if (lastModified > 0) { + response.setDateHeader(HttpConstants.HEADER_LASTMOD, lastModified); + } + + // only set the content length if the property is a binary + if (prop.getType() == PropertyType.BINARY) { + response.setContentLength((int) prop.getLength()); + } + + InputStream ins = prop.getStream(); + OutputStream out = null; + try { + ins = prop.getStream(); + out = response.getOutputStream(); + + byte[] buf = new byte[2048]; + int num; + while ((num = ins.read(buf)) >= 0) { + out.write(buf, 0, num); + } + } finally { + if (ins != null) { + try { + ins.close(); + } catch (IOException ignore) { + } + } + if (out != null) { + try { + out.close(); + } catch (IOException ignore) { + } + } + } + } + + /** Follow the primary item trail of item until a property is found */ + Property findDefaultProperty(Item item) throws ItemNotFoundException, + RepositoryException { + while (item.isNode()) { + // will throw if there is none defined or existsing + item = ((Node) item).getPrimaryItem(); + } + return (Property) item; + } + + /** return the jcr:lastModified property value or null if property is missing */ + private long getLastModified(Node resourceNode) throws RepositoryException { + Property lastModifiedProp = getProperty(resourceNode, + JcrConstants.JCR_LASTMODIFIED); + return (lastModifiedProp != null) ? lastModifiedProp.getLong() : -1; + } + + /** return the jcr:mimeType property value or null if property is missing */ + private String getMimeType(Node resourceNode) throws RepositoryException { + Property mimeTypeProp = getProperty(resourceNode, + JcrConstants.JCR_MIMETYPE); + return (mimeTypeProp != null) ? mimeTypeProp.getString() : null; + } + + /** return the jcr:encoding property value or null if property is missing */ + private String getEncoding(Node resourceNode) throws RepositoryException { + Property encodingProp = getProperty(resourceNode, + JcrConstants.JCR_ENCODING); + return (encodingProp != null) ? encodingProp.getString() : null; + } + + /** Return the named property or null if not existing or node is null */ + private Property getProperty(Node node, String relPath) + throws RepositoryException { + if (node != null && node.hasProperty(relPath)) { + return node.getProperty(relPath); + } + + return null; + } +}