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 2007/11/28 20:48:39 UTC
svn commit: r599118 - in
/incubator/sling/trunk/sling/sample/src/main/java/org/apache/sling/sample/filter:
./ ZipFilter.java
Author: fmeschbe
Date: Wed Nov 28 11:48:39 2007
New Revision: 599118
URL: http://svn.apache.org/viewvc?rev=599118&view=rev
Log:
Add sample request filter (implemented as a Declarative Services component
disabled by default)
Added:
incubator/sling/trunk/sling/sample/src/main/java/org/apache/sling/sample/filter/
incubator/sling/trunk/sling/sample/src/main/java/org/apache/sling/sample/filter/ZipFilter.java
Added: incubator/sling/trunk/sling/sample/src/main/java/org/apache/sling/sample/filter/ZipFilter.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/sling/sample/src/main/java/org/apache/sling/sample/filter/ZipFilter.java?rev=599118&view=auto
==============================================================================
--- incubator/sling/trunk/sling/sample/src/main/java/org/apache/sling/sample/filter/ZipFilter.java (added)
+++ incubator/sling/trunk/sling/sample/src/main/java/org/apache/sling/sample/filter/ZipFilter.java Wed Nov 28 11:48:39 2007
@@ -0,0 +1,268 @@
+/*
+ * 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.sample.filter;
+
+import static org.apache.sling.api.SlingConstants.ATTR_REQUEST_CONTENT;
+import static org.apache.sling.api.wrappers.SlingRequestPaths.INCLUDE_REQUEST_URI;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.GZIPOutputStream;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
+import org.apache.sling.core.RequestUtil;
+
+/**
+ * The <code>ZipFilter</code> is an optionally installable global filter,
+ * which must be first in the filter chain for the compression functionality to
+ * be effective.
+ * <p>
+ * <b>NOTES</b>
+ * <p>
+ * When considering this filter, please keep the following notes in mind:
+ * <ul>
+ * <li>This filter serves as a model for implementing filters.
+ * <li>If using this filter it must be registered with a
+ * <code>filter.scope</code> parameter of <i><code>request</code></i> and
+ * a <code>filter.order</code> value which is smaller than any other
+ * <code>request</code> scope filter.
+ * <li>With small response data and fast networks this filter is not effective
+ * and in fact even slows response time down !!
+ * </ul>
+ *
+ * @scr.component metatype="no" enabled="no"
+ * @scr.property name="service.description" value="Sample Request Filter"
+ * @scr.property name="service.vendor" value="The Apache Software Foundation"
+ * @scr.property name="filter.scope" value="request" private="true"
+ * @scr.property name="filter.order" value="-2147483648" type="Integer" private="true"
+ * @scr.service
+ */
+public class ZipFilter implements Filter {
+
+ /**
+ * Does nothing. This filter has not initialization requirement.
+ */
+ public void init(FilterConfig filterConfig) {
+ }
+
+ /**
+ * Checks the <code>Accept-Encoding</code> request header for its values.
+ * If <i>gzip</i> or <i>x-gzip</i> is desired, the response stream is
+ * compressed using the GZip algorithm. If <i>deflate</i> is desired, the
+ * response stream is compressed using the standard Zip Algorithm. Otherwise
+ * the response stream is transferred unmodified (<i>identity</i>
+ * encoding).
+ */
+ public void doFilter(ServletRequest req, ServletResponse res,
+ FilterChain chain) throws IOException, ServletException {
+
+ // request is Servlet API or Sling API included, do not filter
+ if (req.getAttribute(INCLUDE_REQUEST_URI) != null
+ || req.getAttribute(ATTR_REQUEST_CONTENT) != null) {
+ chain.doFilter(req, res);
+ return;
+ }
+
+ SlingHttpServletRequest request = (SlingHttpServletRequest) req;
+ SlingHttpServletResponse response = (SlingHttpServletResponse) res;
+
+ // check for compress header
+ String enc = request.getHeader("Accept-Encoding");
+ if (enc == null || enc.length() == 0) {
+ // assume identity, no wrapping
+ chain.doFilter(request, response);
+ return;
+ }
+
+ // get settings
+ enc = this.getEncoding(enc);
+ if ("gzip".equals(enc) || "x-gzip".equals(enc)) {
+ // mark the response encoded
+ response.setHeader("Content-Encoding", enc);
+ response = new DeflaterComponentResponse(response, false);
+ } else if ("deflate".equals(enc)) {
+ // mark the response encoded
+ response.setHeader("Content-Encoding", enc);
+ response = new DeflaterComponentResponse(response, true);
+ }
+
+ // continue filtering
+ chain.doFilter(request, response);
+
+ // finish the output
+ if (response instanceof DeflaterComponentResponse) {
+ ((DeflaterComponentResponse) response).finish();
+ }
+ }
+
+ /**
+ * Does nothing. This filter has not destroyal requirement.
+ */
+ public void destroy() {
+ }
+
+ // ---------- internal -----------------------------------------------------
+
+ /**
+ * Parses the <code>Accept-Encoding</code> header and returns the token
+ * with the highest <i>q</i> value or <code>null</code> if the header is
+ * empty.
+ */
+ String getEncoding(String encodingHeader) {
+ String select = null;
+ double q = Double.MIN_VALUE;
+ Map<String, Double> settings = RequestUtil.parserAcceptHeader(encodingHeader);
+ for (Iterator<Map.Entry<String, Double>> ti = settings.entrySet().iterator(); ti.hasNext();) {
+ Map.Entry<String, Double> token = ti.next();
+ Double qv = token.getValue();
+ if (qv.doubleValue() > q) {
+ q = qv.doubleValue();
+ select = token.getKey();
+ }
+ }
+ return select;
+ }
+
+ // ---------- internal classes ---------------------------------------------
+
+ /**
+ * Compressing <code>ComponentResponseWrapper</code> which compresses the
+ * output stream using GZip or Zip algorithm depending on the constructor
+ * flag <code>deflate</code>.
+ * <p>
+ * This wrapper is only
+ */
+ private static class DeflaterComponentResponse extends
+ SlingHttpServletResponseWrapper {
+
+ private boolean deflate;
+
+ private DeflaterServletOutputStream stream;
+
+ private PrintWriter writer;
+
+ public DeflaterComponentResponse(SlingHttpServletResponse delegatee,
+ boolean deflate) {
+ super(delegatee);
+ this.deflate = deflate;
+ }
+
+ public ServletOutputStream getOutputStream() throws IOException {
+ if (this.stream != null) {
+ return this.stream;
+ } else if (this.writer != null) {
+ throw new IllegalStateException(
+ "Writer has already been obtained");
+ }
+
+ this.stream = new DeflaterServletOutputStream(
+ this.getDeflaterOutputStream());
+ return this.stream;
+ }
+
+ public PrintWriter getWriter() throws IOException {
+ if (this.writer != null) {
+ return this.writer;
+ } else if (this.stream != null) {
+ throw new IllegalStateException(
+ "OutputStream has already been obtained");
+ }
+
+ DeflaterOutputStream base = this.getDeflaterOutputStream();
+ String enc = this.getCharacterEncoding();
+ this.writer = new PrintWriter(new OutputStreamWriter(base, enc));
+ return this.writer;
+ }
+
+ public void flushBuffer() throws IOException {
+ if (this.writer != null) {
+ this.writer.flush();
+ } else if (this.stream != null) {
+ this.stream.flush();
+ }
+
+ super.flushBuffer();
+ }
+
+ void finish() throws IOException {
+ if (this.writer != null) {
+ this.writer.flush();
+ } else if (this.stream != null) {
+ this.stream.getDeflaterStream().finish();
+ }
+ }
+
+ protected DeflaterOutputStream getDeflaterOutputStream()
+ throws IOException {
+ OutputStream base = super.getOutputStream();
+ return this.deflate
+ ? new DeflaterOutputStream(base)
+ : new GZIPOutputStream(base);
+ }
+
+ private static class DeflaterServletOutputStream extends
+ ServletOutputStream {
+
+ private DeflaterOutputStream deflaterStream;
+
+ DeflaterServletOutputStream(DeflaterOutputStream deflaterStream) {
+ this.deflaterStream = deflaterStream;
+ }
+
+ DeflaterOutputStream getDeflaterStream() {
+ return this.deflaterStream;
+ }
+
+ public void write(int b) throws IOException {
+ this.deflaterStream.write(b);
+ }
+
+ public void write(byte[] b) throws IOException {
+ this.deflaterStream.write(b);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ this.deflaterStream.write(b, off, len);
+ }
+
+ public void flush() throws IOException {
+ this.deflaterStream.flush();
+ }
+
+ public void close() throws IOException {
+ this.deflaterStream.close();
+ }
+ }
+ }
+}