/**
* 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.series.remote;
import static java.lang.String.format;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.http.HttpStatus.SC_CREATED;
import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
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_UNAUTHORIZED;
import org.opencastproject.metadata.dublincore.DublinCore;
import org.opencastproject.metadata.dublincore.DublinCoreCatalog;
import org.opencastproject.metadata.dublincore.DublinCoreCatalogList;
import org.opencastproject.metadata.dublincore.DublinCores;
import org.opencastproject.rest.BulkOperationResult;
import org.opencastproject.security.api.AccessControlList;
import org.opencastproject.security.api.AccessControlParser;
import org.opencastproject.security.api.UnauthorizedException;
import org.opencastproject.series.api.SeriesException;
import org.opencastproject.series.api.SeriesQuery;
import org.opencastproject.series.api.SeriesService;
import org.opencastproject.serviceregistry.api.RemoteBase;
import org.opencastproject.util.NotFoundException;
import org.opencastproject.util.SolrUtils;
import org.opencastproject.util.doc.rest.RestService;
import com.entwinemedia.fn.data.Opt;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
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.client.methods.HttpPut;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.json.simple.parser.JSONParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* A proxy to a remote series service.
*/
@Path("/")
@RestService(name = "seriesservice", title = "Series Service Remote", abstractText = "This service creates, edits and retrieves and helps managing series.", notes = {
"All paths above are relative to the REST endpoint base (something like http://your.server/files)",
"If the service is down or not working it will return a status 503, this means the the underlying service is "
+ "not working and is either restarting or has failed",
"A status code 500 means a general failure has occurred which is not recoverable and was not anticipated. In "
+ "other words, there is a bug! You should file an error report with your server logs from the time when the "
+ "error occurred: <a href=\"https://opencast.jira.com\">Opencast Issue Tracker</a>" })
public class SeriesServiceRemoteImpl extends RemoteBase implements SeriesService {
private static final Logger logger = LoggerFactory.getLogger(SeriesServiceRemoteImpl.class);
/** A parser for handling JSON documents inside the body of a request. **/
private JSONParser parser = new JSONParser();
public SeriesServiceRemoteImpl() {
super(JOB_TYPE);
}
@Override
public DublinCoreCatalog updateSeries(DublinCoreCatalog dc) throws SeriesException, UnauthorizedException {
String seriesId = dc.getFirst(DublinCore.PROPERTY_IDENTIFIER);
HttpPost post = new HttpPost("/");
try {
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("series", dc.toXmlString()));
post.setEntity(new UrlEncodedFormEntity(params));
} catch (Exception e) {
throw new SeriesException("Unable to assemble a remote series request for updating series " + seriesId, e);
}
HttpResponse response = getResponse(post, SC_NO_CONTENT, SC_CREATED, SC_UNAUTHORIZED);
try {
if (response != null) {
int statusCode = response.getStatusLine().getStatusCode();
if (SC_NO_CONTENT == statusCode) {
logger.info("Successfully updated series {} in the series service", seriesId);
return null;
} else if (SC_UNAUTHORIZED == statusCode) {
throw new UnauthorizedException("Not authorized to update series " + seriesId);
} else if (SC_CREATED == statusCode) {
DublinCoreCatalog catalogImpl = DublinCores.read(response.getEntity().getContent());
logger.info("Successfully created series {} in the series service", seriesId);
return catalogImpl;
}
}
} catch (UnauthorizedException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to update series " + seriesId + " using the remote series services: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to update series " + seriesId + " using the remote series services");
}
@Override
public boolean updateAccessControl(String seriesID, AccessControlList accessControl) throws NotFoundException,
SeriesException, UnauthorizedException {
HttpPost post = new HttpPost(seriesID + "/accesscontrol");
try {
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("seriesID", seriesID));
params.add(new BasicNameValuePair("acl", AccessControlParser.toXml(accessControl)));
post.setEntity(new UrlEncodedFormEntity(params));
} catch (Exception e) {
throw new SeriesException("Unable to assemble a remote series request for updating an ACL " + accessControl, e);
}
HttpResponse response = getResponse(post, SC_NO_CONTENT, SC_CREATED, SC_NOT_FOUND, SC_UNAUTHORIZED);
try {
if (response != null) {
int status = response.getStatusLine().getStatusCode();
if (SC_NOT_FOUND == status) {
throw new NotFoundException("Series not found: " + seriesID);
} else if (SC_NO_CONTENT == status) {
logger.info("Successfully updated ACL of {} to the series service", seriesID);
return true;
} else if (SC_UNAUTHORIZED == status) {
throw new UnauthorizedException("Not authorized to update series ACL of " + seriesID);
} else if (SC_CREATED == status) {
logger.info("Successfully created ACL of {} to the series service", seriesID);
return false;
}
}
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to update series ACL " + accessControl + " using the remote series services");
}
@Override
public void deleteSeries(String seriesID) throws SeriesException, NotFoundException, UnauthorizedException {
HttpDelete del = new HttpDelete(seriesID);
HttpResponse response = getResponse(del, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
try {
if (response != null) {
int statusCode = response.getStatusLine().getStatusCode();
if (SC_NOT_FOUND == statusCode) {
throw new NotFoundException("Series not found: " + seriesID);
} else if (SC_UNAUTHORIZED == statusCode) {
throw new UnauthorizedException("Not authorized to delete series " + seriesID);
} else if (SC_OK == statusCode) {
logger.info("Successfully deleted {} from the remote series index", seriesID);
return;
}
}
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to remove " + seriesID + " from a remote series index");
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{seriesID:.+}.json")
public Response getSeriesJSON(@PathParam("seriesID") String seriesID) throws UnauthorizedException {
logger.debug("Series Lookup: {}", seriesID);
try {
DublinCoreCatalog dc = getSeries(seriesID);
return Response.ok(dc.toJson()).build();
} catch (NotFoundException e) {
return Response.status(NOT_FOUND).build();
} catch (UnauthorizedException e) {
throw e;
} catch (Exception e) {
logger.error("Could not retrieve series: {}", e.getMessage());
throw new WebApplicationException(INTERNAL_SERVER_ERROR);
}
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{seriesID:.+}/acl.json")
public Response getSeriesAccessControlListJson(@PathParam("seriesID") String seriesID) {
logger.debug("Series ACL lookup: {}", seriesID);
try {
AccessControlList acl = getSeriesAccessControl(seriesID);
return Response.ok(acl).build();
} catch (NotFoundException e) {
return Response.status(NOT_FOUND).build();
} catch (SeriesException e) {
logger.error("Could not retrieve series ACL: {}", e.getMessage());
throw new WebApplicationException(INTERNAL_SERVER_ERROR);
}
}
@Override
public DublinCoreCatalog getSeries(String seriesID) throws SeriesException, NotFoundException, UnauthorizedException {
HttpGet get = new HttpGet(seriesID + ".xml");
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
try {
if (response != null) {
if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
throw new NotFoundException("Series " + seriesID + " not found in remote series index!");
} else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
throw new UnauthorizedException("Not authorized to get series " + seriesID);
} else {
DublinCoreCatalog dublinCoreCatalog = DublinCores.read(response.getEntity().getContent());
logger.debug("Successfully received series {} from the remote series index", seriesID);
return dublinCoreCatalog;
}
}
} catch (UnauthorizedException e) {
throw e;
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to parse series from remote series index: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to get series from remote series index");
}
@Override
public AccessControlList getSeriesAccessControl(String seriesID) throws NotFoundException, SeriesException {
HttpGet get = new HttpGet(seriesID + "/acl.xml");
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND);
try {
if (response != null) {
if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
throw new NotFoundException("Series ACL " + seriesID + " not found on remote series index!");
} else {
AccessControlList acl = AccessControlParser.parseAcl(response.getEntity().getContent());
logger.info("Successfully get series ACL {} from the remote series index", seriesID);
return acl;
}
}
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to parse series ACL form remote series index: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to get series ACL from remote series index");
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("series.json")
public Response getSeriesAsJson(@QueryParam("startPage") int startPage, @QueryParam("count") int count)
throws UnauthorizedException {
try {
DublinCoreCatalogList result = getSeries(new SeriesQuery().setStartPage(startPage).setCount(count));
return Response.ok(result.getResultsAsJson()).build();
} catch (UnauthorizedException e) {
throw e;
} catch (Exception e) {
logger.warn("Could not perform search query: {}", e.getMessage());
}
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
@Override
public DublinCoreCatalogList getSeries(SeriesQuery query) throws SeriesException, UnauthorizedException {
HttpGet get = new HttpGet(getSeriesUrl(query));
HttpResponse response = getResponse(get, SC_OK, SC_UNAUTHORIZED);
try {
if (response != null) {
int statusCode = response.getStatusLine().getStatusCode();
if (SC_OK == statusCode) {
DublinCoreCatalogList list = DublinCoreCatalogList.parse(EntityUtils.toString(response.getEntity(), "UTF-8"));
logger.info("Successfully get series dublin core catalog list from the remote series index");
return list;
} else if (SC_UNAUTHORIZED == statusCode) {
throw new UnauthorizedException("Not authorized to get series from query");
}
}
} catch (UnauthorizedException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to get series from query from remote series index: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to get series from query from remote series index: " + getSeriesUrl(query));
}
@Override
public int getSeriesCount() throws SeriesException {
HttpGet get = new HttpGet("/count");
HttpResponse response = getResponse(get);
try {
if (response != null) {
int count = Integer.parseInt(IOUtils.toString(response.getEntity().getContent()));
logger.info("Successfully get series dublin core catalog list from the remote series index");
return count;
}
} catch (Exception e) {
throw new SeriesException("Unable to count series from remote series index: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to count series from remote series index");
}
@Override
public boolean isOptOut(String seriesId) throws NotFoundException, SeriesException {
HttpGet get = new HttpGet(seriesId + "/optOut");
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND);
try {
if (response != null) {
if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
throw new NotFoundException("Series with id '" + seriesId + "' not found on remote series service!");
} else {
String optOutString = EntityUtils.toString(response.getEntity(), "UTF-8");
Boolean booleanObject = BooleanUtils.toBooleanObject(optOutString);
if (booleanObject == null)
throw new SeriesException("Could not parse opt out status from the remote series service: " + optOutString);
logger.info("Successfully get opt out status of series with id {} from the remote series service", seriesId);
return booleanObject.booleanValue();
}
}
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to get the series opt out status from remote series service: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to get series opt out status from remote series service");
}
@Override
public void updateOptOutStatus(String seriesId, boolean optOut) throws NotFoundException, SeriesException {
HttpPost post = new HttpPost("/optOutSeries/" + optOut);
HttpResponse response = null;
try {
JSONArray seriesIds = new JSONArray();
seriesIds.put(seriesId);
post.setEntity(new StringEntity(seriesIds.toString()));
response = getResponse(post, SC_OK);
BulkOperationResult bulkOperationResult = new BulkOperationResult();
bulkOperationResult.fromJson(response.getEntity().getContent());
if (bulkOperationResult.getNotFound().size() > 0) {
throw new NotFoundException("Unable to find series with id " + seriesId);
} else if (bulkOperationResult.getServerError().size() > 0) {
throw new SeriesException("Unable to update series " + seriesId
+ " opt out status using the remote series services.");
}
} catch (Exception e) {
throw new SeriesException("Unable to assemble a remote series request for updating series " + seriesId
+ " with optOut status of " + optOut + " because:" + ExceptionUtils.getStackTrace(e));
} finally {
if (response != null) {
closeConnection(response);
}
}
throw new SeriesException("Unable to update series " + seriesId + " using the remote series services");
}
/**
* Builds the a series URL.
*
* @param q
* the series query
* @return the series URL
*/
private String getSeriesUrl(SeriesQuery q) {
StringBuilder url = new StringBuilder();
url.append("/series.xml?");
List<NameValuePair> queryStringParams = new ArrayList<NameValuePair>();
if (q.getText() != null)
queryStringParams.add(new BasicNameValuePair("q", q.getText()));
if (q.getSeriesId() != null)
queryStringParams.add(new BasicNameValuePair("seriesId", q.getSeriesId()));
queryStringParams.add(new BasicNameValuePair("edit", Boolean.toString(q.isEdit())));
if (q.getSeriesTitle() != null)
queryStringParams.add(new BasicNameValuePair("seriesTitle", q.getSeriesTitle()));
if (q.getCreator() != null)
queryStringParams.add(new BasicNameValuePair("creator", q.getCreator()));
if (q.getContributor() != null)
queryStringParams.add(new BasicNameValuePair("contributor", q.getContributor()));
if (q.getPublisher() != null)
queryStringParams.add(new BasicNameValuePair("publisher", q.getPublisher()));
if (q.getRightsHolder() != null)
queryStringParams.add(new BasicNameValuePair("rightsholder", q.getRightsHolder()));
if (q.getCreatedFrom() != null)
queryStringParams.add(new BasicNameValuePair("createdfrom", SolrUtils.serializeDate(q.getCreatedFrom())));
if (q.getCreatedTo() != null)
queryStringParams.add(new BasicNameValuePair("createdto", SolrUtils.serializeDate(q.getCreatedTo())));
if (q.getLanguage() != null)
queryStringParams.add(new BasicNameValuePair("language", q.getLanguage()));
if (q.getLicense() != null)
queryStringParams.add(new BasicNameValuePair("license", q.getLicense()));
if (q.getSubject() != null)
queryStringParams.add(new BasicNameValuePair("subject", q.getSubject()));
if (q.getAbstract() != null)
queryStringParams.add(new BasicNameValuePair("abstract", q.getAbstract()));
if (q.getDescription() != null)
queryStringParams.add(new BasicNameValuePair("description", q.getDescription()));
if (q.getSort() != null) {
String sortString = q.getSort().toString();
if (!q.isSortAscending())
sortString = sortString.concat("_DESC");
queryStringParams.add(new BasicNameValuePair("sort", sortString));
}
queryStringParams.add(new BasicNameValuePair("startPage", Long.toString(q.getStartPage())));
queryStringParams.add(new BasicNameValuePair("count", Long.toString(q.getCount())));
url.append(URLEncodedUtils.format(queryStringParams, "UTF-8"));
return url.toString();
}
@Override
public Map<String, String> getSeriesProperties(String seriesID) throws SeriesException, NotFoundException,
UnauthorizedException {
HttpGet get = new HttpGet(seriesID + "/properties.json");
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
try {
if (response != null) {
if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
throw new NotFoundException("Series " + seriesID + " not found in remote series index!");
} else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
throw new UnauthorizedException("Not authorized to get series " + seriesID);
} else {
logger.debug("Successfully received series {} properties from the remote series index", seriesID);
StringWriter writer = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
JSONArray jsonProperties = (JSONArray) parser.parse(writer.toString());
Map<String, String> properties = new TreeMap<String, String>();
for (int i = 0; i < jsonProperties.length(); i++) {
JSONObject property = (JSONObject) jsonProperties.get(i);
JSONArray names = property.names();
for (int j = 0; j < names.length(); j++) {
properties.put(names.get(j).toString(), property.get(names.get(j).toString()).toString());
}
}
return properties;
}
}
} catch (UnauthorizedException e) {
throw e;
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to parse series properties from remote series index: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to get series from remote series index");
}
@Override
public String getSeriesProperty(String seriesID, String propertyName) throws SeriesException, NotFoundException,
UnauthorizedException {
HttpGet get = new HttpGet(seriesID + "/property/" + propertyName + ".json");
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
try {
if (response != null) {
if (SC_NOT_FOUND == response.getStatusLine().getStatusCode()) {
throw new NotFoundException("Series " + seriesID + " not found in remote series index!");
} else if (SC_UNAUTHORIZED == response.getStatusLine().getStatusCode()) {
throw new UnauthorizedException("Not authorized to get series " + seriesID);
} else {
logger.debug("Successfully received series {} property {} from the remote series index", seriesID,
propertyName);
StringWriter writer = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8");
return writer.toString();
}
}
} catch (UnauthorizedException e) {
throw e;
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to parse series from remote series index: " + e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to get series from remote series index");
}
@Override
public void updateSeriesProperty(String seriesID, String propertyName, String propertyValue) throws SeriesException,
NotFoundException, UnauthorizedException {
HttpPost post = new HttpPost("/" + seriesID + "/property");
try {
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("name", propertyName));
params.add(new BasicNameValuePair("value", propertyValue));
post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
} catch (Exception e) {
throw new SeriesException("Unable to assemble a remote series request for updating series " + seriesID
+ " series property " + propertyName + ":" + propertyValue, e);
}
HttpResponse response = getResponse(post, SC_NO_CONTENT, SC_CREATED, SC_UNAUTHORIZED);
try {
if (response != null) {
int statusCode = response.getStatusLine().getStatusCode();
if (SC_NO_CONTENT == statusCode) {
logger.info("Successfully updated series {} with property name {} and value {} in the series service",
new Object[] { seriesID, propertyName, propertyValue });
return;
} else if (SC_UNAUTHORIZED == statusCode) {
throw new UnauthorizedException("Not authorized to update series " + seriesID);
}
}
} catch (UnauthorizedException e) {
throw e;
} catch (Exception e) {
throw new SeriesException("Unable to update series " + seriesID + " with property " + propertyName + ":"
+ propertyValue + " using the remote series services: ", e);
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to update series " + seriesID + " using the remote series services");
}
@Override
public void deleteSeriesProperty(String seriesID, String propertyName) throws SeriesException, NotFoundException,
UnauthorizedException {
HttpDelete del = new HttpDelete("/" + seriesID + "/property/" + propertyName);
HttpResponse response = getResponse(del, SC_OK, SC_NOT_FOUND, SC_UNAUTHORIZED);
try {
if (response != null) {
int statusCode = response.getStatusLine().getStatusCode();
if (SC_NOT_FOUND == statusCode) {
throw new NotFoundException("Series not found: " + seriesID);
} else if (SC_UNAUTHORIZED == statusCode) {
throw new UnauthorizedException("Not authorized to delete series " + seriesID);
} else if (SC_OK == statusCode) {
logger.info("Successfully deleted {} from the remote series index", seriesID);
return;
}
}
} finally {
closeConnection(response);
}
throw new SeriesException("Unable to remove " + seriesID + " from a remote series index");
}
@Override
public Opt<Map<String, byte[]>> getSeriesElements(String seriesID) throws SeriesException {
HttpGet get = new HttpGet("/" + seriesID + "/elements.json");
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_INTERNAL_SERVER_ERROR);
try {
if (response == null) {
throw new SeriesException(format("Error while retrieving elements from series '%s'", seriesID));
} else {
final int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case SC_OK:
JSONArray elementArray = (JSONArray) parser.parse(IOUtils.toString(response.getEntity().getContent()));
Map<String, byte[]> elements = new HashMap<String, byte[]>();
for (int i = 0; i < elementArray.length(); i++) {
final String type = elementArray.getString(i);
Opt<byte[]> optData = getSeriesElementData(seriesID, type);
if (optData.isSome()) {
elements.put(type, optData.get());
} else {
throw new SeriesException(format("Tried to load non-existing element of type '%s'", type));
}
}
return Opt.some(elements);
case SC_NOT_FOUND:
return Opt.none();
case SC_INTERNAL_SERVER_ERROR:
throw new SeriesException(format("Error while retrieving elements from series '%s'", seriesID));
default:
throw new SeriesException(format("Unexpected status code", statusCode));
}
}
} catch (Exception e) {
logger.warn("Error while retrieving elements from remote service: %s", ExceptionUtils.getStackTrace(e));
throw new SeriesException(e);
} finally {
closeConnection(response);
}
}
@Override
public Opt<byte[]> getSeriesElementData(String seriesID, String type) throws SeriesException {
HttpGet get = new HttpGet("/" + seriesID + "/elements/" + type);
HttpResponse response = getResponse(get, SC_OK, SC_NOT_FOUND, SC_INTERNAL_SERVER_ERROR);
try {
if (response == null) {
throw new SeriesException(
format("Error while retrieving element of type '%s' from series '%s'", type, seriesID));
} else {
final int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case SC_OK:
return Opt.some(IOUtils.toByteArray(response.getEntity().getContent()));
case SC_NOT_FOUND:
return Opt.none();
case SC_INTERNAL_SERVER_ERROR:
throw new SeriesException(format("Error while retrieving element of type '%s' from series '%s'", type,
seriesID));
default:
throw new SeriesException(format("Unexpected status code", statusCode));
}
}
} catch (Exception e) {
logger.warn("Error while retrieving element from remote service: %s", ExceptionUtils.getStackTrace(e));
throw new SeriesException(e);
} finally {
closeConnection(response);
}
}
@Override
public boolean addSeriesElement(String seriesID, String type, byte[] data) throws SeriesException {
HttpPut put = new HttpPut("/" + seriesID + "/elements/" + type);
put.setEntity(new ByteArrayEntity(data, ContentType.DEFAULT_BINARY));
HttpResponse response = getResponse(put, SC_CREATED, SC_INTERNAL_SERVER_ERROR);
try {
if (response == null) {
throw new SeriesException(format("Error while adding element of type '%s' in series '%s'", type, seriesID));
} else {
final int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case SC_CREATED:
return true;
case SC_INTERNAL_SERVER_ERROR:
throw new SeriesException(
format("Error while updating element of type '%s' in series '%s'", type, seriesID));
default:
throw new SeriesException(format("Unexpected status code", statusCode));
}
}
} finally {
closeConnection(response);
}
}
@Override
public boolean updateSeriesElement(String seriesID, String type, byte[] data) throws SeriesException {
HttpPut put = new HttpPut("/" + seriesID + "/elements/" + type);
put.setEntity(new ByteArrayEntity(data, ContentType.DEFAULT_BINARY));
HttpResponse response = getResponse(put, SC_NO_CONTENT, SC_INTERNAL_SERVER_ERROR);
try {
if (response == null) {
throw new SeriesException(format("Error while updating element of type '%s' in series '%s'", type, seriesID));
} else {
final int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case SC_NO_CONTENT:
return true;
case SC_INTERNAL_SERVER_ERROR:
throw new SeriesException(
format("Error while updating element of type '%s' in series '%s'", type, seriesID));
default:
throw new SeriesException(format("Unexpected status code", statusCode));
}
}
} finally {
closeConnection(response);
}
}
@Override
public boolean deleteSeriesElement(String seriesID, String type) throws SeriesException {
if (isBlank(seriesID))
throw new IllegalArgumentException("Series ID must not be blank");
if (isBlank(type))
throw new IllegalArgumentException("Element type must not be blank");
HttpDelete del = new HttpDelete("/" + seriesID + "/elements/" + type);
HttpResponse response = getResponse(del, SC_NO_CONTENT, SC_NOT_FOUND, SC_INTERNAL_SERVER_ERROR);
try {
if (response == null) {
throw new SeriesException("Unable to remove " + seriesID + " from a remote series index");
} else {
final int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case SC_NO_CONTENT:
return true;
case SC_NOT_FOUND:
return false;
case SC_INTERNAL_SERVER_ERROR:
throw new SeriesException(format("Error while deleting element of type '%s' from series '%s'", type,
seriesID));
default:
throw new SeriesException(format("Unexpected status code", statusCode));
}
}
} finally {
closeConnection(response);
}
}
}