1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.workingfilerepository.impl;
23
24 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
25 import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
26 import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
27 import static javax.servlet.http.HttpServletResponse.SC_OK;
28 import static org.opencastproject.util.MimeTypes.getMimeType;
29 import static org.opencastproject.util.RestUtil.R.ok;
30 import static org.opencastproject.util.RestUtil.fileResponse;
31 import static org.opencastproject.util.RestUtil.partialFileResponse;
32 import static org.opencastproject.util.doc.rest.RestParameter.Type.FILE;
33 import static org.opencastproject.util.doc.rest.RestParameter.Type.STRING;
34
35 import org.opencastproject.security.api.SecurityService;
36 import org.opencastproject.serviceregistry.api.ServiceRegistry;
37 import org.opencastproject.util.MimeTypes;
38 import org.opencastproject.util.NotFoundException;
39 import org.opencastproject.util.UnknownFileTypeException;
40 import org.opencastproject.util.doc.rest.RestParameter;
41 import org.opencastproject.util.doc.rest.RestQuery;
42 import org.opencastproject.util.doc.rest.RestResponse;
43 import org.opencastproject.util.doc.rest.RestService;
44 import org.opencastproject.workingfilerepository.api.PathMappable;
45 import org.opencastproject.workingfilerepository.api.WorkingFileRepository;
46
47 import org.apache.commons.fileupload.FileItemIterator;
48 import org.apache.commons.fileupload.FileItemStream;
49 import org.apache.commons.fileupload.servlet.ServletFileUpload;
50 import org.apache.commons.io.IOUtils;
51 import org.apache.commons.lang3.StringUtils;
52 import org.apache.http.HttpStatus;
53 import org.json.simple.JSONArray;
54 import org.json.simple.JSONObject;
55 import org.osgi.service.component.ComponentContext;
56 import org.osgi.service.component.annotations.Activate;
57 import org.osgi.service.component.annotations.Component;
58 import org.osgi.service.component.annotations.Deactivate;
59 import org.osgi.service.component.annotations.Reference;
60 import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import java.io.File;
65 import java.io.IOException;
66 import java.net.URI;
67 import java.util.Optional;
68
69 import javax.servlet.http.HttpServletRequest;
70 import javax.ws.rs.DELETE;
71 import javax.ws.rs.FormParam;
72 import javax.ws.rs.GET;
73 import javax.ws.rs.HeaderParam;
74 import javax.ws.rs.POST;
75 import javax.ws.rs.Path;
76 import javax.ws.rs.PathParam;
77 import javax.ws.rs.Produces;
78 import javax.ws.rs.core.Context;
79 import javax.ws.rs.core.MediaType;
80 import javax.ws.rs.core.Response;
81
82 @Path("/files")
83 @RestService(name = "filerepo", title = "Working File Repository", abstractText = "Stores and retrieves files for use during media processing.", notes = {
84 "All paths above are relative to the REST endpoint base (something like http://your.server/files)",
85 "If the service is down or not working it will return a status 503, this means the the underlying service is "
86 + "not working and is either restarting or has failed",
87 "A status code 500 means a general failure has occurred which is not recoverable and was not anticipated. In "
88 + "other words, there is a bug! You should file an error report with your server logs from the time when the "
89 + "error occurred: <a href=\"https://github.com/opencast/opencast/issues\">Opencast Issue Tracker</a>" })
90 @Component(
91 name = "org.opencastproject.workingfilerepository.impl.WorkingFileRepository",
92 property = {
93 "service.description=Working File Repository REST Endpoint",
94 "opencast.service.type=org.opencastproject.files",
95 "opencast.service.path=/files"
96 },
97 immediate = true,
98 service = { WorkingFileRepositoryRestEndpoint.class, WorkingFileRepository.class, PathMappable.class }
99 )
100 @JaxrsResource
101 public class WorkingFileRepositoryRestEndpoint extends WorkingFileRepositoryImpl {
102
103 private static final Logger logger = LoggerFactory.getLogger(WorkingFileRepositoryRestEndpoint.class);
104
105
106
107
108
109
110
111 @Override
112 @Activate
113 public void activate(ComponentContext cc) throws IOException {
114 super.activate(cc);
115 }
116
117
118
119
120 @Override
121 @Deactivate
122 public void deactivate() {
123 super.deactivate();
124 }
125
126
127
128
129
130
131 @Override
132 @Reference
133 public void setRemoteServiceManager(ServiceRegistry remoteServiceManager) {
134 super.setRemoteServiceManager(remoteServiceManager);
135 }
136
137 @Override
138 @Reference
139 public void setSecurityService(SecurityService securityService) {
140 super.setSecurityService(securityService);
141 }
142
143 @POST
144 @Produces(MediaType.TEXT_HTML)
145 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}")
146 @RestQuery(name = "put", description = "Store a file in working repository under ./mediaPackageID/mediaPackageElementID", returnDescription = "The URL to access the stored file", pathParameters = {
147 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true, type = STRING),
148 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier", isRequired = true, type = STRING) }, responses = { @RestResponse(responseCode = SC_OK, description = "OK, file stored") }, restParameters = { @RestParameter(name = "file", description = "the filename", isRequired = true, type = FILE) })
149 public Response restPut(@PathParam("mediaPackageID") String mediaPackageID,
150 @PathParam("mediaPackageElementID") String mediaPackageElementID, @Context HttpServletRequest request)
151 throws Exception {
152 if (ServletFileUpload.isMultipartContent(request)) {
153 for (FileItemIterator iter = new ServletFileUpload().getItemIterator(request); iter.hasNext();) {
154 FileItemStream item = iter.next();
155 if (item.isFormField()) {
156 continue;
157
158 }
159 URI url = this.put(mediaPackageID, mediaPackageElementID, item.getName(), item.openStream());
160 return Response.ok(url.toString()).build();
161 }
162 }
163 return Response.serverError().status(400).build();
164 }
165
166 @POST
167 @Produces(MediaType.TEXT_HTML)
168 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}/{filename}")
169 @RestQuery(name = "putWithFilename", description = "Store a file in working repository under ./mediaPackageID/mediaPackageElementID/filename", returnDescription = "The URL to access the stored file", pathParameters = {
170 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true, type = STRING),
171 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier", isRequired = true, type = STRING),
172 @RestParameter(name = "filename", description = "the filename", isRequired = true, type = FILE) }, responses = { @RestResponse(responseCode = SC_OK, description = "OK, file stored") })
173 public Response restPutURLEncoded(@Context HttpServletRequest request,
174 @PathParam("mediaPackageID") String mediaPackageID,
175 @PathParam("mediaPackageElementID") String mediaPackageElementID, @PathParam("filename") String filename,
176 @FormParam("content") String content) throws Exception {
177 String encoding = request.getCharacterEncoding();
178 if (encoding == null)
179 encoding = "utf-8";
180
181 URI url = this.put(mediaPackageID, mediaPackageElementID, filename, IOUtils.toInputStream(content, encoding));
182 return Response.ok(url.toString()).build();
183 }
184
185 @POST
186 @Produces(MediaType.TEXT_HTML)
187 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "{collectionId}")
188 @RestQuery(name = "putInCollection", description = "Store a file in working repository under ./collectionId/filename", returnDescription = "The URL to access the stored file", pathParameters = { @RestParameter(name = "collectionId", description = "the colection identifier", isRequired = true, type = STRING) }, restParameters = { @RestParameter(name = "file", description = "the filename", isRequired = true, type = FILE) }, responses = { @RestResponse(responseCode = SC_OK, description = "OK, file stored") })
189 public Response restPutInCollection(@PathParam("collectionId") String collectionId,
190 @Context HttpServletRequest request) throws Exception {
191 if (ServletFileUpload.isMultipartContent(request)) {
192 for (FileItemIterator iter = new ServletFileUpload().getItemIterator(request); iter.hasNext();) {
193 FileItemStream item = iter.next();
194 if (item.isFormField()) {
195 continue;
196
197 }
198 URI url = this.putInCollection(collectionId, item.getName(), item.openStream());
199 return Response.ok(url.toString()).build();
200 }
201 }
202 return Response.serverError().status(400).build();
203 }
204
205 @DELETE
206 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}")
207 @RestQuery(name = "delete", description = "Remove the file from the working repository under /mediaPackageID/mediaPackageElementID", returnDescription = "No content", pathParameters = {
208 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true, type = STRING),
209 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier", isRequired = true, type = STRING) }, responses = {
210 @RestResponse(responseCode = SC_OK, description = "File deleted"),
211 @RestResponse(responseCode = SC_NOT_FOUND, description = "File did not exist") })
212 public Response restDelete(@PathParam("mediaPackageID") String mediaPackageID,
213 @PathParam("mediaPackageElementID") String mediaPackageElementID) {
214 try {
215 if (delete(mediaPackageID, mediaPackageElementID))
216 return Response.ok().build();
217 else
218 return Response.status(HttpStatus.SC_NOT_FOUND).build();
219 } catch (Exception e) {
220 logger.error("Unable to delete element '{}' from mediapackage '{}'", mediaPackageElementID,
221 mediaPackageID, e);
222 return Response.serverError().entity(e.getMessage()).build();
223 }
224 }
225
226 @DELETE
227 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "{collectionId}/{fileName}")
228 @RestQuery(name = "deleteFromCollection", description = "Remove the file from the working repository under /collectionId/filename", returnDescription = "No content", pathParameters = {
229 @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true, type = STRING),
230 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING) }, responses = {
231 @RestResponse(responseCode = SC_NO_CONTENT, description = "File deleted"),
232 @RestResponse(responseCode = SC_NOT_FOUND, description = "Collection or file not found") })
233 public Response restDeleteFromCollection(@PathParam("collectionId") String collectionId,
234 @PathParam("fileName") String fileName) {
235 try {
236 if (this.deleteFromCollection(collectionId, fileName))
237 return Response.noContent().build();
238 else
239 return Response.status(SC_NOT_FOUND).build();
240 } catch (Exception e) {
241 logger.error("Unable to delete element '{}' from collection '{}'", fileName, collectionId, e);
242 return Response.serverError().entity(e.getMessage()).build();
243 }
244 }
245
246 @DELETE
247 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "cleanup/{collectionId}/{numberOfDays}")
248 @RestQuery(name = "cleanupOldFilesFromCollection", description = "Remove the files from the working repository under /collectionId that are older than N days", returnDescription = "No content", pathParameters = {
249 @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true, type = STRING),
250 @RestParameter(name = "numberOfDays", description = "files older than this number of days will be deleted", isRequired = true, type = STRING) }, responses = {
251 @RestResponse(responseCode = SC_NO_CONTENT, description = "Files deleted"),
252 @RestResponse(responseCode = SC_NOT_FOUND, description = "Collection not found") })
253 public Response restCleanupOldFilesFromCollection(@PathParam("collectionId") String collectionId,
254 @PathParam("numberOfDays") long days) {
255 try {
256 if (this.cleanupOldFilesFromCollection(collectionId, days))
257 return Response.noContent().build();
258 else
259 return Response.status(SC_NOT_FOUND).build();
260 } catch (Exception e) {
261 logger.error("Unable to delete files older than '{}' days from collection '{}'",
262 days, collectionId, e);
263 return Response.serverError().entity(e.getMessage()).build();
264 }
265 }
266
267 @DELETE
268 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "cleanup/mediapackage/{numberOfDays}")
269 @RestQuery(name = "cleanupOldFilesFromMediaPackage", description = "Remove files and directories from the working file repository under /mediapackage that are older than N days", returnDescription = "No content", pathParameters = {
270 @RestParameter(name = "numberOfDays", description = "files older than this number of days will be deleted", isRequired = true, type = STRING) }, responses = {
271 @RestResponse(responseCode = SC_NO_CONTENT, description = "Files deleted")})
272 public Response restCleanupOldFilesFromMediaPackage(@PathParam("numberOfDays") long days) {
273 try {
274 this.cleanupOldFilesFromMediaPackage(days);
275 return Response.noContent().build();
276 } catch (Exception e) {
277 return Response.serverError().entity(e.getMessage()).build();
278 }
279 }
280
281 @GET
282 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}")
283 @RestQuery(name = "get", description = "Gets the file from the working repository under /mediaPackageID/mediaPackageElementID", returnDescription = "The file", pathParameters = {
284 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true, type = STRING),
285 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier", isRequired = true, type = STRING) }, responses = {
286 @RestResponse(responseCode = SC_OK, description = "File returned"),
287 @RestResponse(responseCode = SC_NOT_MODIFIED, description = "If file not modified"),
288 @RestResponse(responseCode = SC_NOT_FOUND, description = "Not found") })
289 public Response restGet(@PathParam("mediaPackageID") final String mediaPackageID,
290 @PathParam("mediaPackageElementID") final String mediaPackageElementID,
291 @HeaderParam("If-None-Match") String ifNoneMatch) throws NotFoundException {
292
293 String md5 = null;
294 try {
295 md5 = getMediaPackageElementDigest(mediaPackageID, mediaPackageElementID);
296 if (StringUtils.isNotBlank(ifNoneMatch) && md5.equals(ifNoneMatch)) {
297 return Response.notModified(md5).build();
298 }
299 } catch (IOException e) {
300 logger.warn("Error reading digest of {}/{}", mediaPackageElementID, mediaPackageElementID);
301 }
302 try {
303 String contentType;
304 File file = getFile(mediaPackageID, mediaPackageElementID);
305 try {
306 contentType = MimeTypes.fromString(file.getPath()).toString();
307 } catch (UnknownFileTypeException e) {
308 contentType = "application/octet-stream";
309 }
310 try {
311 return ok(get(mediaPackageID, mediaPackageElementID), contentType, Optional.of(file.length()), Optional.empty());
312 } catch (IOException e) {
313 throw new NotFoundException();
314 }
315 } catch (IllegalStateException e) {
316 logger.error("Unable to provide element '{}' from mediapackage '{}'", mediaPackageElementID,
317 mediaPackageID, e);
318 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
319 }
320 }
321
322 @GET
323 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}/{fileName}")
324 @RestQuery(name = "getWithFilename", description = "Gets the file from the working repository under /mediaPackageID/mediaPackageElementID/filename", returnDescription = "The file", pathParameters = {
325 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true, type = STRING),
326 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier", isRequired = true, type = STRING),
327 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING) }, responses = {
328 @RestResponse(responseCode = SC_OK, description = "File returned"),
329 @RestResponse(responseCode = SC_NOT_FOUND, description = "Not found") })
330 public Response restGet(@PathParam("mediaPackageID") String mediaPackageID,
331 @PathParam("mediaPackageElementID") String mediaPackageElementID, @PathParam("fileName") String fileName,
332 @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("Range") String range)
333 throws NotFoundException {
334 String md5 = null;
335
336 try {
337 md5 = getMediaPackageElementDigest(mediaPackageID, mediaPackageElementID);
338 if (StringUtils.isNotBlank(ifNoneMatch) && md5.equals(ifNoneMatch)) {
339 return Response.notModified(md5).build();
340 }
341 } catch (IOException e) {
342 logger.warn("Error reading digest of {}/{}/{}", mediaPackageElementID, mediaPackageElementID,
343 fileName);
344 }
345
346 try {
347 if (StringUtils.isNotBlank(range)) {
348 logger.debug("trying to retrieve range: {}", range);
349 return partialFileResponse(getFile(mediaPackageID, mediaPackageElementID), getMimeType(fileName),
350 Optional.of(fileName), range).tag(md5).build();
351
352 } else {
353
354 return fileResponse(getFile(mediaPackageID, mediaPackageElementID), getMimeType(fileName),
355 Optional.of(fileName)).tag(md5).build();
356 }
357 } catch (Exception e) {
358 logger.error("Unable to provide element '{}' from mediapackage '{}'", mediaPackageElementID,
359 mediaPackageID, e);
360 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
361 }
362 }
363
364 @GET
365 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "{collectionId}/{fileName}")
366 @RestQuery(name = "getFromCollection", description = "Gets the file from the working repository under /collectionId/filename", returnDescription = "The file", pathParameters = {
367 @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true, type = STRING),
368 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING) }, responses = {
369 @RestResponse(responseCode = SC_OK, description = "File returned"),
370 @RestResponse(responseCode = SC_NOT_FOUND, description = "Not found") })
371 public Response restGetFromCollection(@PathParam("collectionId") String collectionId,
372 @PathParam("fileName") String fileName) throws NotFoundException {
373 return fileResponse(getFileFromCollection(collectionId, fileName), getMimeType(fileName), Optional.of(fileName))
374 .build();
375 }
376
377 @GET
378 @Path("/collectionuri/{collectionID}/{fileName}")
379 @RestQuery(name = "getUriFromCollection", description = "Gets the URL for a file to be stored in the working repository under /collectionId/filename", returnDescription = "The url to this file", pathParameters = {
380 @RestParameter(name = "collectionID", description = "the collection identifier", isRequired = true, type = STRING),
381 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING) }, responses = { @RestResponse(responseCode = SC_OK, description = "URL returned") })
382 public Response restGetCollectionUri(@PathParam("collectionID") String collectionId,
383 @PathParam("fileName") String fileName) {
384 URI uri = this.getCollectionURI(collectionId, fileName);
385 return Response.ok(uri.toString()).build();
386 }
387
388 @GET
389 @Path("/uri/{mediaPackageID}/{mediaPackageElementID}")
390 @RestQuery(name = "getUri", description = "Gets the URL for a file to be stored in the working repository under /mediaPackageID", returnDescription = "The url to this file", pathParameters = {
391 @RestParameter(name = "mediaPackageID", description = "the mediaPackage identifier", isRequired = true, type = STRING),
392 @RestParameter(name = "mediaPackageElementID", description = "the mediaPackage element identifier", isRequired = true, type = STRING) }, responses = { @RestResponse(responseCode = SC_OK, description = "URL returned") })
393 public Response restGetUri(@PathParam("mediaPackageID") String mediaPackageID,
394 @PathParam("mediaPackageElementID") String mediaPackageElementID) {
395 URI uri = this.getURI(mediaPackageID, mediaPackageElementID);
396 return Response.ok(uri.toString()).build();
397 }
398
399 @GET
400 @Path("/uri/{mediaPackageID}/{mediaPackageElementID}/{fileName}")
401 @RestQuery(name = "getUriWithFilename", description = "Gets the URL for a file to be stored in the working repository under /mediaPackageID", returnDescription = "The url to this file", pathParameters = {
402 @RestParameter(name = "mediaPackageID", description = "the mediaPackage identifier", isRequired = true, type = STRING),
403 @RestParameter(name = "mediaPackageElementID", description = "the mediaPackage element identifier", isRequired = true, type = STRING),
404 @RestParameter(name = "fileName", description = "the filename", isRequired = true, type = STRING) }, responses = { @RestResponse(responseCode = SC_OK, description = "URL returned") })
405 public Response restGetUri(@PathParam("mediaPackageID") String mediaPackageID,
406 @PathParam("mediaPackageElementID") String mediaPackageElementID, @PathParam("fileName") String fileName) {
407 URI uri = this.getURI(mediaPackageID, mediaPackageElementID, fileName);
408 return Response.ok(uri.toString()).build();
409 }
410
411 @SuppressWarnings("unchecked")
412 @GET
413 @Produces(MediaType.APPLICATION_JSON)
414 @Path("/list/{collectionId}.json")
415 @RestQuery(name = "filesInCollection", description = "Lists files in a collection", returnDescription = "Links to the URLs in a collection", pathParameters = { @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true, type = STRING) }, responses = {
416 @RestResponse(responseCode = SC_OK, description = "URLs returned"),
417 @RestResponse(responseCode = SC_NOT_FOUND, description = "Collection not found") })
418 public Response restGetCollectionContents(@PathParam("collectionId") String collectionId) throws NotFoundException {
419 URI[] uris = super.getCollectionContents(collectionId);
420 JSONArray jsonArray = new JSONArray();
421 for (URI uri : uris) {
422 jsonArray.add(uri.toString());
423 }
424 return Response.ok(jsonArray.toJSONString()).build();
425 }
426
427 @POST
428 @Path("/copy/{fromCollection}/{fromFileName}/{toMediaPackage}/{toMediaPackageElement}/{toFileName}")
429 @RestQuery(name = "copy", description = "Copies a file from a collection to a mediapackage", returnDescription = "A URL to the copied file", pathParameters = {
430 @RestParameter(name = "fromCollection", description = "the collection identifier hosting the source", isRequired = true, type = STRING),
431 @RestParameter(name = "fromFileName", description = "the source file name", isRequired = true, type = STRING),
432 @RestParameter(name = "toMediaPackage", description = "the destination mediapackage identifier", isRequired = true, type = STRING),
433 @RestParameter(name = "toMediaPackageElement", description = "the destination mediapackage element identifier", isRequired = true, type = STRING),
434 @RestParameter(name = "toFileName", description = "the destination file name", isRequired = true, type = STRING) }, responses = {
435 @RestResponse(responseCode = SC_OK, description = "URL returned"),
436 @RestResponse(responseCode = SC_NOT_FOUND, description = "File to copy not found") })
437 public Response restCopyTo(@PathParam("fromCollection") String fromCollection,
438 @PathParam("fromFileName") String fromFileName, @PathParam("toMediaPackage") String toMediaPackage,
439 @PathParam("toMediaPackageElement") String toMediaPackageElement, @PathParam("toFileName") String toFileName)
440 throws NotFoundException {
441 try {
442 URI uri = super.copyTo(fromCollection, fromFileName, toMediaPackage, toMediaPackageElement, toFileName);
443 return Response.ok().entity(uri.toString()).build();
444 } catch (IOException e) {
445 logger.error("Unable to copy file '{}' from collection '{}' to mediapackage {}/{}",
446 fromFileName, fromCollection, toMediaPackage, toMediaPackageElement, e);
447 return Response.serverError().entity(e.getMessage()).build();
448 }
449 }
450
451 @POST
452 @Path("/move/{fromCollection}/{fromFileName}/{toMediaPackage}/{toMediaPackageElement}/{toFileName}")
453 @RestQuery(name = "move", description = "Moves a file from a collection to a mediapackage", returnDescription = "A URL to the moved file", pathParameters = {
454 @RestParameter(name = "fromCollection", description = "the collection identifier hosting the source", isRequired = true, type = STRING),
455 @RestParameter(name = "fromFileName", description = "the source file name", isRequired = true, type = STRING),
456 @RestParameter(name = "toMediaPackage", description = "the destination mediapackage identifier", isRequired = true, type = STRING),
457 @RestParameter(name = "toMediaPackageElement", description = "the destination mediapackage element identifier", isRequired = true, type = STRING),
458 @RestParameter(name = "toFileName", description = "the destination file name", isRequired = true, type = STRING) }, responses = {
459 @RestResponse(responseCode = SC_OK, description = "URL returned"),
460 @RestResponse(responseCode = SC_NOT_FOUND, description = "File to move not found") })
461 public Response restMoveTo(@PathParam("fromCollection") String fromCollection,
462 @PathParam("fromFileName") String fromFileName, @PathParam("toMediaPackage") String toMediaPackage,
463 @PathParam("toMediaPackageElement") String toMediaPackageElement, @PathParam("toFileName") String toFileName)
464 throws NotFoundException {
465 try {
466 URI uri = super.moveTo(fromCollection, fromFileName, toMediaPackage, toMediaPackageElement, toFileName);
467 return Response.ok().entity(uri.toString()).build();
468 } catch (IOException e) {
469 logger.error("Unable to move file '{}' from collection '{}' to mediapackage {}/{}",
470 fromFileName, fromCollection, toMediaPackage, toMediaPackageElement, e);
471 return Response.serverError().entity(e.getMessage()).build();
472 }
473 }
474
475 @SuppressWarnings("unchecked")
476 @GET
477 @Produces(MediaType.APPLICATION_JSON)
478 @Path("storage")
479 @RestQuery(name = "storage", description = "Returns a report on the disk usage and availability", returnDescription = "Plain text containing the report", responses = { @RestResponse(responseCode = SC_OK, description = "Report returned") })
480 public Response restGetTotalStorage() {
481 long total = this.getTotalSpace().get();
482 long usable = this.getUsableSpace().get();
483 long used = this.getUsedSpace().get();
484 String summary = this.getDiskSpace();
485 JSONObject json = new JSONObject();
486 json.put("size", total);
487 json.put("usable", usable);
488 json.put("used", used);
489 json.put("summary", summary);
490 return Response.ok(json.toJSONString()).build();
491 }
492
493 @GET
494 @Produces(MediaType.TEXT_PLAIN)
495 @Path("/baseUri")
496 @RestQuery(name = "baseuri", description = "Returns a base URI for this repository", returnDescription = "Plain text containing the base URI", responses = { @RestResponse(responseCode = SC_OK, description = "Base URI returned") })
497 public Response restGetBaseUri() {
498 return Response.ok(super.getBaseUri().toString()).build();
499 }
500 }