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