/** * Copyright 2008 The University of North Carolina at Chapel Hill * * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0 * * 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 edu.unc.lib.dl.cdr.sword.server.managers; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.http.HttpStatus; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.log4j.Logger; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import org.jdom2.output.XMLOutputter; import org.swordapp.server.AuthCredentials; import org.swordapp.server.Deposit; import org.swordapp.server.DepositReceipt; import org.swordapp.server.MediaResource; import org.swordapp.server.MediaResourceManager; import org.swordapp.server.SwordAuthException; import org.swordapp.server.SwordConfiguration; import org.swordapp.server.SwordError; import org.swordapp.server.SwordServerException; import edu.unc.lib.dl.acl.util.AccessControlTransformationUtil; import edu.unc.lib.dl.cdr.sword.server.ResponseAwareInputStream; import edu.unc.lib.dl.cdr.sword.server.SwordConfigurationImpl; import edu.unc.lib.dl.fedora.DatastreamPID; import edu.unc.lib.dl.httpclient.HttpClientUtil; import edu.unc.lib.dl.util.ContentModelHelper; import edu.unc.lib.dl.util.ContentModelHelper.Datastream; import edu.unc.lib.dl.util.ErrorURIRegistry; public class MediaResourceManagerImpl extends AbstractFedoraManager implements MediaResourceManager { private static Logger log = Logger.getLogger(MediaResourceManagerImpl.class); private String fedoraHost; private String fedoraPath; private Map<String, Datastream> virtualDatastreamMap; @Override public MediaResource getMediaResourceRepresentation(String uri, Map<String, String> accept, AuthCredentials auth, SwordConfiguration config) throws SwordError, SwordServerException, SwordAuthException { log.debug("Retrieving media resource representation for " + uri); DatastreamPID targetPID = (DatastreamPID) extractPID(uri, SwordConfigurationImpl.EDIT_MEDIA_PATH + "/"); Datastream datastream = Datastream.getDatastream(targetPID.getDatastream()); if (datastream == null) datastream = virtualDatastreamMap.get(targetPID.getDatastream()); if (datastream == null) throw new SwordError(ErrorURIRegistry.RESOURCE_NOT_FOUND, 404, "Media representations other than those of datastreams are not currently supported"); InputStream inputStream = null; String mimeType = null; String lastModified = null; CloseableHttpClient client = HttpClientUtil.getAuthenticatedClient(fedoraHost, accessClient.getUsername(), accessClient.getPassword()); String url = fedoraPath + "/objects/" + targetPID.getPid() + "/datastreams/" + datastream.getName() + "/content"; HttpGet method = new HttpGet(url); try { CloseableHttpResponse httpResp = client.execute(method); int statusCode = httpResp.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_OK) { StringBuilder query = new StringBuilder(); query.append("select $mimeType $lastModified from <%1$s>") .append(" where <%2$s> <%3$s> $mimeType and <%2$s> <%4$s> $lastModified").append(";"); String formatted = String.format(query.toString(), tripleStoreQueryService.getResourceIndexModelUri(), targetPID.getURI() + "/" + datastream.getName(), ContentModelHelper.FedoraProperty.mimeType.getURI().toString(), ContentModelHelper.FedoraProperty.lastModifiedDate.getURI().toString()); List<List<String>> datastreamResults = tripleStoreQueryService.queryResourceIndex(formatted); if (datastreamResults.size() > 0) { mimeType = datastreamResults.get(0).get(0); lastModified = datastreamResults.get(0).get(1); } inputStream = new ResponseAwareInputStream(httpResp); // For the ACL virtual datastream, transform RELS-EXT into accessControl tag if ("ACL".equals(targetPID.getDatastream())) { try { log.debug("Converting response XML to ACL format"); SAXBuilder saxBuilder = new SAXBuilder(); Document relsExt = saxBuilder.build(inputStream); XMLOutputter outputter = new XMLOutputter(); Element accessElement = AccessControlTransformationUtil.rdfToACL(relsExt.getRootElement()); inputStream.close(); inputStream = new ByteArrayInputStream(outputter.outputString(accessElement).getBytes()); } catch (Exception e) { log.debug("Failed to parse response from " + targetPID.getDatastreamURI() + " into ACL format", e); throw new SwordError(ErrorURIRegistry.RETRIEVAL_EXCEPTION, "An exception occurred while attempting to retrieve " + targetPID.getPid()); } } MediaResource resource = new MediaResource(inputStream, mimeType, null, true); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); Date lastModifiedDate; try { lastModifiedDate = formatter.parse(lastModified); resource.setLastModified(lastModifiedDate); } catch (ParseException e) { log.error("Unable to set last modified date for " + uri, e); } return resource; } else if (statusCode >= 500) { throw new SwordError(ErrorURIRegistry.RETRIEVAL_EXCEPTION, statusCode, "Failed to retrieve " + targetPID.getPid() + ": " + httpResp.getStatusLine()); } else if (statusCode == HttpStatus.SC_NOT_FOUND) { throw new SwordError(ErrorURIRegistry.RESOURCE_NOT_FOUND, 404, "Object " + targetPID.getPid() + " could not be found."); } } catch (IOException e) { throw new SwordError(ErrorURIRegistry.RETRIEVAL_EXCEPTION, "An exception occurred while attempting to retrieve " + targetPID.getPid()); } return null; } @Override public DepositReceipt replaceMediaResource(String uri, Deposit deposit, AuthCredentials auth, SwordConfiguration config) throws SwordError, SwordServerException, SwordAuthException { // TODO Auto-generated method stub return null; } @Override public void deleteMediaResource(String uri, AuthCredentials auth, SwordConfiguration config) throws SwordError, SwordServerException, SwordAuthException { // TODO Auto-generated method stub } @Override public DepositReceipt addResource(String uri, Deposit deposit, AuthCredentials auth, SwordConfiguration config) throws SwordError, SwordServerException, SwordAuthException { // TODO Auto-generated method stub return null; } public String getFedoraPath() { return fedoraPath; } public void setFedoraPath(String fedoraPath) { this.fedoraPath = fedoraPath; } public void setVirtualDatastreamMap(Map<String, Datastream> virtualDatastreamMap) { this.virtualDatastreamMap = virtualDatastreamMap; } public String getFedoraHost() { return fedoraHost; } public void setFedoraHost(String fedoraHost) { this.fedoraHost = fedoraHost; } }