WICKET-5819 - Own file for PartWriterCallback Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/4434d94f Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/4434d94f Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/4434d94f
Branch: refs/heads/pr-86-media_tags Commit: 4434d94f95c5c8b8b6e70e65ab630ccac42f9b6d Parents: ff1bf27 Author: klopfdreh <klopfdreh@tobiass-mbp> Authored: Sat Feb 7 20:06:27 2015 +0100 Committer: klopfdreh <klopfdreh@tobiass-mbp> Committed: Sat Feb 7 20:06:27 2015 +0100 ---------------------------------------------------------------------- .../media/MediaStreamingResourceReference.java | 234 +++++-------------- .../markup/html/media/PartWriterCallback.java | 188 +++++++++++++++ 2 files changed, 252 insertions(+), 170 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/4434d94f/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaStreamingResourceReference.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaStreamingResourceReference.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaStreamingResourceReference.java index 0f7568f..54d9442 100755 --- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaStreamingResourceReference.java +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaStreamingResourceReference.java @@ -17,14 +17,11 @@ package org.apache.wicket.markup.html.media; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.Locale; import org.apache.wicket.Application; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.core.util.resource.PackageResourceStream; -import org.apache.wicket.protocol.http.servlet.ResponseIOException; import org.apache.wicket.request.Request; import org.apache.wicket.request.Response; import org.apache.wicket.request.cycle.RequestCycle; @@ -46,8 +43,6 @@ public class MediaStreamingResourceReference extends ResourceReference private static final long serialVersionUID = 1L; - private Integer buffer; - public MediaStreamingResourceReference(Class<?> scope, String name, Locale locale, String style, String variation) { @@ -75,152 +70,96 @@ public class MediaStreamingResourceReference extends ResourceReference AbstractResource mediaStreamingResource = new AbstractResource() { private static final long serialVersionUID = 1L; - private Long startbyte; - private Long endbyte; - private PackageResourceStream packageResourceStream; @Override protected ResourceResponse newResourceResponse(Attributes attributes) { + PackageResourceStream packageResourceStream = null; + Long startbyte = null; + Long endbyte = null; try { Request request = attributes.getRequest(); Response response = attributes.getResponse(); - if (request instanceof WebRequest && response instanceof WebResponse) + + if (!(request instanceof WebRequest) || !(response instanceof WebResponse)) { - WebRequest webRequest = (WebRequest)request; - WebResponse webResponse = (WebResponse)response; + throw new IllegalStateException( + "Either the request is no web request or the response is no web response"); + } + + WebRequest webRequest = (WebRequest)request; + WebResponse webResponse = (WebResponse)response; - packageResourceStream = new PackageResourceStream( - MediaStreamingResourceReference.this.getScope(), - MediaStreamingResourceReference.this.getName(), - MediaStreamingResourceReference.this.getLocale(), - MediaStreamingResourceReference.this.getStyle(), - MediaStreamingResourceReference.this.getVariation()); - long length = packageResourceStream.length().bytes(); + packageResourceStream = new PackageResourceStream( + MediaStreamingResourceReference.this.getScope(), + MediaStreamingResourceReference.this.getName(), + MediaStreamingResourceReference.this.getLocale(), + MediaStreamingResourceReference.this.getStyle(), + MediaStreamingResourceReference.this.getVariation()); - ResourceResponse resourceResponse = new ResourceResponse(); - resourceResponse.setContentType(packageResourceStream.getContentType()); - resourceResponse.setFileName(MediaStreamingResourceReference.this.getName()); - resourceResponse.setContentDisposition(ContentDisposition.ATTACHMENT); - resourceResponse.setLastModified(packageResourceStream.lastModifiedTime()); - // We accept ranges, so that the player can - // load and play content from a specific byte position - webResponse.setHeader("Accept-Range", "bytes"); + long length = packageResourceStream.length().bytes(); - // Calculating the response code and the byte range to be played - String rangeHeader = webRequest.getHeader("range"); - if (rangeHeader == null || "".equals(rangeHeader)) + ResourceResponse resourceResponse = new ResourceResponse(); + resourceResponse.setContentType(packageResourceStream.getContentType()); + resourceResponse.setFileName(MediaStreamingResourceReference.this.getName()); + resourceResponse.setContentDisposition(ContentDisposition.ATTACHMENT); + resourceResponse.setLastModified(packageResourceStream.lastModifiedTime()); + + // We accept ranges, so that the player can + // load and play content from a specific byte position + webResponse.setHeader("Accept-Range", "bytes"); + + // Calculating the response code and the byte range to be played + String rangeHeader = webRequest.getHeader("range"); + if (rangeHeader == null || "".equals(rangeHeader)) + { + resourceResponse.setStatusCode(200); + resourceResponse.setContentLength(length); + } + else + { + rangeHeader = rangeHeader.replaceAll(" ", ""); + // If the range header is filled 206 for + // partial content has to be returned + resourceResponse.setStatusCode(206); + + // And now the calculation of the range to be read + // and to be given as response within the Content-Range header + // for more information take a look here: + // http://stackoverflow.com/questions/8293687/sample-http-range-request-session + String range = rangeHeader.substring(rangeHeader.indexOf('=') + 1, + rangeHeader.length()); + String[] rangeParts = range.split("-"); + if (rangeParts[0].equals("0")) { - resourceResponse.setStatusCode(200); + webResponse.setHeader("Content-Range", "bytes 0-" + (length - 1) + "/" + + length); resourceResponse.setContentLength(length); } else { - rangeHeader = rangeHeader.replaceAll(" ", ""); - // If the range header is filled 206 for - // partial content has to be returned - resourceResponse.setStatusCode(206); - - // And now the calculation of the range to be read - // and to be given as response within the Content-Range header - String range = rangeHeader.substring(rangeHeader.indexOf('=') + 1, - rangeHeader.length()); - String[] rangeParts = range.split("-"); - if (rangeParts[0].equals("0")) + startbyte = Long.parseLong(rangeParts[0]); + if (rangeParts.length == 2) { - webResponse.setHeader("Content-Range", "bytes 0-" + (length - 1) + - "/" + length); - resourceResponse.setContentLength(length); + endbyte = Long.parseLong(rangeParts[1]); } else { - startbyte = Long.parseLong(rangeParts[0]); - if (rangeParts.length == 2) - { - endbyte = Long.parseLong(rangeParts[1]); - } - else - { - endbyte = length - 1; - } - webResponse.setHeader("Content-Range", "bytes " + startbyte + "-" + - endbyte + "/" + length); - resourceResponse.setContentLength((endbyte - startbyte) + 1); + endbyte = length - 1; } + webResponse.setHeader("Content-Range", "bytes " + startbyte + "-" + + endbyte + "/" + length); + resourceResponse.setContentLength((endbyte - startbyte) + 1); } + } - resourceResponse.setWriteCallback(new WriteCallback() - { - @Override - public void writeData(Attributes attributes) throws IOException - { - try - { - InputStream inputStream = packageResourceStream.getInputStream(); - OutputStream outputStream = attributes.getResponse() - .getOutputStream(); - byte[] buffer = new byte[MediaStreamingResourceReference.this.getBuffer()]; - - if (startbyte != null || endbyte != null) - { - // skipping the first bytes which are - // not requested by the client - inputStream.skip(startbyte); - - long totalBytes = 0; - int actualReadBytes = 0; - - while ((actualReadBytes = inputStream.read(buffer)) != -1) - { - totalBytes = totalBytes + buffer.length; - long lowerBuffer = endbyte - totalBytes; - if (lowerBuffer <= 0) - { - buffer = (byte[])resizeArray(buffer, - actualReadBytes); - outputStream.write(buffer); - break; - } - else - { - outputStream.write(buffer); - } - } - } - else - { - while (inputStream.read(buffer) != -1) - { - outputStream.write(buffer); - } - } - } - catch (ResponseIOException e) - { - // the client has closed the connection and - // doesn't read the stream further on - // (in tomcats - // org.apache.catalina.connector.ClientAbortException) - // we ignore this case - } - catch (Exception e) - { - throw new WicketRuntimeException( - "A problem occurred while writing the buffer to the output stream.", - e); - } - } - }); + // Apply the writer callback to send the requested part to the client + resourceResponse.setWriteCallback(new PartWriterCallback( + packageResourceStream, startbyte, endbyte)); - return resourceResponse; - } - else - { - throw new IllegalStateException( - "Either the request is no web request or the response is no web response"); - } + return resourceResponse; } catch (Exception e) { @@ -249,51 +188,6 @@ public class MediaStreamingResourceReference extends ResourceReference } /** - * Sets the buffer size used to send the data to the client - * - * @return the buffer size used to send the data to the client - */ - public Integer getBuffer() - { - return buffer != null ? buffer : 4048; - } - - /** - * Sets the buffer size used to send the data to the client - * - * @param buffer - * the buffer size used to send the data to the client - */ - public void setBuffer(Integer buffer) - { - this.buffer = buffer; - } - - /** - * Reallocates an array with a new size, and copies the contents of the old array to the new - * array. - * - * @param oldArray - * the old array, to be reallocated. - * @param newSize - * the new array size. - * @return A new array with the same contents. - */ - @SuppressWarnings("rawtypes") - private static Object resizeArray(Object oldArray, int newSize) - { - int oldSize = java.lang.reflect.Array.getLength(oldArray); - Class elementType = oldArray.getClass().getComponentType(); - Object newArray = java.lang.reflect.Array.newInstance(elementType, newSize); - int preserveLength = Math.min(oldSize, newSize); - if (preserveLength > 0) - { - System.arraycopy(oldArray, 0, newArray, 0, preserveLength); - } - return newArray; - } - - /** * Gets the type of the media this resource reference belongs to * * @return the type of this media http://git-wip-us.apache.org/repos/asf/wicket/blob/4434d94f/wicket-core/src/main/java/org/apache/wicket/markup/html/media/PartWriterCallback.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/PartWriterCallback.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/PartWriterCallback.java new file mode 100644 index 0000000..694544d --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/PartWriterCallback.java @@ -0,0 +1,188 @@ +/* + * 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.wicket.markup.html.media; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.wicket.WicketRuntimeException; +import org.apache.wicket.core.util.resource.PackageResourceStream; +import org.apache.wicket.protocol.http.servlet.ResponseIOException; +import org.apache.wicket.request.resource.AbstractResource.WriteCallback; +import org.apache.wicket.request.resource.IResource.Attributes; + +/** + * Used to read a part of the package resource stream and write it to the output stream of the + * response. + * + * @author Tobias Soloschenko + * + */ +public class PartWriterCallback extends WriteCallback +{ + private PackageResourceStream packageResourceStream; + + private Long startbyte; + + private Long endbyte; + + private Integer buffer; + + /** + * Creates a part writer callback.<br> + * <br> + * Reads a part of the given package resource stream. If the startbyte parameter is not null the + * number of bytes are skipped till the stream is read. If the endbyte is not null the stream is + * read till endbyte, else to the end of the whole stream. If startbyte and endbyte is null the + * whole stream is read. + * + * @param packageResourceStream + * the package resource stream to be read + * @param startbyte + * the start position to read from (if not null the number of bytes are skipped till + * the stream is read) + * @param endbyte + * the end position to read to (if not null the stream is going to be read till + * endbyte, else to the end of the whole stream) + */ + public PartWriterCallback(PackageResourceStream packageResourceStream, Long startbyte, + Long endbyte) + { + this.packageResourceStream = packageResourceStream; + this.startbyte = startbyte; + this.endbyte = endbyte; + } + + /** + * Writes the data + * + * @param Attributes + * the attributes to get the output stream of the response + */ + @Override + public void writeData(Attributes attributes) throws IOException + { + try + { + InputStream inputStream = packageResourceStream.getInputStream(); + OutputStream outputStream = attributes.getResponse().getOutputStream(); + byte[] buffer = new byte[getBuffer()]; + + if (startbyte != null || endbyte != null) + { + // skipping the first bytes which are + // requested to be skipped by the client + if (startbyte != null) + { + inputStream.skip(startbyte); + } + + // If there are no end bytes given read the whole stream till the end + if (endbyte == null) + { + endbyte = packageResourceStream.length().bytes(); + } + + long totalBytes = 0; + int actualReadBytes = 0; + + while ((actualReadBytes = inputStream.read(buffer)) != -1) + { + totalBytes = totalBytes + buffer.length; + long lowerBuffer = endbyte - totalBytes; + if (lowerBuffer <= 0) + { + buffer = (byte[])resizeArray(buffer, actualReadBytes); + outputStream.write(buffer); + break; + } + else + { + outputStream.write(buffer); + } + } + } + else + { + while (inputStream.read(buffer) != -1) + { + outputStream.write(buffer); + } + } + } + catch (ResponseIOException e) + { + // the client has closed the connection and + // doesn't read the stream further on + // (in tomcats + // org.apache.catalina.connector.ClientAbortException) + // we ignore this case + } + catch (Exception e) + { + throw new WicketRuntimeException( + "A problem occurred while writing the buffer to the output stream.", e); + } + } + + /** + * Reallocates an array with a new size, and copies the contents of the old array to the new + * array. + * + * @param oldArray + * the old array, to be reallocated. + * @param newSize + * the new array size. + * @return A new array with the same contents. + */ + @SuppressWarnings("rawtypes") + private static Object resizeArray(Object oldArray, int newSize) + { + int oldSize = java.lang.reflect.Array.getLength(oldArray); + Class elementType = oldArray.getClass().getComponentType(); + Object newArray = java.lang.reflect.Array.newInstance(elementType, newSize); + int preserveLength = Math.min(oldSize, newSize); + if (preserveLength > 0) + { + System.arraycopy(oldArray, 0, newArray, 0, preserveLength); + } + return newArray; + } + + /** + * Sets the buffer size used to send the data to the client + * + * @return the buffer size used to send the data to the client (default is 4048) + */ + public Integer getBuffer() + { + return buffer != null ? buffer : 4048; + } + + /** + * Sets the buffer size used to send the data to the client + * + * @param buffer + * the buffer size used to send the data to the client + */ + public void setBuffer(Integer buffer) + { + this.buffer = buffer; + } + +}
