/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community 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://opensource.org/licenses/ecl2.txt * * 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.opencastproject.workingfilerepository.remote; import static org.apache.http.HttpStatus.SC_NOT_FOUND; import static org.apache.http.HttpStatus.SC_NO_CONTENT; import static org.apache.http.HttpStatus.SC_OK; import org.opencastproject.serviceregistry.api.RemoteBase; import org.opencastproject.util.NotFoundException; import org.opencastproject.util.UrlSupport; import org.opencastproject.util.data.Option; import org.opencastproject.workingfilerepository.api.WorkingFileRepository; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.ContentBody; import org.apache.http.entity.mime.content.InputStreamBody; import org.apache.http.util.EntityUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.net.URI; /** * A remote service proxy for a working file repository */ public class WorkingFileRepositoryRemoteImpl extends RemoteBase implements WorkingFileRepository { /** the logger */ private static final Logger logger = LoggerFactory.getLogger(WorkingFileRepositoryRemoteImpl.class); public WorkingFileRepositoryRemoteImpl() { super(SERVICE_TYPE); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#copyTo(java.lang.String, java.lang.String, * java.lang.String, java.lang.String, java.lang.String) */ @Override public URI copyTo(String fromCollection, String fromFileName, String toMediaPackage, String toMediaPackageElement, String toFileName) throws IOException, NotFoundException { String urlSuffix = UrlSupport.concat(new String[] { "copy", fromCollection, fromFileName, toMediaPackage, toMediaPackageElement, toFileName }); HttpPost post = new HttpPost(urlSuffix); HttpResponse response = getResponse(post, SC_OK, SC_NOT_FOUND); try { if (response != null) { if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) { throw new NotFoundException("File from collection to copy not found: " + fromCollection + "/" + fromFileName); } else { URI uri = new URI(EntityUtils.toString(response.getEntity(), "UTF-8")); logger.info("Copied collection file {}/{} to {}", new Object[] { fromCollection, fromFileName, uri }); return uri; } } } catch (NotFoundException e) { throw e; } catch (Exception e) { throw new IOException("Unable to copy file", e); } finally { closeConnection(response); } throw new RuntimeException("Unable to copy file from collection"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#moveTo(java.lang.String, java.lang.String, * java.lang.String, java.lang.String, java.lang.String) */ @Override public URI moveTo(String fromCollection, String fromFileName, String toMediaPackage, String toMediaPackageElement, String toFileName) throws IOException, NotFoundException { String urlSuffix = UrlSupport.concat(new String[] { "move", fromCollection, fromFileName, toMediaPackage, toMediaPackageElement, toFileName }); HttpPost post = new HttpPost(urlSuffix); HttpResponse response = getResponse(post, SC_OK, SC_NOT_FOUND); try { if (response != null) { if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) { throw new NotFoundException("File from collection to move not found: " + fromCollection + "/" + fromFileName); } else { URI uri = new URI(EntityUtils.toString(response.getEntity(), "UTF-8")); logger.info("Moved collection file {}/{} to {}", new Object[] { fromCollection, fromFileName, uri }); return uri; } } } catch (NotFoundException e) { throw e; } catch (Exception e) { throw new IOException("Unable to move file", e); } finally { closeConnection(response); } throw new RuntimeException("Unable to move file from collection"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#delete(java.lang.String, java.lang.String) */ @Override public boolean delete(String mediaPackageID, String mediaPackageElementID) { String urlSuffix = UrlSupport .concat(new String[] { MEDIAPACKAGE_PATH_PREFIX, mediaPackageID, mediaPackageElementID }); HttpDelete del = new HttpDelete(urlSuffix); HttpResponse response = getResponse(del, SC_OK, SC_NOT_FOUND); try { if (response != null) { return HttpStatus.SC_OK == response.getStatusLine().getStatusCode(); } } finally { closeConnection(response); } throw new RuntimeException("Error removing file"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#get(java.lang.String, java.lang.String) */ @Override public InputStream get(String mediaPackageID, String mediaPackageElementID) throws NotFoundException { String urlSuffix = UrlSupport .concat(new String[] { MEDIAPACKAGE_PATH_PREFIX, mediaPackageID, mediaPackageElementID }); HttpGet get = new HttpGet(urlSuffix); HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND); try { if (response != null) { if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) { throw new NotFoundException(); } else { // Do not close this response. It will be closed when the caller closes the input stream return new HttpClientClosingInputStream(response); } } } catch (Exception e) { throw new RuntimeException(); } throw new RuntimeException("Error getting file"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getCollectionContents(java.lang.String) */ @Override public URI[] getCollectionContents(String collectionId) throws NotFoundException { String urlSuffix = UrlSupport.concat(new String[] { "list", collectionId + ".json" }); HttpGet get = new HttpGet(urlSuffix); HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND); try { if (response != null) { if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) { throw new NotFoundException(); } else { String json = EntityUtils.toString(response.getEntity()); JSONArray jsonArray = (JSONArray) JSONValue.parse(json); URI[] uris = new URI[jsonArray.size()]; for (int i = 0; i < jsonArray.size(); i++) { uris[i] = new URI((String) jsonArray.get(i)); } return uris; } } } catch (NotFoundException e) { throw e; } catch (Exception e) { throw new RuntimeException(); } finally { closeConnection(response); } throw new RuntimeException("Error getting collection contents"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getCollectionSize(java.lang.String) */ @Override public long getCollectionSize(String id) throws NotFoundException { return getCollectionContents(id).length; } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getDiskSpace() */ @Override public String getDiskSpace() { return (String) getStorageReport().get("summary"); } protected JSONObject getStorageReport() { String url = UrlSupport.concat(new String[] { "storage" }); HttpGet get = new HttpGet(url); HttpResponse response = getResponse(get); try { if (response != null) { String json = EntityUtils.toString(response.getEntity()); return (JSONObject) JSONValue.parse(json); } } catch (Exception e) { throw new RuntimeException(e); } finally { closeConnection(response); } throw new RuntimeException("Error getting storage report"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getFromCollection(java.lang.String, * java.lang.String) */ @Override public InputStream getFromCollection(String collectionId, String fileName) throws NotFoundException { String url = UrlSupport.concat(new String[] { COLLECTION_PATH_PREFIX, collectionId, fileName }); HttpGet get = new HttpGet(url); HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND); try { if (response != null) { if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) throw new NotFoundException(); // Do not close this response. It will be closed when the caller closes the input stream return new HttpClientClosingInputStream(response); } } catch (NotFoundException e) { throw e; } catch (Exception e) { throw new RuntimeException(); } throw new RuntimeException("Error get from collection"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getTotalSpace() */ @Override public Option<Long> getTotalSpace() { return Option.some((Long) (getStorageReport().get("size"))); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getCollectionURI(java.lang.String, * java.lang.String) */ @Override public URI getCollectionURI(String collectionID, String fileName) { String url = UrlSupport.concat(new String[] { "collectionuri", collectionID, fileName }); HttpGet get = new HttpGet(url); HttpResponse response = getResponse(get); try { if (response != null) { return new URI(EntityUtils.toString(response.getEntity())); } } catch (Exception e) { throw new RuntimeException(e); } finally { closeConnection(response); } throw new RuntimeException("Unable to get collection URI"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getURI(java.lang.String, java.lang.String) */ @Override public URI getURI(String mediaPackageID, String mediaPackageElementID) { return getURI(mediaPackageID, mediaPackageElementID, null); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getURI(java.lang.String, java.lang.String, * java.lang.String) */ @Override public URI getURI(String mediaPackageID, String mediaPackageElementID, String fileName) { String url = UrlSupport.concat(new String[] { "uri", mediaPackageID, mediaPackageElementID }); if (fileName != null) url = UrlSupport.concat(url, fileName); HttpGet get = new HttpGet(url); HttpResponse response = getResponse(get); try { if (response != null) { return new URI(EntityUtils.toString(response.getEntity())); } } catch (Exception e) { throw new RuntimeException(e); } finally { closeConnection(response); } throw new RuntimeException("Unable to get URI"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getUsableSpace() */ @Override public Option<Long> getUsableSpace() { return Option.some((Long) (getStorageReport().get("usable"))); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getUsedSpace() */ @Override public Option<Long> getUsedSpace() { return Option.some((Long) (getStorageReport().get("used"))); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#put(java.lang.String, java.lang.String, * java.lang.String, java.io.InputStream) */ @Override public URI put(String mediaPackageID, String mediaPackageElementID, String filename, InputStream in) { String url = UrlSupport.concat(new String[] { MEDIAPACKAGE_PATH_PREFIX, mediaPackageID, mediaPackageElementID }); HttpPost post = new HttpPost(url); MultipartEntity entity = new MultipartEntity(); ContentBody body = new InputStreamBody(in, filename); entity.addPart("file", body); post.setEntity(entity); HttpResponse response = getResponse(post); try { if (response != null) { String content = EntityUtils.toString(response.getEntity()); return new URI(content); } } catch (Exception e) { throw new RuntimeException(e); } finally { closeConnection(response); } throw new RuntimeException("Unable to put file"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#putInCollection(java.lang.String, * java.lang.String, java.io.InputStream) */ @Override public URI putInCollection(String collectionId, String fileName, InputStream in) { String url = UrlSupport.concat(new String[] { COLLECTION_PATH_PREFIX, collectionId }); HttpPost post = new HttpPost(url); MultipartEntity entity = new MultipartEntity(); ContentBody body = new InputStreamBody(in, fileName); entity.addPart("file", body); post.setEntity(entity); HttpResponse response = getResponse(post); try { if (response != null) { String content = EntityUtils.toString(response.getEntity()); return new URI(content); } } catch (Exception e) { throw new RuntimeException(e); } finally { closeConnection(response); } throw new RuntimeException("Unable to put file in collection"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#deleteFromCollection(java.lang.String, * java.lang.String) */ @Override public boolean deleteFromCollection(String collectionId, String fileName) { String url = UrlSupport.concat(new String[] { COLLECTION_PATH_PREFIX, collectionId, fileName }); HttpDelete del = new HttpDelete(url); HttpResponse response = getResponse(del, SC_NO_CONTENT, SC_NOT_FOUND); try { if (response != null) return SC_NO_CONTENT == response.getStatusLine().getStatusCode(); } finally { closeConnection(response); } throw new RuntimeException("Error removing file from collection"); } /** * {@inheritDoc} * * @see org.opencastproject.workingfilerepository.api.WorkingFileRepository#getBaseUri() */ @Override public URI getBaseUri() { HttpGet get = new HttpGet("/baseUri"); HttpResponse response = getResponse(get); try { if (response != null) return new URI(EntityUtils.toString(response.getEntity(), "UTF-8")); } catch (Exception e) { throw new IllegalStateException("Unable to determine the base URI of the file repository"); } finally { closeConnection(response); } throw new IllegalStateException("Unable to determine the base URI of the file repository"); } }