Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java V2 Updated the S3 video render example #5948

Merged
merged 5 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 95 additions & 82 deletions javav2/usecases/create_spring_stream_app/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ public class VideoStreamController {
}

// Returns the video in the bucket specified by the ID value.
@RequestMapping(value = "/{id}/stream", method = RequestMethod.GET)
public Mono<ResponseEntity<byte[]>> streamVideo(@PathVariable String id) {
@GetMapping("/{id}/stream")
public Mono<ResponseEntity<StreamingResponseBody>> streamVideo(@PathVariable String id) {
String fileName = id;
return Mono.just(vid.getObjectBytes(bucket, fileName));
}
Expand All @@ -247,13 +247,15 @@ public class VideoStreamController {
The following Java code represents the **VideoStreamService** class. This class uses the Amazon S3 Java API (V2) to interact with content located in an Amazon S3 bucket. For example, the **getTags** method returns a collection of tags that are used to create the video menu. Likewise, the **getObjectBytes** reads bytes from a MP4 video. The byte array is used to create a **ResponseEntity** object. This object sets HTTP header information and the HTTP status code required to stream the video.

```java
package com.example;
package com.example;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.core.ResponseBytes;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
Expand All @@ -279,37 +281,40 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.BufferedOutputStream;
import java.io.StringWriter;
import java.time.Duration;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.springframework.http.HttpHeaders;

@Service
public class VideoStreamService {

public static final String CONTENT_TYPE = "Content-Type";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String VIDEO_CONTENT = "video/";

private S3Client getClient() {

return S3Client.builder()
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
.region(Region.US_WEST_2)
.build();
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
.region(Region.US_WEST_2)
.build();
}

// Places a new video into an Amazon S3 bucket.
public void putVideo(byte[] bytes, String bucketName, String fileName, String description) {
S3Client s3 = getClient();

try {
// Set the tags to apply to the object.
String theTags = "name="+fileName+"&description="+description;

PutObjectRequest putOb = PutObjectRequest.builder()
.bucket(bucketName)
.key(fileName)
.tagging(theTags)
.build();
.bucket(bucketName)
.key(fileName)
.tagging(theTags)
.build();

s3.putObject(putOb, RequestBody.fromBytes(bytes));

Expand All @@ -319,6 +324,7 @@ public class VideoStreamService {
}
}


// Returns a schema that describes all tags for all videos in the given bucket.
public String getTags(String bucketName){
S3Client s3 = getClient();
Expand All @@ -328,88 +334,96 @@ public class VideoStreamService {
.bucket(bucketName)
.build();

ListObjectsResponse res = s3.listObjects(listObjects);
List<S3Object> objects = res.contents();
List<String> keys = new ArrayList<>();
for (S3Object myValue: objects) {
String key = myValue.key(); // We need the key to get the tags.
GetObjectTaggingRequest getTaggingRequest = GetObjectTaggingRequest.builder()
.key(key)
.bucket(bucketName)
.build();

GetObjectTaggingResponse tags = s3.getObjectTagging(getTaggingRequest);
List<Tag> tagSet= tags.tagSet();
for (Tag tag : tagSet) {
keys.add(tag.value());
}
}

List<Tags> tagList = modList(keys);
return convertToString(toXml(tagList));

} catch (S3Exception e) {
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
}
ListObjectsResponse res = s3.listObjects(listObjects);
List<S3Object> objects = res.contents();
List<String> keys = new ArrayList<>();
for (S3Object myValue: objects) {
String key = myValue.key(); // We need the key to get the tags.
GetObjectTaggingRequest getTaggingRequest = GetObjectTaggingRequest.builder()
.key(key)
.bucket(bucketName)
.build();

GetObjectTaggingResponse tags = s3.getObjectTagging(getTaggingRequest);
List<Tag> tagSet= tags.tagSet();
for (Tag tag : tagSet) {
keys.add(tag.value());
}
}

List<Tags> tagList = modList(keys);
return convertToString(toXml(tagList));

} catch (S3Exception e) {
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
}
return "";
}

// Return a List where each element is a Tags object.
private List<Tags> modList(List<String> myList){
// Get the elements from the collection.
private List<Tags> modList(List<String> myList) {
int count = myList.size();
List<Tags> allTags = new ArrayList<>();
Tags myTag ;
ArrayList<String> keys = new ArrayList<>();
ArrayList<String> values = new ArrayList<>();

for ( int index=0; index < count; index++) {
if (index % 2 == 0)
keys.add(myList.get(index));
else
values.add(myList.get(index));
}

// Create a list where each element is a Tags object.
for (int r=0; r<keys.size(); r++){
myTag = new Tags();
myTag.setName(keys.get(r));
myTag.setDesc(values.get(r));
allTags.add(myTag);
}
return allTags;
return IntStream.range(0, count / 2)
.mapToObj(index -> {
Tags myTag = new Tags();
myTag.setName(myList.get(index * 2));
myTag.setDesc(myList.get(index * 2 + 1));
return myTag;
})
.collect(Collectors.toList());
}


// Reads a video from a bucket and returns a ResponseEntity.
public ResponseEntity<byte[]> getObjectBytes (String bucketName, String keyName) {
public ResponseEntity<StreamingResponseBody> getObjectBytes(String bucketName, String keyName) {
S3Client s3 = getClient();
try {
// create a GetObjectRequest instance.
GetObjectRequest objectRequest = GetObjectRequest
.builder()
.key(keyName)
.bucket(bucketName)
.build();
// Create an S3 object request.
GetObjectRequest objectRequest = GetObjectRequest.builder()
.bucket(bucketName)
.key(keyName)
.build();

// get the byte[] from this AWS S3 object and return a ResponseEntity.
ResponseBytes<GetObjectResponse> objectBytes = s3.getObjectAsBytes(objectRequest);
return ResponseEntity.status(HttpStatus.OK)
.header(CONTENT_TYPE, VIDEO_CONTENT + "mp4")
.header(CONTENT_LENGTH, String.valueOf(objectBytes.asByteArray().length))
.body(objectBytes.asByteArray());
// Get the S3 object stream.
ResponseInputStream<GetObjectResponse> objectStream = s3.getObject(objectRequest);

} catch (S3Exception e) {
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
// Set content type and length headers.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf(VIDEO_CONTENT + "mp4"));

// Set content length if available.
Long contentLength = objectStream.response().contentLength();
if (contentLength != null) {
headers.setContentLength(contentLength);
}

// Set disposition as inline to display content in the browser.
headers.setContentDispositionFormData("inline", keyName);

// Create a StreamingResponseBody to stream the content.
StreamingResponseBody responseBody = outputStream -> {
try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
byte[] buffer = new byte[1024 * 1024];
int bytesRead;
while ((bytesRead = objectStream.read(buffer)) != -1) {
bufferedOutputStream.write(buffer, 0, bytesRead);
}
bufferedOutputStream.flush();
} finally {
objectStream.close();
}
};

return new ResponseEntity<>(responseBody, headers, HttpStatus.OK);
} catch (Exception e) {
// Handle exceptions and return an appropriate ResponseEntity.
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
return null;
}


// Convert a LIST to XML data.
private Document toXml(List<Tags> itemList) {
private Document toXml(List<Tags> itemList) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
Expand All @@ -422,7 +436,6 @@ public class VideoStreamService {

// Iterate through the list.
for (Tags myItem: itemList) {

Element item = doc.createElement( "Tag" );
root.appendChild( item );

Expand All @@ -447,13 +460,14 @@ public class VideoStreamService {
private String convertToString(Document xml) {
try {
TransformerFactory transformerFactory = getSecureTransformerFactory();
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer transformer = transformerFactory.newTransformer();
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(xml);
transformer.transform(source, result);
return result.getWriter().toString();

} catch(TransformerException ex) {
} catch (TransformerException ex) {
ex.printStackTrace();
}
return null;
Expand All @@ -469,7 +483,6 @@ public class VideoStreamService {
return transformerFactory;
}
}

```

## Create the HTML file
Expand Down
8 changes: 3 additions & 5 deletions javav2/usecases/create_spring_stream_app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<java.version>11</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.21.20</version>
<version>2.20.45</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
scmacdon marked this conversation as resolved.
Show resolved Hide resolved
SPDX-License-Identifier: Apache-2.0
*/

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;

@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class })
public class Application {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package com.example;

Expand All @@ -9,18 +11,18 @@ public class Tags {
private String description;

public String getDesc() {
return this.description;
return this.description ;
}

public void setDesc(String description) {
public void setDesc(String description){
this.description = description;
}

public String getName() {
return this.name;
return this.name ;
}

public void setName(String name) {
public void setName(String name){
this.name = name;
}
}
Loading
Loading