Starting from:

$27.99

Basic application for uploading video to a cloud service_Assignment 1 Solution

# Assignment 1 

## Running the Application

__You do not use "jettyRun" to launch this application. Please read these instructions__

To run the application:

Right-click on the Application class in the org.magnum.dataup
package, Run As-Java Application

To stop the application:

Open the Eclipse Debug Perspective (Window-Open Perspective-Debug), right-click on
the application in the "Debug" view (if it isn't open, Window-Show View-Debug) and
select Terminate

## Overview

A popular use of cloud services is to manage media that is uploaded
from mobile devices. This assignment will create a very basic application
for uploading video to a cloud service and managing the video's metadata.
Once you are able to build this basic type of infrastructure, you will have
the core knowledge needed to create much more sophisticated cloud services.


## Instructions

First, clone this Git repository and import it into Eclipse as described
in the development environment setup guide
[https://class.coursera.org/mobilecloud-001/wiki/Installing_Eclipse%2C_Git%2C_and_Gradle].

This assignment tests your ability to create a web application that
allows clients to upload videos to a server. The server allows clients
to first upload a video's metadata (e.g., duration, etc.) and then to
upload the actual binary data for the video. The server should support
uploading video binary data with a multipart request.

The test that is used to grade your implementation is AutoGradingTest
in the org.magnum.dataup package in src/test/java. **_You should use the
source code in the AutoGradingTest as the ground truth for what the expected
behavior of your solution is_.** Your app should pass this test without
any errors. The test methods are annotated with @Rubric and specify
the number of points associated with each test, the purpose of the test,
and the videos relevant to the test.

The HTTP API that you must implement so that this test will pass is as
follows:

GET /video
- Returns the list of videos that have been added to the
server as JSON. The list of videos does not have to be
persisted across restarts of the server. The list of
Video objects should be able to be unmarshalled by the
client into a Collection<Video.
- The return content-type should be application/json, which
will be the default if you use @ResponseBody


POST /video
- The video metadata is provided as an application/json request
body. The JSON should generate a valid instance of the
Video class when deserialized by Spring's default
Jackson library.
- Returns the JSON representation of the Video object that
was stored along with any updates to that object made by the server.
- **_The server should generate a unique identifier for the Video
object and assign it to the Video by calling its setId(...)
method._**
- No video should have ID = 0. All IDs should be 0.
- The returned Video JSON should include this server-generated
identifier so that the client can refer to it when uploading the
binary mpeg video content for the Video.
- The server should also generate a "data url" for the
Video. The "data url" is the url of the binary data for a
Video (e.g., the raw mpeg data). The URL should be the _full_ URL
for the video and not just the path (e.g., http://localhost:8080/video/1/data would
be a valid data url). See the Hints section for some ideas on how to
generate this URL.

POST /video/{id}/data
- The binary mpeg data for the video should be provided in a multipart
request as a part with the key "data". The id in the path should be
replaced with the unique identifier generated by the server for the
Video. A client MUST *create* a Video first by sending a POST to /video
and getting the identifier for the newly created Video object before
sending a POST to /video/{id}/data.
- The endpoint should return a VideoStatus object with state=VideoState.READY
if the request succeeds and the appropriate HTTP error status otherwise.
VideoState.PROCESSING is not used in this assignment but is present in VideoState.
- Rather than a PUT request, a POST is used because, by default, Spring
does not support a PUT with multipart data due to design decisions in the
Commons File Upload library: https://issues.apache.org/jira/browse/FILEUPLOAD-197


GET /video/{id}/data
- Returns the binary mpeg data (if any) for the video with the given
identifier. If no mpeg data has been uploaded for the specified video,
then the server should return a 404 status code.


The AutoGradingTest should be used as the ultimate ground truth for what should be
implemented in the assignment. If there are any details in the description above
that conflict with the AutoGradingTest, use the details in the AutoGradingTest
as the correct behavior and report the discrepancy on the course forums. Further,
you should look at the AutoGradingTest to ensure that
you understand all of the requirements. It is perfectly OK to post on the forums and
ask what a specific section of the AutoGradingTest does. Do not, however, post any
code from your solution or potential solution.

There is a VideoSvcApi interface that is annotated with Retrofit annotations in order
to communicate with the video service that you will be creating. Your solution controller(s)
should not directly implement this interface in a "Java sense" (e.g., you should not have
YourSolution implements VideoSvcApi). Your solution should support the HTTP API that
is described by this interface, in the text above, and in the AutoGradingTest. In some
cases it may be possible to have the Controller and the client implement the interface,
but it is not in this

Again -- the ultimate ground truth of how the assignment will be graded, is contained
in AutoGradingTest, which shows the specific tests that will be run to grade your
solution. You must implement everything that is required to make all of the tests in
this class pass. If a test case is not mentioned in this README file, you are still
responsible for it and will be graded on whether or not it passes. __Make sure and read
the AutoGradingTest code and look at each test__!

You should not modify any of the code in Video, VideoStatus, VideoSvcApi, AutoGrading,
or AutoGradingTest.

## Testing Your Implementation

To test your solution, first run the application as described above. Once your application
is running, you can right-click on the AutoGradingTest-Run As-JUnit Test to launch the
test. Eclipse will report which tests pass or fail.

To get an estimated score for your solution, right-click on AutoGrading (not AutoGradingTest) and
Run As-Java Application. The AutoGrading application will run AutoGradingTest and then print a
summary of the test results and your score to the Eclipse Console (Window-Show View-Console).
The AutoGrading application will also zip all of your source code into a submission package that
you can submit to Coursera to receive your official grade. Note: each time that you run AutoGrading
it will create a separate zip file. Make sure that you choose the right zip file when submitting
your assignment! All of the submission zip files are placed in the coursera-submission folder.

## Submitting Your Assignment

To submit your assignment, you must first run the AutoGrading application as described in the previous
step to create your submission zip file. Make sure that you take note of the name of the submission
package that is printed in the console to ensure that you submit the correct zip file. You should
submit the submission package that is generated in the coursera-submission folder as the
"Output Submission". Leave the "Additional Submission" empty.

After submitting your solution to Coursera, your submission package will be sent to the auto-grading
servers. It may take a few minutes for a score to be assigned to your submission. Once the submission
is graded, a detailed score will be registered with Coursera.

Note: locally running the AutoGrading application DOES NOT submit your solution to Coursera and will
not be counted as a valid submission. The grade that you see when running the AutoGrading application
is an estimate of your grade only. You must correctly submit the solution to Coursera to receive an
official grade.


## Provided Code

- __org.magnum.dataup.Video__: This is a simple class to represent the metadata for a video.
You can create one using a builder like this:

```java
Video video = Video.create().withContentType("video/mpeg")
.withDuration(123).withSubject("Mobile Cloud")
.withTitle("Programming Cloud Services for ...").build();
```
You can also accept a Video from an application/json request body or return the
JSON of a video like this:
```java
@RequestMapping(value = "/funny/video", method = RequestMethod.POST)
public @ResponseBody Video addVideo(@RequestBody Video v){
// Do something with the Video
// ...
return v;
}
```
- __org.magnum.dataup.VideoFileManager__: This is a class that you can (but are not required) to
use to store video binary data to the file system. By default, it will store all videos to
a "videos" directory in the current working directory. You can use this class as follows:
```java
// Initialize this member variable somewhere with
// videoDataMgr = VideoFileManager.get()
//
private VideoFileManager videoDataMgr;

// You would need some Controller method to call this...
public void saveSomeVideo(Video v, MultipartFile videoData) throws IOException {
videoDataMgr.saveVideoData(video, videoData.getInputStream());
}

public void serveSomeVideo(Video v, HttpServletResponse response) throws IOException {
// Of course, you would need to send some headers, etc. to the
// client too!
// ...
videoDataMgr.copyVideoData(v, response.getOutputStream());
}
```


## Hints

- The examples in GitHub will be helpful on this assignment
- A valid solution is going to have at least one class annotated with @Controller
- There will probably need to be at least 4 different methods annotated with @RequestMapping to
implement the HTTP API described
- Any Controller method can take an HttpServletRequest or HttpServletResponse as parameters to
gain low-level access/control over the HTTP messages. Spring will automatically fill in these
parameters when your Controller's method is invoked:
```java
...
@RequestMapping("/some/path/{id}")
public MyObject doSomething(
@PathVariable("id") String id,
@RequestParam("something") String data,
HttpServletResponse response) {

// Maybe you want to set the status code with the response
// or write some binary data to an OutputStream obtained from
// the HttpServletResponse object
....
}

```
- The IDs must be of type long. The tests send long values to the server and will generate
400 response codes if you use an int.
- If you get an error 400, you have incorrectly specified the parameter values that the method
should accept and their mapping to HTTP parameters.
- One of the Controller methods that is annotated with @RequestMapping is probably going to need
to take an HttpServletResponse object as a parameter and use this object to write out binary data
that should be sent to the client.
- There are multiple ways to implement most pieces of the application. Any solution that passes
the tests will be given full credit.
- None of your Controllers or other classes should "implement VideoSvcApi" -- which is an interface
that is only used to create a Retrofit client. None of your classes should look like this:
```java
public class SomeClass implements VideoSvcApi // Don't implement this interface!
{
...
}
```
- You can use a method like the following to figure out the address of your server and generate a
data url for a video:
```java
private String getDataUrl(long videoId){
String url = getUrlBaseForLocalServer() + "/video/" + videoId + "/data";
return url;
}

private String getUrlBaseForLocalServer() {
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String base =
"http://"+request.getServerName()
+ ((request.getServerPort() != 80) ? ":"+request.getServerPort() : "");
return base;
}
```
- One way to generate a unique ID for each video is to use an AtomicLong similar to this:
```java
private static final AtomicLong currentId = new AtomicLong(0L);

private Map<Long,Video videos = new HashMap<Long, Video();

public Video save(Video entity) {
checkAndSetId(entity);
videos.put(entity.getId(), entity);
return entity;
}

private void checkAndSetId(Video entity) {
if(entity.getId() == 0){
entity.setId(currentId.incrementAndGet());
}
}
```

More products