001/** 002 * Copyright 2015 DuraSpace, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.fcrepo.client.impl; 017 018import static org.apache.http.HttpStatus.SC_CONFLICT; 019import static org.apache.http.HttpStatus.SC_CREATED; 020import static org.apache.http.HttpStatus.SC_FORBIDDEN; 021import static org.apache.http.HttpStatus.SC_NO_CONTENT; 022import static org.apache.http.HttpStatus.SC_NOT_FOUND; 023import static org.apache.http.HttpStatus.SC_OK; 024 025import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty; 026 027import static org.fcrepo.kernel.api.RdfLexicon.DESCRIBES; 028import static org.fcrepo.kernel.api.RdfLexicon.HAS_ORIGINAL_NAME; 029import static org.fcrepo.kernel.api.RdfLexicon.HAS_MIME_TYPE; 030import static org.fcrepo.kernel.api.RdfLexicon.HAS_SIZE; 031import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE; 032 033import static org.slf4j.LoggerFactory.getLogger; 034 035import java.io.InputStream; 036import java.net.URI; 037import java.net.URISyntaxException; 038 039import org.fcrepo.client.ForbiddenException; 040import org.fcrepo.client.NotFoundException; 041 042import com.hp.hpl.jena.graph.Node; 043import com.hp.hpl.jena.graph.NodeFactory; 044import com.hp.hpl.jena.graph.Graph; 045import com.hp.hpl.jena.graph.Triple; 046import com.hp.hpl.jena.rdf.model.Property; 047 048import org.apache.http.HttpResponse; 049import org.apache.http.StatusLine; 050import org.apache.http.client.methods.HttpGet; 051import org.apache.http.client.methods.HttpPut; 052 053import org.apache.jena.atlas.lib.NotImplemented; 054 055import org.fcrepo.client.FedoraContent; 056import org.fcrepo.client.FedoraDatastream; 057import org.fcrepo.client.FedoraException; 058import org.fcrepo.client.FedoraObject; 059import org.fcrepo.client.FedoraRepository; 060import org.fcrepo.client.utils.HttpHelper; 061 062import org.fcrepo.kernel.api.FedoraJcrTypes; 063import org.slf4j.Logger; 064 065/** 066 * A Fedora Datastream Impl. 067 * 068 * @author escowles 069 * @since 2014-08-25 070 */ 071public class FedoraDatastreamImpl extends FedoraResourceImpl implements FedoraDatastream { 072 private static final Logger LOGGER = getLogger(FedoraDatastreamImpl.class); 073 protected static final Property REST_API_DIGEST = createProperty(REPOSITORY_NAMESPACE + "digest"); 074 private boolean hasContent; 075 private Node contentSubject; 076 077 /** 078 * Constructor for FedoraDatastreamImpl 079 * 080 * @param repository Repository that created this object. 081 * @param httpHelper HTTP helper for making repository requests 082 * @param path Path of the datastream in the repository 083 */ 084 public FedoraDatastreamImpl(final FedoraRepository repository, final HttpHelper httpHelper, final String path) { 085 super(repository, httpHelper, path); 086 contentSubject = NodeFactory.createURI( 087 repository.getRepositoryUrl() + path.substring(0, path.lastIndexOf("/")) ); 088 } 089 090 @Override 091 public void setGraph( final Graph graph ) { 092 super.setGraph( graph ); 093 hasContent = getTriple( subject, DESCRIBES ) != null; 094 } 095 096 @Override 097 public String getPropertiesPath() { 098 return path + "/" + FedoraJcrTypes.FCR_METADATA; 099 } 100 101 @Override 102 public boolean hasContent() throws FedoraException { 103 return hasContent; 104 } 105 106 @Override 107 public FedoraObject getObject() throws FedoraException { 108 final String contentPath = path.substring(0, path.lastIndexOf("/")); 109 return repository.getObject( contentPath.substring(0, contentPath.lastIndexOf("/")) ); 110 } 111 112 @Override 113 public String getName() { 114 final String p = path.endsWith("/") ? path.substring(0, path.length() - 1) : path; 115 final String[] paths = p.split("/"); 116 return paths[paths.length - 2]; 117 } 118 119 @Override 120 public URI getContentDigest() throws FedoraException { 121 final Node contentDigest = getObjectValue( REST_API_DIGEST ); 122 try { 123 if ( contentDigest == null ) { 124 return null; 125 } 126 127 return new URI( contentDigest.getURI() ); 128 } catch ( final URISyntaxException e ) { 129 throw new FedoraException("Error parsing checksum URI: " + contentDigest.getURI(), e); 130 } 131 } 132 133 @Override 134 public Long getContentSize() throws FedoraException { 135 final Node size = getObjectValue( HAS_SIZE ); 136 if ( size == null ) { 137 return null; 138 } 139 140 return new Long( size.getLiteralValue().toString() ); 141 } 142 143 @Override 144 public String getFilename() throws FedoraException { 145 final Node filename = getObjectValue( HAS_ORIGINAL_NAME ); 146 if ( filename == null ) { 147 return null; 148 } 149 150 return filename.getLiteralValue().toString(); 151 } 152 153 @Override 154 public String getContentType() throws FedoraException { 155 final Node contentType = getObjectValue( HAS_MIME_TYPE ); 156 if ( contentType == null ) { 157 return null; 158 } 159 160 return contentType.getLiteralValue().toString(); 161 } 162 163 @Override 164 public void updateContent( final FedoraContent content ) throws FedoraException { 165 final HttpPut put = httpHelper.createContentPutMethod( path, null, content ); 166 167 try { 168 final HttpResponse response = httpHelper.execute( put ); 169 final StatusLine status = response.getStatusLine(); 170 final String uri = put.getURI().toString(); 171 172 if ( status.getStatusCode() == SC_CREATED 173 || status.getStatusCode() == SC_NO_CONTENT) { 174 LOGGER.debug("content updated successfully for resource {}", uri); 175 } else if ( status.getStatusCode() == SC_FORBIDDEN) { 176 LOGGER.error("request for resource {} is not authorized.", uri); 177 throw new ForbiddenException("request for resource " + uri + " is not authorized."); 178 } else if ( status.getStatusCode() == SC_NOT_FOUND) { 179 LOGGER.error("resource {} does not exist, cannot retrieve", uri); 180 throw new NotFoundException("resource " + uri + " does not exist, cannot retrieve"); 181 } else if ( status.getStatusCode() == SC_CONFLICT) { 182 LOGGER.error("checksum mismatch for {}", uri); 183 throw new FedoraException("checksum mismatch for resource " + uri); 184 } else { 185 LOGGER.error("error retrieving resource {}: {} {}", uri, status.getStatusCode(), 186 status.getReasonPhrase()); 187 throw new FedoraException("error retrieving resource " + uri + ": " + status.getStatusCode() + " " + 188 status.getReasonPhrase()); 189 } 190 191 // update properties from server 192 httpHelper.loadProperties(this); 193 194 } catch (final FedoraException e) { 195 throw e; 196 } catch (final Exception e) { 197 LOGGER.error("could not encode URI parameter", e); 198 throw new FedoraException(e); 199 } finally { 200 put.releaseConnection(); 201 } 202 } 203 204 @Override 205 public InputStream getContent() throws FedoraException { 206 final HttpGet get = httpHelper.createGetMethod( path, null ); 207 final String uri = get.getURI().toString(); 208 209 try { 210 final HttpResponse response = httpHelper.execute( get ); 211 final StatusLine status = response.getStatusLine(); 212 213 if ( status.getStatusCode() == SC_OK) { 214 return response.getEntity().getContent(); 215 } else if ( status.getStatusCode() == SC_FORBIDDEN) { 216 LOGGER.error("request for resource {} is not authorized.", uri); 217 throw new ForbiddenException("request for resource " + uri + " is not authorized."); 218 } else if ( status.getStatusCode() == SC_NOT_FOUND) { 219 LOGGER.error("resource {} does not exist, cannot retrieve", uri); 220 throw new NotFoundException("resource " + uri + " does not exist, cannot retrieve"); 221 } else { 222 LOGGER.error("error retrieving resource {}: {} {}", uri, status.getStatusCode(), 223 status.getReasonPhrase()); 224 throw new FedoraException("error retrieving resource " + uri + ": " + status.getStatusCode() + " " + 225 status.getReasonPhrase()); 226 } 227 } catch (final Exception e) { 228 LOGGER.error("could not encode URI parameter", e); 229 throw new FedoraException(e); 230 } finally { 231 get.releaseConnection(); 232 } 233 } 234 235 @Override 236 public void checkFixity() { 237 throw new NotImplemented("Method checkFixity() is not implemented"); 238 } 239 240 private Node getObjectValue( final Property property ) { 241 if ( !hasContent ) { 242 return null; 243 } 244 245 final Triple t = getTriple( contentSubject, property ); 246 if ( t == null ) { 247 return null; 248 } 249 250 return t.getObject(); 251 } 252}