You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2015/03/30 21:01:28 UTC
[2/4] wicket git commit: WICKET-5819 Support for HTML 5 media tags
(audio / video)
WICKET-5819 Support for HTML 5 media tags (audio / video)
Move range handling code to AbstractResource.
Remove MediaStreamingResourceReference.
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/f623ceaa
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/f623ceaa
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/f623ceaa
Branch: refs/heads/master
Commit: f623ceaa93696427aafa8a15ecc86f2d0e362969
Parents: 499f11f
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Wed Mar 25 23:29:51 2015 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Mon Mar 30 21:59:14 2015 +0300
----------------------------------------------------------------------
.../markup/html/media/MediaComponent.java | 29 +-
.../media/MediaStreamingResourceReference.java | 182 ------------
.../markup/html/media/PartWriterCallback.java | 185 ------------
.../apache/wicket/markup/html/media/Source.java | 36 ++-
.../wicket/markup/html/media/audio/Audio.java | 18 +-
.../wicket/markup/html/media/video/Video.java | 18 +-
.../request/resource/AbstractResource.java | 280 +++++++++++++++++--
.../request/resource/PackageResource.java | 90 +++---
.../request/resource/PartWriterCallback.java | 184 ++++++++++++
.../html/media/MediaTagsExtendedTestPage.java | 9 +-
.../markup/html/media/MediaTagsTestPage.java | 8 +-
.../org/apache/wicket/examples/media/Home.java | 7 +-
.../apache/wicket/request/http/WebResponse.java | 52 +++-
13 files changed, 583 insertions(+), 515 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaComponent.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaComponent.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaComponent.java
index 093cd8e..83186f9 100755
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaComponent.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaComponent.java
@@ -23,6 +23,7 @@ import org.apache.wicket.request.Url;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
+import org.apache.wicket.request.resource.PackageResourceReference;
/**
* The media component is used to provide basic functionality to the video and audio component. The
@@ -100,7 +101,7 @@ public abstract class MediaComponent extends WebMarkupContainer
private final PageParameters pageParameters;
- private final MediaStreamingResourceReference mediaStreamingResourceReference;
+ private final PackageResourceReference resourceReference;
private final String url;
@@ -133,31 +134,31 @@ public abstract class MediaComponent extends WebMarkupContainer
*
* @param id
* The component id
- * @param mediaStreamingResourceReference
+ * @param resourceReference
*/
- public MediaComponent(String id, MediaStreamingResourceReference mediaStreamingResourceReference)
+ public MediaComponent(String id, PackageResourceReference resourceReference)
{
- this(id, null, null, null, mediaStreamingResourceReference);
+ this(id, null, null, null, resourceReference);
}
public MediaComponent(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference)
+ PackageResourceReference resourceReference)
{
- this(id, model, null, null, mediaStreamingResourceReference);
+ this(id, model, null, null, resourceReference);
}
public MediaComponent(String id,
- MediaStreamingResourceReference mediaStreamingResourceReference,
+ PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- this(id, null, null, pageParameters, mediaStreamingResourceReference);
+ this(id, null, null, pageParameters, resourceReference);
}
public MediaComponent(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference,
+ PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- this(id, model, null, pageParameters, mediaStreamingResourceReference);
+ this(id, model, null, pageParameters, resourceReference);
}
public MediaComponent(String id, String url)
@@ -176,12 +177,12 @@ public abstract class MediaComponent extends WebMarkupContainer
}
private MediaComponent(String id, IModel<?> model, String url, PageParameters pageParameters,
- MediaStreamingResourceReference mediaStreamingResourceReference)
+ PackageResourceReference resourceReference)
{
super(id, model);
this.url = url;
this.pageParameters = pageParameters;
- this.mediaStreamingResourceReference = mediaStreamingResourceReference;
+ this.resourceReference = resourceReference;
}
@Override
@@ -197,10 +198,10 @@ public abstract class MediaComponent extends WebMarkupContainer
timeManagement += "#t=" + startTime + (endTime != null ? "," + endTime : "");
}
- if (mediaStreamingResourceReference != null)
+ if (resourceReference != null)
{
CharSequence urlToMediaReference = RequestCycle.get().urlFor(
- mediaStreamingResourceReference, pageParameters);
+ resourceReference, pageParameters);
tag.put("src", urlToMediaReference + timeManagement);
}
else if (url != null)
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/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
deleted file mode 100755
index 76a208f..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/MediaStreamingResourceReference.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.util.Locale;
-
-import org.apache.wicket.Application;
-import org.apache.wicket.WicketRuntimeException;
-import org.apache.wicket.request.Request;
-import org.apache.wicket.request.Response;
-import org.apache.wicket.request.http.WebRequest;
-import org.apache.wicket.request.http.WebResponse;
-import org.apache.wicket.request.resource.ContentDisposition;
-import org.apache.wicket.request.resource.PackageResource;
-import org.apache.wicket.request.resource.PackageResourceReference;
-import org.apache.wicket.util.resource.IResourceStream;
-import org.apache.wicket.util.string.Strings;
-
-/**
- * The media streaming resource reference is used to provided streamed data based on bytes requested
- * by the client for video and audio files
- *
- * @author Tobias Soloschenko
- */
-public class MediaStreamingResourceReference extends PackageResourceReference
-{
- private static final long serialVersionUID = 1L;
-
- public MediaStreamingResourceReference(Class<?> scope, String name, Locale locale,
- String style, String variation)
- {
- super(scope, name, locale, style, variation);
- }
-
- public MediaStreamingResourceReference(Class<?> scope, String name)
- {
- this(scope, name, null, null, null);
- }
-
- public MediaStreamingResourceReference(Key key)
- {
- super(key);
- }
-
- public MediaStreamingResourceReference(String name)
- {
- super(name);
- }
-
- @Override
- public PackageResource getResource()
- {
- return new PackageResource(getScope(), getName(), getLocale(), getStyle(), getVariation())
- {
- private static final long serialVersionUID = 1L;
-
- @Override
- protected ResourceResponse newResourceResponse(Attributes attributes)
- {
- IResourceStream resourceStream = getResourceStream();
- if (resourceStream == null)
- {
- throw new WicketRuntimeException("Cannot find resource: " + toString());
- }
- try
- {
- Request request = attributes.getRequest();
- Response response = attributes.getResponse();
-
- if (!(request instanceof WebRequest) || !(response instanceof WebResponse))
- {
- throw new IllegalStateException(
- "Web request/response are required! Request: " + request +
- ", response: " + response);
- }
-
- WebRequest webRequest = (WebRequest)request;
- WebResponse webResponse = (WebResponse)response;
-
- long length = resourceStream.length().bytes();
-
- ResourceResponse resourceResponse = new ResourceResponse();
- resourceResponse.setContentType(resourceStream.getContentType());
- resourceResponse.setFileName(MediaStreamingResourceReference.this.getName());
- resourceResponse.setContentDisposition(ContentDisposition.ATTACHMENT);
- resourceResponse.setLastModified(resourceStream.lastModifiedTime());
-
- // accept ranges, so that the player can
- // load and play content from a specific byte position
- webResponse.setHeader("Accept-Range", "bytes");
-
- Long startbyte = null;
- Long endbyte = null;
-
- // Calculating the response code and the byte range to be played
- String rangeHeader = webRequest.getHeader("range");
- if (Strings.isEmpty(rangeHeader))
- {
- resourceResponse.setStatusCode(200);
- resourceResponse.setContentLength(length);
- }
- else
- {
- rangeHeader = rangeHeader.replaceAll(" ", "");
- // 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 = Strings.split(range, '-');
-
- String startByteString = rangeParts[0];
- String endByteString = rangeParts[1];
-
- startbyte = startByteString != null && !startByteString.trim().equals("")
- ? Long.parseLong(startByteString) : 0;
- endbyte = endByteString != null && !endByteString.trim().equals("")
- ? Long.parseLong(endByteString) : length - 1;
-
- webResponse.setHeader("Content-Range", "bytes " + startbyte + '-' +
- endbyte + '/' + length);
- resourceResponse.setContentLength((endbyte - startbyte) + 1);
- }
-
- // Apply the writer callback to send the requested part to the client
- resourceResponse.setWriteCallback(new PartWriterCallback(resourceStream,
- startbyte, endbyte));
-
- return resourceResponse;
- }
- catch (Exception e)
- {
- throw new WicketRuntimeException(
- "A problem occurred while creating the video response.", e);
- }
- finally
- {
- try
- {
- resourceStream.close();
- }
- catch (IOException e)
- {
- throw new WicketRuntimeException(
- "A problem occurred while closing the video response stream.", e);
- }
- }
- }
- };
-
- }
-
- /**
- * Returns the mime type of the media this resource reference belongs to
- *
- * @return the mime type of this media
- */
- public String getType()
- {
- final String resourceName = MediaStreamingResourceReference.this.getName();
- return Application.get().getMimeType(resourceName);
- }
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/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
deleted file mode 100644
index da8abda..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/PartWriterCallback.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.protocol.http.servlet.ResponseIOException;
-import org.apache.wicket.request.resource.AbstractResource.WriteCallback;
-import org.apache.wicket.request.resource.IResource.Attributes;
-import org.apache.wicket.util.io.Streams;
-import org.apache.wicket.util.resource.IResourceStream;
-
-/**
- * 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 final IResourceStream resourceStream;
-
- private final Long startbyte;
-
- private Long endbyte;
-
- private int bufferSize;
-
- /**
- * Creates a part writer callback.<br>
- * <br>
- * Reads a part of the given 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 resourceStream
- * the resource stream to 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(IResourceStream resourceStream, Long startbyte,
- Long endbyte)
- {
- this.resourceStream = resourceStream;
- 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 = resourceStream.getInputStream();
- OutputStream outputStream = attributes.getResponse().getOutputStream();
- byte[] buffer = new byte[getBufferSize()];
-
- 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 = resourceStream.length().bytes();
- }
-
- long totalBytes = 0;
- int actualReadBytes;
-
- while ((actualReadBytes = inputStream.read(buffer)) != -1)
- {
- totalBytes = totalBytes + buffer.length;
- long lowerBuffer = endbyte - totalBytes;
- if (lowerBuffer <= 0)
- {
- buffer = resizeArray(buffer, actualReadBytes);
- outputStream.write(buffer);
- break;
- }
- else
- {
- outputStream.write(buffer);
- }
- }
- }
- else
- {
- Streams.copy(inputStream, outputStream, getBufferSize());
- }
- }
- 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 byte[] resizeArray(byte[] oldArray, int newSize)
- {
- int oldSize = oldArray.length;
- byte[] newArray = new byte[newSize];
- int minLength = Math.min(oldSize, newSize);
- if (minLength > 0)
- {
- System.arraycopy(oldArray, 0, newArray, 0, minLength);
- }
- 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 4096)
- */
- public int getBufferSize()
- {
- return bufferSize > 0 ? bufferSize : 4096;
- }
-
- /**
- * Sets the buffer size used to send the data to the client
- *
- * @param bufferSize
- * the buffer size used to send the data to the client
- */
- public void setBufferSize(int bufferSize)
- {
- this.bufferSize = bufferSize;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
index 76b4002..6b19e60 100755
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/Source.java
@@ -21,6 +21,9 @@ import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.PackageResource;
+import org.apache.wicket.request.resource.PackageResourceReference;
+import org.apache.wicket.util.resource.IResourceStream;
/**
* The source of an audio or a video media component
@@ -38,7 +41,7 @@ public class Source extends WebMarkupContainer
private String media;
- private final MediaStreamingResourceReference mediaStreamingResourceReference;
+ private final PackageResourceReference resourceReference;
private final PageParameters pageParameters;
@@ -54,28 +57,28 @@ public class Source extends WebMarkupContainer
this(id, model, null, null, null);
}
- public Source(String id, MediaStreamingResourceReference mediaStreamingResourceReference)
+ public Source(String id, PackageResourceReference resourceReference)
{
- this(id, null, null, null, mediaStreamingResourceReference);
+ this(id, null, null, null, resourceReference);
}
public Source(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference)
+ PackageResourceReference resourceReference)
{
- this(id, model, null, null, mediaStreamingResourceReference);
+ this(id, model, null, null, resourceReference);
}
- public Source(String id, MediaStreamingResourceReference mediaStreamingResourceReference,
+ public Source(String id, PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- this(id, null, null, pageParameters, mediaStreamingResourceReference);
+ this(id, null, null, pageParameters, resourceReference);
}
public Source(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference,
+ PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- this(id, model, null, pageParameters, mediaStreamingResourceReference);
+ this(id, model, null, pageParameters, resourceReference);
}
public Source(String id, String url)
@@ -89,12 +92,12 @@ public class Source extends WebMarkupContainer
}
private Source(String id, IModel<?> model, String url, PageParameters pageParameters,
- MediaStreamingResourceReference mediaStreamingResourceReference)
+ PackageResourceReference resourceReference)
{
super(id, model);
this.url = url;
this.pageParameters = pageParameters;
- this.mediaStreamingResourceReference = mediaStreamingResourceReference;
+ this.resourceReference = resourceReference;
}
@Override
@@ -103,9 +106,9 @@ public class Source extends WebMarkupContainer
checkComponentTag(tag, "source");
super.onComponentTag(tag);
- if (mediaStreamingResourceReference != null)
+ if (resourceReference != null)
{
- CharSequence url = RequestCycle.get().urlFor(mediaStreamingResourceReference, pageParameters);
+ CharSequence url = RequestCycle.get().urlFor(resourceReference, pageParameters);
tag.put("src", url);
} else if (url != null)
{
@@ -118,9 +121,12 @@ public class Source extends WebMarkupContainer
{
tag.put("type", type);
}
- else if (mediaStreamingResourceReference != null)
+ else if (resourceReference != null)
{
- tag.put("type", mediaStreamingResourceReference.getType());
+ PackageResource resource = resourceReference.getResource();
+ IResourceStream resourceStream = resource.getResourceStream();
+ String contentType = resourceStream.getContentType();
+ tag.put("type", contentType);
}
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/main/java/org/apache/wicket/markup/html/media/audio/Audio.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/audio/Audio.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/audio/Audio.java
index e16cb8b..c0592fa 100755
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/audio/Audio.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/audio/Audio.java
@@ -18,9 +18,9 @@ package org.apache.wicket.markup.html.media.audio;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.media.MediaComponent;
-import org.apache.wicket.markup.html.media.MediaStreamingResourceReference;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.PackageResourceReference;
/**
* An audio media component to playback audio files.
@@ -42,28 +42,28 @@ public class Audio extends MediaComponent
super(id, model);
}
- public Audio(String id, MediaStreamingResourceReference mediaStreamingResourceReference)
+ public Audio(String id, PackageResourceReference resourceReference)
{
- super(id, mediaStreamingResourceReference);
+ super(id, resourceReference);
}
public Audio(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference)
+ PackageResourceReference resourceReference)
{
- super(id, model, mediaStreamingResourceReference);
+ super(id, model, resourceReference);
}
- public Audio(String id, MediaStreamingResourceReference mediaStreamingResourceReference,
+ public Audio(String id, PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- super(id, mediaStreamingResourceReference, pageParameters);
+ super(id, resourceReference, pageParameters);
}
public Audio(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference,
+ PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- super(id, model, mediaStreamingResourceReference, pageParameters);
+ super(id, model, resourceReference, pageParameters);
}
public Audio(String id, String url)
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/main/java/org/apache/wicket/markup/html/media/video/Video.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/video/Video.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/video/Video.java
index b73ba3d..1106696 100755
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/media/video/Video.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/media/video/Video.java
@@ -18,10 +18,10 @@ package org.apache.wicket.markup.html.media.video;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.media.MediaComponent;
-import org.apache.wicket.markup.html.media.MediaStreamingResourceReference;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
/**
@@ -52,28 +52,28 @@ public class Video extends MediaComponent
super(id, model);
}
- public Video(String id, MediaStreamingResourceReference mediaStreamingResourceReference)
+ public Video(String id, PackageResourceReference resourceReference)
{
- super(id, mediaStreamingResourceReference);
+ super(id, resourceReference);
}
public Video(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference)
+ PackageResourceReference resourceReference)
{
- super(id, model, mediaStreamingResourceReference);
+ super(id, model, resourceReference);
}
- public Video(String id, MediaStreamingResourceReference mediaStreamingResourceReference,
+ public Video(String id, PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- super(id, mediaStreamingResourceReference, pageParameters);
+ super(id, resourceReference, pageParameters);
}
public Video(String id, IModel<?> model,
- MediaStreamingResourceReference mediaStreamingResourceReference,
+ PackageResourceReference resourceReference,
PageParameters pageParameters)
{
- super(id, model, mediaStreamingResourceReference, pageParameters);
+ super(id, model, resourceReference, pageParameters);
}
public Video(String id, String url)
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/main/java/org/apache/wicket/request/resource/AbstractResource.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/request/resource/AbstractResource.java b/wicket-core/src/main/java/org/apache/wicket/request/resource/AbstractResource.java
index 386b7b3..18764d4 100644
--- a/wicket-core/src/main/java/org/apache/wicket/request/resource/AbstractResource.java
+++ b/wicket-core/src/main/java/org/apache/wicket/request/resource/AbstractResource.java
@@ -24,9 +24,12 @@ import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import org.apache.wicket.Application;
+import org.apache.wicket.MetaDataKey;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.request.HttpHeaderCollection;
+import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
+import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebRequest;
import org.apache.wicket.request.http.WebResponse;
import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
@@ -34,6 +37,7 @@ import org.apache.wicket.request.resource.caching.IStaticCacheableResource;
import org.apache.wicket.util.io.Streams;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.lang.Classes;
+import org.apache.wicket.util.string.Strings;
import org.apache.wicket.util.time.Duration;
import org.apache.wicket.util.time.Time;
@@ -50,6 +54,39 @@ public abstract class AbstractResource implements IResource
/** header values that are managed internally and must not be set directly */
public static final Set<String> INTERNAL_HEADERS;
+ /** The meta data key of the content range start byte **/
+ public static final MetaDataKey<Long> CONTENT_RANGE_STARTBYTE = new MetaDataKey<Long>()
+ {
+ private static final long serialVersionUID = 1L;
+ };
+
+ /** The meta data key of the content range end byte **/
+ public static final MetaDataKey<Long> CONTENT_RANGE_ENDBYTE = new MetaDataKey<Long>()
+ {
+ private static final long serialVersionUID = 1L;
+ };
+
+ /**
+ * All available content range types. The type name represents the name used in header
+ * information.
+ */
+ public enum ContentRangeType
+ {
+ BYTES("bytes"), NONE("none");
+
+ private final String typeName;
+
+ private ContentRangeType(String typeName)
+ {
+ this.typeName = typeName;
+ }
+
+ public String getTypeName()
+ {
+ return typeName;
+ }
+ }
+
static
{
INTERNAL_HEADERS = new HashSet<>();
@@ -63,6 +100,8 @@ public abstract class AbstractResource implements IResource
INTERNAL_HEADERS.add("transfer-encoding");
INTERNAL_HEADERS.add("connection");
INTERNAL_HEADERS.add("content-disposition");
+ INTERNAL_HEADERS.add("content-range");
+ INTERNAL_HEADERS.add("accept-range");
}
/**
@@ -94,6 +133,8 @@ public abstract class AbstractResource implements IResource
private String fileName = null;
private ContentDisposition contentDisposition = ContentDisposition.INLINE;
private String contentType = null;
+ private String contentRange = null;
+ private ContentRangeType contentRangeType = null;
private String textEncoding;
private long contentLength = -1;
private Time lastModified = null;
@@ -262,8 +303,53 @@ public abstract class AbstractResource implements IResource
}
/**
- * Sets the text encoding for the resource. This setting must only used
- * if the resource response represents text.
+ * Gets the content range of the resource. If no content range is set the client assumes the
+ * whole content.
+ *
+ * @return the content range
+ */
+ public String getContentRange()
+ {
+ return contentRange;
+ }
+
+ /**
+ * Sets the content range of the resource. If no content range is set the client assumes the
+ * whole content. Please note that if the content range is set, the content length, the
+ * status code and the accept range must be set right, too.
+ *
+ * @param contentRange
+ * the content range
+ */
+ public void setContentRange(String contentRange)
+ {
+ this.contentRange = contentRange;
+ }
+
+ /**
+ * If the resource accepts ranges
+ *
+ * @return the type of range (e.g. bytes)
+ */
+ public ContentRangeType getAcceptRange()
+ {
+ return contentRangeType;
+ }
+
+ /**
+ * Sets the accept range header (e.g. bytes)
+ *
+ * @param contentRangeType
+ * the content range header information
+ */
+ public void setAcceptRange(ContentRangeType contentRangeType)
+ {
+ this.contentRangeType = contentRangeType;
+ }
+
+ /**
+ * Sets the text encoding for the resource. This setting must only used if the resource
+ * response represents text.
*
* @param textEncoding
* character encoding of text body
@@ -534,6 +620,9 @@ public abstract class AbstractResource implements IResource
@Override
public void respond(final Attributes attributes)
{
+ // Sets the request attributes
+ setRequestMetaData(attributes);
+
// Get a "new" ResourceResponse to write a response
ResourceResponse data = newResourceResponse(attributes);
@@ -552,8 +641,8 @@ public abstract class AbstractResource implements IResource
// set response header
setResponseHeaders(data, attributes);
- if (!data.dataNeedsToBeWritten(attributes) || data.getErrorCode() != null
- || needsBody(data.getStatusCode()) == false)
+ if (!data.dataNeedsToBeWritten(attributes) || data.getErrorCode() != null ||
+ needsBody(data.getStatusCode()) == false)
{
return;
}
@@ -574,19 +663,19 @@ public abstract class AbstractResource implements IResource
}
/**
- * Decides whether a response body should be written back to the client depending
- * on the set status code
+ * Decides whether a response body should be written back to the client depending on the set
+ * status code
*
* @param statusCode
- * the status code set by the application
+ * the status code set by the application
* @return {@code true} if the status code allows response body, {@code false} - otherwise
*/
private boolean needsBody(Integer statusCode)
{
return statusCode == null ||
- (statusCode < 300 &&
- statusCode != HttpServletResponse.SC_NO_CONTENT &&
- statusCode != HttpServletResponse.SC_RESET_CONTENT);
+ (statusCode < 300 &&
+ statusCode != HttpServletResponse.SC_NO_CONTENT &&
+ statusCode != HttpServletResponse.SC_RESET_CONTENT);
}
/**
@@ -606,15 +695,69 @@ public abstract class AbstractResource implements IResource
{
throw new IllegalArgumentException("you are not allowed to directly access header [" +
name + "], " + "use one of the other specialized methods of " +
- Classes.simpleName(getClass()) + " to get or modify its value");
+ Classes.simpleName(getClass()) + " to get or modify its value");
}
}
/**
- * @param data
+ * Reads the plain request header information and applies enriched information as meta data to
+ * the current request. Those information are available for the whole request cycle.
+ *
+ * @param attributes
+ * the attributes to get the plain request header information
+ */
+ protected void setRequestMetaData(Attributes attributes)
+ {
+ Request request = attributes.getRequest();
+ if (request instanceof WebRequest)
+ {
+ WebRequest webRequest = (WebRequest)request;
+
+ setRequestRangeMetaData(webRequest);
+ }
+ }
+
+ protected void setRequestRangeMetaData(WebRequest webRequest)
+ {
+ String rangeHeader = webRequest.getHeader("range");
+
+ // The content range header is only be calculated if a range is given
+ if (!Strings.isEmpty(rangeHeader) &&
+ rangeHeader.contains(ContentRangeType.BYTES.getTypeName()))
+ {
+ // fixing white spaces
+ rangeHeader = rangeHeader.replaceAll(" ", "");
+
+ String range = rangeHeader.substring(rangeHeader.indexOf('=') + 1,
+ rangeHeader.length());
+
+ String[] rangeParts = Strings.split(range, '-');
+
+ String startByteString = rangeParts[0];
+ String endByteString = rangeParts[1];
+
+ Long startbyte = startByteString != null && !startByteString.trim().equals("")
+ ? Long.parseLong(startByteString) : 0;
+ Long endbyte = endByteString != null && !endByteString.trim().equals("")
+ ? Long.parseLong(endByteString) : -1;
+
+ // Make the content range information available for the whole request cycle
+ RequestCycle.get().setMetaData(CONTENT_RANGE_STARTBYTE, startbyte);
+ RequestCycle.get().setMetaData(CONTENT_RANGE_ENDBYTE, endbyte);
+ }
+ }
+
+ /**
+ * Sets the response header of resource response to the response received from the attributes
+ *
+ * @param resourceResponse
+ * the resource response to get the header fields from
* @param attributes
+ * the attributes to get the response from to which the header information are going
+ * to be applied
*/
- protected void setResponseHeaders(final ResourceResponse data, final Attributes attributes)
+ protected void setResponseHeaders(final ResourceResponse resourceResponse,
+ final Attributes attributes)
{
Response response = attributes.getResponse();
if (response instanceof WebResponse)
@@ -622,38 +765,36 @@ public abstract class AbstractResource implements IResource
WebResponse webResponse = (WebResponse)response;
// 1. Last Modified
- Time lastModified = data.getLastModified();
+ Time lastModified = resourceResponse.getLastModified();
if (lastModified != null)
{
webResponse.setLastModifiedTime(lastModified);
}
// 2. Caching
- configureCache(data, attributes);
+ configureCache(resourceResponse, attributes);
- if (data.getErrorCode() != null)
+ if (resourceResponse.getErrorCode() != null)
{
- webResponse.sendError(data.getErrorCode(), data.getErrorMessage());
+ webResponse.sendError(resourceResponse.getErrorCode(),
+ resourceResponse.getErrorMessage());
return;
}
- if (data.getStatusCode() != null)
+ if (resourceResponse.getStatusCode() != null)
{
- webResponse.setStatus(data.getStatusCode());
+ webResponse.setStatus(resourceResponse.getStatusCode());
}
-
- if (!data.dataNeedsToBeWritten(attributes))
+
+ if (!resourceResponse.dataNeedsToBeWritten(attributes))
{
webResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
- String fileName = data.getFileName();
- ContentDisposition disposition = data.getContentDisposition();
- String mimeType = data.getContentType();
- long contentLength = data.getContentLength();
-
// 3. Content Disposition
+ String fileName = resourceResponse.getFileName();
+ ContentDisposition disposition = resourceResponse.getContentDisposition();
if (ContentDisposition.ATTACHMENT == disposition)
{
webResponse.setAttachmentHeader(fileName);
@@ -664,10 +805,11 @@ public abstract class AbstractResource implements IResource
}
// 4. Mime Type (+ encoding)
+ String mimeType = resourceResponse.getContentType();
if (mimeType != null)
{
- final String encoding = data.getTextEncoding();
-
+ final String encoding = resourceResponse.getTextEncoding();
+
if (encoding == null)
{
webResponse.setContentType(mimeType);
@@ -678,14 +820,46 @@ public abstract class AbstractResource implements IResource
}
}
- // 5. Content Length
- if (contentLength != -1)
+ // 5. Accept Range
+ ContentRangeType acceptRange = resourceResponse.getAcceptRange();
+ if (acceptRange != null)
+ {
+ webResponse.setAcceptRange(acceptRange.getTypeName());
+ }
+
+ long contentLength = resourceResponse.getContentLength();
+ boolean contentRangeApplied = false;
+
+ // 6. Content Range
+ // for more information take a look here:
+ // http://stackoverflow.com/questions/8293687/sample-http-range-request-session
+ // if the content range header has been set directly
+ // to the resource response use it otherwise calculate it
+ String contentRange = resourceResponse.getContentRange();
+ if (contentRange != null)
+ {
+ webResponse.setContentRange(contentRange);
+ }
+ else
+ {
+ // content length has to be set otherwise the content range header can not be
+ // calculated - accept range must be set to bytes - others are not supported at the
+ // moment
+ if (contentLength != -1 && ContentRangeType.BYTES.equals(acceptRange))
+ {
+ contentRangeApplied = setResponseContentRangeHeaderFields(webResponse,
+ attributes, contentLength);
+ }
+ }
+
+ // 7. Content Length
+ if (contentLength != -1 && !contentRangeApplied)
{
webResponse.setContentLength(contentLength);
}
// add custom headers and values
- final HttpHeaderCollection headers = data.getHeaders();
+ final HttpHeaderCollection headers = resourceResponse.getHeaders();
for (String name : headers.getHeaderNames())
{
@@ -698,6 +872,50 @@ public abstract class AbstractResource implements IResource
}
}
}
+
+ /**
+ * Sets the content range header fields to the given web response
+ *
+ * @param webResponse
+ * the web response to apply the content range information to
+ * @param attributes
+ * the attributes to get the request from
+ * @param contentLength
+ * the content length of the response
+ * @return if the content range header information has been applied
+ */
+ protected boolean setResponseContentRangeHeaderFields(WebResponse webResponse,
+ Attributes attributes, long contentLength)
+ {
+ boolean contentRangeApplied = false;
+ if (attributes.getRequest() instanceof WebRequest)
+ {
+ Long startbyte = RequestCycle.get().getMetaData(CONTENT_RANGE_STARTBYTE);
+ Long endbyte = RequestCycle.get().getMetaData(CONTENT_RANGE_ENDBYTE);
+
+ if (startbyte != null && endbyte != null)
+ {
+ // if end byte hasn't been set
+ if (endbyte == -1)
+ {
+ endbyte = contentLength - 1;
+ }
+
+ // Change the status code to 206 partial content
+ webResponse.setStatus(206);
+ // currently only bytes are supported.
+ webResponse.setContentRange(ContentRangeType.BYTES.getTypeName() + " " + startbyte +
+ '-' + endbyte + '/' + contentLength);
+ // content length must be overridden by the recalculated one
+ webResponse.setContentLength((endbyte - startbyte) + 1);
+
+ // content range has been applied do not set the content length again!
+ contentRangeApplied = true;
+ }
+ }
+ return contentRangeApplied;
+ }
+
/**
* Callback invoked when resource data needs to be written to response. Subclass needs to
* implement the {@link #writeData(org.apache.wicket.request.resource.IResource.Attributes)}
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
index 8c5b457..ab66014 100644
--- a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
+++ b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
@@ -136,15 +136,13 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
* controls whether {@link org.apache.wicket.request.resource.caching.IResourceCachingStrategy}
* should be applied to resource
*/
-
private boolean cachingEnabled = true;
-
+
/**
* text encoding (may be null) - only makes sense for character-based resources
*/
-
private String textEncoding = null;
-
+
/**
* Hidden constructor.
*
@@ -189,7 +187,7 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
{
return Session.get().getLocale();
}
-
+
return locale;
}
@@ -199,7 +197,7 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
{
return Session.get().getStyle();
}
-
+
return style;
}
@@ -216,7 +214,7 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
/**
* get text encoding (intented for character-based resources)
-
+ *
* @return custom encoding or {@code null} to use default
*/
public String getTextEncoding()
@@ -288,7 +286,7 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
if (resourceStream == null)
{
return sendResourceError(resourceResponse, HttpServletResponse.SC_NOT_FOUND,
- "Unable to find resource");
+ "Unable to find resource");
}
// add Last-Modified header (to support HEAD requests and If-Modified-Since)
@@ -307,27 +305,28 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
// set Content-Type (may be null)
resourceResponse.setContentType(contentType);
-
+
// set content encoding (may be null)
resourceResponse.setTextEncoding(getTextEncoding());
+ // supports accept range
+ resourceResponse.setAcceptRange(ContentRangeType.BYTES);
+
try
{
- // read resource data
- final byte[] bytes = IOUtils.toByteArray(resourceStream.getInputStream());
+ // read resource data to get the content length
+ long contentLength = IOUtils.toByteArray(resourceStream.getInputStream()).length;
// send Content-Length header
- resourceResponse.setContentLength(bytes.length);
+ resourceResponse.setContentLength(contentLength);
+
+ // get content range information
+ Long startbyte = RequestCycle.get().getMetaData(CONTENT_RANGE_STARTBYTE);
+ Long endbyte = RequestCycle.get().getMetaData(CONTENT_RANGE_ENDBYTE);
// send response body with resource data
- resourceResponse.setWriteCallback(new WriteCallback()
- {
- @Override
- public void writeData(Attributes attributes)
- {
- attributes.getResponse().write(bytes);
- }
- });
+ resourceResponse.setWriteCallback(new PartWriterCallback(
+ resourceStream.getInputStream(), contentLength, startbyte, endbyte));
}
catch (IOException e)
{
@@ -408,7 +407,7 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
{
return internalGetResourceStream(getCurrentStyle(), getCurrentLocale());
}
-
+
/**
* locate resource stream for current resource
*
@@ -421,7 +420,7 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
/**
* @return whether {@link org.apache.wicket.resource.ITextResourceCompressor} can be used to compress the
- * resource.
+ * resource.
*/
public boolean getCompress()
{
@@ -466,8 +465,8 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
if (accept(realPath) == false)
{
throw new PackageResourceBlockedException(
- "Access denied to (static) package resource " + absolutePath +
- ". See IPackageResourceGuard");
+ "Access denied to (static) package resource " + absolutePath +
+ ". See IPackageResourceGuard");
}
if (resourceStream != null)
@@ -478,11 +477,12 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
}
/**
- * An IResourceStream that processes the input stream of the original
- * IResourceStream
+ * An IResourceStream that processes the input stream of the original IResourceStream
*/
private class ProcessingResourceStream extends ResourceStreamWrapper
{
+ private static final long serialVersionUID = 1L;
+
private ProcessingResourceStream(IResourceStream delegate)
{
super(delegate);
@@ -496,10 +496,12 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
try
{
bytes = IOUtils.toByteArray(inputStream);
- } catch (IOException iox)
+ }
+ catch (IOException iox)
{
throw new WicketRuntimeException(iox);
- } finally
+ }
+ finally
{
IOUtils.closeQuietly(this);
}
@@ -523,8 +525,8 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
/**
* Checks whether access is granted for this resource.
*
- * By default IPackageResourceGuard is used to check the permissions but
- * the resource itself can also make the check.
+ * By default IPackageResourceGuard is used to check the permissions but the resource itself can
+ * also make the check.
*
* @param path
* resource path
@@ -548,7 +550,8 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
*/
public static boolean exists(final ResourceReference.Key key)
{
- return exists(key.getScopeClass(), key.getName(), key.getLocale(), key.getStyle(), key.getVariation());
+ return exists(key.getScopeClass(), key.getName(), key.getLocale(), key.getStyle(),
+ key.getVariation());
}
/**
@@ -622,15 +625,13 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
return false;
if (getClass() != obj.getClass())
return false;
-
+
PackageResource other = (PackageResource)obj;
-
- return Objects.equals(absolutePath, other.absolutePath)
- && Objects.equals(locale, other.locale)
- && Objects.equals(path, other.path)
- && Objects.equals(scopeName, other.scopeName)
- && Objects.equals(style, other.style)
- && Objects.equals(variation, other.variation);
+
+ return Objects.equals(absolutePath, other.absolutePath) &&
+ Objects.equals(locale, other.locale) && Objects.equals(path, other.path) &&
+ Objects.equals(scopeName, other.scopeName) && Objects.equals(style, other.style) &&
+ Objects.equals(variation, other.variation);
}
String getParentFolderPlaceholder()
@@ -675,12 +676,11 @@ public class PackageResource extends AbstractResource implements IStaticCacheabl
return false;
CacheKey cacheKey = (CacheKey)o;
-
- return Objects.equals(locale, cacheKey.locale)
- && Objects.equals(path, cacheKey.path)
- && Objects.equals(scopeName, cacheKey.scopeName)
- && Objects.equals(style, cacheKey.style)
- && Objects.equals(variation, cacheKey.variation);
+
+ return Objects.equals(locale, cacheKey.locale) && Objects.equals(path, cacheKey.path) &&
+ Objects.equals(scopeName, cacheKey.scopeName) &&
+ Objects.equals(style, cacheKey.style) &&
+ Objects.equals(variation, cacheKey.variation);
}
@Override
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/main/java/org/apache/wicket/request/resource/PartWriterCallback.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/request/resource/PartWriterCallback.java b/wicket-core/src/main/java/org/apache/wicket/request/resource/PartWriterCallback.java
new file mode 100644
index 0000000..ca70470
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/request/resource/PartWriterCallback.java
@@ -0,0 +1,184 @@
+/*
+ * 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.request.resource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.wicket.protocol.http.servlet.ResponseIOException;
+import org.apache.wicket.request.resource.AbstractResource.WriteCallback;
+import org.apache.wicket.request.resource.IResource.Attributes;
+import org.apache.wicket.util.io.Streams;
+
+/**
+ * Used to read a part of an input stream and writes it to the output stream of the response taken
+ * from attributes of the writeData method.
+ *
+ * @author Tobias Soloschenko
+ *
+ */
+public class PartWriterCallback extends WriteCallback
+{
+ private final InputStream inputStream;
+
+ private final Long contentLength;
+
+ private final Long startbyte;
+
+ private Long endbyte;
+
+ private int bufferSize;
+
+
+ /**
+ * Creates a part writer callback.<br>
+ * <br>
+ * Reads a part of the given input 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 inputStream
+ * the input stream to be read
+ * @param the
+ * content length
+ * @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(InputStream inputStream, Long contentLength, Long startbyte,
+ Long endbyte)
+ {
+ this.inputStream = inputStream;
+ this.contentLength = contentLength;
+ this.startbyte = startbyte;
+ this.endbyte = endbyte;
+ }
+
+ /**
+ * Writes the data
+ *
+ * @param attributes
+ * the attributes to get the output stream of the response
+ * @throws IOException
+ * if something went wrong while writing the data to the output stream
+ */
+ @Override
+ public void writeData(Attributes attributes) throws IOException
+ {
+ try
+ {
+ OutputStream outputStream = attributes.getResponse().getOutputStream();
+ byte[] buffer = new byte[getBufferSize()];
+
+ 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 || Long.valueOf(-1).equals(endbyte))
+ {
+ endbyte = contentLength;
+ }
+
+ long totalBytes = 0;
+ int actualReadBytes;
+
+ while ((actualReadBytes = inputStream.read(buffer)) != -1)
+ {
+ totalBytes = totalBytes + buffer.length;
+ long lowerBuffer = endbyte - totalBytes;
+ if (lowerBuffer <= 0)
+ {
+ buffer = resizeArray(buffer, actualReadBytes);
+ outputStream.write(buffer);
+ break;
+ }
+ else
+ {
+ outputStream.write(buffer);
+ }
+ }
+ }
+ else
+ {
+ Streams.copy(inputStream, outputStream, getBufferSize());
+ }
+ }
+ 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
+ }
+ }
+
+ /**
+ * 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.
+ */
+ private static byte[] resizeArray(byte[] oldArray, int newSize)
+ {
+ int oldSize = oldArray.length;
+ byte[] newArray = new byte[newSize];
+ int minLength = Math.min(oldSize, newSize);
+ if (minLength > 0)
+ {
+ System.arraycopy(oldArray, 0, newArray, 0, minLength);
+ }
+ 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 4096)
+ */
+ public int getBufferSize()
+ {
+ return bufferSize > 0 ? bufferSize : 4096;
+ }
+
+ /**
+ * Sets the buffer size used to send the data to the client
+ *
+ * @param bufferSize
+ * the buffer size used to send the data to the client
+ */
+ public void setBufferSize(int bufferSize)
+ {
+ this.bufferSize = bufferSize;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsExtendedTestPage.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsExtendedTestPage.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsExtendedTestPage.java
index b191c35..d4ad5b3 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsExtendedTestPage.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsExtendedTestPage.java
@@ -29,18 +29,19 @@ public class MediaTagsExtendedTestPage extends WebPage
public MediaTagsExtendedTestPage()
{
- Video video = new Video("video", new MediaStreamingResourceReference(
- MediaTagsTestPage.class, "dummyVideo.m4a"));
+ Video video = new Video("video", new PackageResourceReference(MediaTagsTestPage.class,
+ "dummyVideo.m4a"));
// source tag
- Source source = new Source("source","http://www.mytestpage.xc/video.m4a");
+ Source source = new Source("source", "http://www.mytestpage.xc/video.m4a");
source.setMedia("screen and (device-width:500px)");
source.setType("video/mp4");
source.setDisplayType(true);
video.add(source);
// tack tag
- Track track = new Track("track", new PackageResourceReference(MediaTagsTestPage.class,"dummySubtitles.vtt"));
+ Track track = new Track("track", new PackageResourceReference(MediaTagsTestPage.class,
+ "dummySubtitles.vtt"));
track.setKind(Kind.SUBTITLES);
track.setLabel("Subtitles of video");
track.setSrclang(Locale.GERMANY);
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsTestPage.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsTestPage.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsTestPage.java
index e8dbdd8..edc3ab4 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsTestPage.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/media/MediaTagsTestPage.java
@@ -31,8 +31,8 @@ public class MediaTagsTestPage extends WebPage
{
PageParameters pageParameters = new PageParameters();
pageParameters.set("test", "test");
- Audio audio = new Audio("audio", new MediaStreamingResourceReference(
- MediaTagsTestPage.class, "dummyAudio.mp3"), pageParameters);
+ Audio audio = new Audio("audio", new PackageResourceReference(MediaTagsTestPage.class,
+ "dummyAudio.mp3"), pageParameters);
audio.setAutoplay(true);
audio.setControls(true);
audio.setCrossOrigin(Cors.USER_CREDENTIALS);
@@ -42,8 +42,8 @@ public class MediaTagsTestPage extends WebPage
audio.setEndTime("10");
add(audio);
- Video video = new Video("video", new MediaStreamingResourceReference(
- MediaTagsTestPage.class, "dummyVideo.m4a"));
+ Video video = new Video("video", new PackageResourceReference(MediaTagsTestPage.class,
+ "dummyVideo.m4a"));
PageParameters pageParameters2 = new PageParameters();
pageParameters2.add("test2", "test2");
video.setPoster(new PackageResourceReference(MediaTagsTestPage.class, "dummyPoster.jpg"),
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-examples/src/main/java/org/apache/wicket/examples/media/Home.java
----------------------------------------------------------------------
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/media/Home.java b/wicket-examples/src/main/java/org/apache/wicket/examples/media/Home.java
index 87d70f5..9055ff1 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/media/Home.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/media/Home.java
@@ -21,7 +21,6 @@ import java.util.UUID;
import org.apache.wicket.examples.WicketExamplePage;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.html.media.MediaStreamingResourceReference;
import org.apache.wicket.markup.html.media.Source;
import org.apache.wicket.markup.html.media.video.Video;
import org.apache.wicket.request.mapper.parameter.PageParameters;
@@ -50,7 +49,7 @@ public final class Home extends WicketExamplePage
{
// Internal video with several options
- Video video1 = new Video("video1", new MediaStreamingResourceReference(Home.class,
+ Video video1 = new Video("video1", new PackageResourceReference(Home.class,
"video.mp4"));
video1.setAutoplay(false);
video1.setControls(true);
@@ -65,7 +64,7 @@ public final class Home extends WicketExamplePage
Video video2 = new Video("video2");
video2.setPoster(new PackageResourceReference(Home.class, "novideo.gif"));
- Source source2 = new Source("source2", new MediaStreamingResourceReference(Home.class,
+ Source source2 = new Source("source2", new PackageResourceReference(Home.class,
"video.mp4"));
// Need to be set to true to show the type
source2.setDisplayType(true);
@@ -86,7 +85,7 @@ public final class Home extends WicketExamplePage
/*
* // video with track
- * Video video4 = new Video("video4", new MediaStreamingResourceReference(Home.class, "dummyVideo.m4a"));
+ * Video video4 = new Video("video4", new PackageResourceReference(Home.class, "dummyVideo.m4a"));
*
* // source tag
* Source source4 = new Source("source4", "http://www.mytestpage.xc/video.m4a");
http://git-wip-us.apache.org/repos/asf/wicket/blob/f623ceaa/wicket-request/src/main/java/org/apache/wicket/request/http/WebResponse.java
----------------------------------------------------------------------
diff --git a/wicket-request/src/main/java/org/apache/wicket/request/http/WebResponse.java b/wicket-request/src/main/java/org/apache/wicket/request/http/WebResponse.java
index 0566d0c..a790d0b 100644
--- a/wicket-request/src/main/java/org/apache/wicket/request/http/WebResponse.java
+++ b/wicket-request/src/main/java/org/apache/wicket/request/http/WebResponse.java
@@ -97,6 +97,32 @@ public abstract class WebResponse extends Response
public abstract void setContentType(final String mimeType);
/**
+ * Sets the content range of the response. If no content range is set the client assumes the
+ * whole content. Please note that if the content range is set, the content length, the status
+ * code and the accept range must be set right, too.
+ *
+ * @param contentRange
+ * the content range
+ */
+ public void setContentRange(final String contentRange)
+ {
+ setHeader("Content-Range", contentRange);
+ }
+
+
+ /**
+ * Sets the accept range (e.g. bytes)
+ *
+ * @param acceptRange
+ * the accept range header information
+ */
+ public void setAcceptRange(final String acceptRange)
+ {
+ setHeader("Accept-Range", acceptRange);
+
+ }
+
+ /**
* Set the contents last modified time, if appropriate in the subclass.
*
* @param time
@@ -138,19 +164,18 @@ public abstract class WebResponse extends Response
}
/**
- * <a href="http://greenbytes.de/tech/tc2231/">Encodes</a> the value of the filename
- * used in "Content-Disposition" response header
+ * <a href="http://greenbytes.de/tech/tc2231/">Encodes</a> the value of the filename used in
+ * "Content-Disposition" response header
*
* @param filename
- * the non-encoded file name
+ * the non-encoded file name
* @return encoded filename
*/
private String encodeDispositionHeaderValue(final String filename)
{
- return (Strings.isEmpty(filename) ?
- "" :
- String.format("; filename=\"%1$s\"; filename*=UTF-8''%1$s",
- UrlEncoder.PATH_INSTANCE.encode(filename, "UTF-8")));
+ return (Strings.isEmpty(filename) ? "" : String.format(
+ "; filename=\"%1$s\"; filename*=UTF-8''%1$s",
+ UrlEncoder.PATH_INSTANCE.encode(filename, "UTF-8")));
}
/**
@@ -213,9 +238,9 @@ public abstract class WebResponse extends Response
/**
* Make this response cacheable
- * <p/>
- * when trying to enable caching for web pages check this out:
- * <a href="https://issues.apache.org/jira/browse/WICKET-4357">WICKET-4357</a>
+ * <p/>
+ * when trying to enable caching for web pages check this out: <a
+ * href="https://issues.apache.org/jira/browse/WICKET-4357">WICKET-4357</a>
*
* @param duration
* maximum duration before the response must be invalidated by any caches. It should
@@ -223,7 +248,7 @@ public abstract class WebResponse extends Response
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">RFC-2616</a>.
* @param scope
* controls which caches are allowed to cache the response
- *
+ *
* @see WebResponse#MAX_CACHE_DURATION
*/
public void enableCaching(Duration duration, final WebResponse.CacheScope scope)
@@ -248,7 +273,7 @@ public abstract class WebResponse extends Response
// Set cache scope
setHeader("Cache-Control", scope.cacheControl);
-
+
// Set maximum age for caching in seconds (rounded)
addHeader("Cache-Control", "max-age=" + Math.round(duration.seconds()));
@@ -266,7 +291,8 @@ public abstract class WebResponse extends Response
* href="http://palisade.plynt.com/issues/2008Jul/cache-control-attributes">here</a> or in <a
* href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">RFC-2616</a>.
*/
- public static enum CacheScope {
+ public static enum CacheScope
+ {
/**
* use all caches (private + public)
* <p/>