001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.kernel.impl.models; 007 008import org.apache.commons.io.input.BoundedInputStream; 009import org.fcrepo.kernel.api.RdfStream; 010import org.fcrepo.kernel.api.Transaction; 011import org.fcrepo.kernel.api.cache.UserTypesCache; 012import org.fcrepo.kernel.api.exception.ItemNotFoundException; 013import org.fcrepo.kernel.api.exception.PathNotFoundException; 014import org.fcrepo.kernel.api.exception.PathNotFoundRuntimeException; 015import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; 016import org.fcrepo.kernel.api.identifiers.FedoraId; 017import org.fcrepo.kernel.api.models.Binary; 018import org.fcrepo.kernel.api.models.ExternalContent; 019import org.fcrepo.kernel.api.models.FedoraResource; 020import org.fcrepo.kernel.api.models.ResourceFactory; 021import org.fcrepo.persistence.api.PersistentStorageSessionManager; 022import org.fcrepo.persistence.api.exceptions.PersistentItemNotFoundException; 023import org.fcrepo.persistence.api.exceptions.PersistentStorageException; 024 025import java.io.BufferedInputStream; 026import java.io.IOException; 027import java.io.InputStream; 028import java.net.URI; 029import java.util.Collection; 030import java.util.List; 031 032import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_BINARY; 033import static org.fcrepo.kernel.api.models.ExternalContent.PROXY; 034 035 036/** 037 * Implementation of a Non-RDF resource. 038 * 039 * @author bbpennel 040 */ 041public class BinaryImpl extends FedoraResourceImpl implements Binary { 042 043 private static final URI FEDORA_BINARY_URI = URI.create(FEDORA_BINARY.getURI()); 044 045 private String externalHandling; 046 047 private String externalUrl; 048 049 private Long contentSize; 050 051 private String filename; 052 053 private String mimeType; 054 055 private Collection<URI> digests; 056 057 /** 058 * Construct the binary 059 * 060 * @param fedoraID fedora identifier 061 * @param transaction transaction 062 * @param pSessionManager session manager 063 * @param resourceFactory resource factory 064 * @param userTypesCache the user types cache 065 */ 066 public BinaryImpl(final FedoraId fedoraID, 067 final Transaction transaction, 068 final PersistentStorageSessionManager pSessionManager, 069 final ResourceFactory resourceFactory, 070 final UserTypesCache userTypesCache) { 071 super(fedoraID, transaction, pSessionManager, resourceFactory, userTypesCache); 072 } 073 074 @Override 075 public InputStream getContent() { 076 try { 077 if (isProxy() || isRedirect()) { 078 // non-external streams are already buffered 079 return new BufferedInputStream(URI.create(getExternalURL()).toURL().openStream()); 080 } else { 081 return getSession().getBinaryContent(getFedoraId().asResourceId(), getMementoDatetime()); 082 } 083 } catch (final PersistentItemNotFoundException e) { 084 throw new ItemNotFoundException("Unable to find content for " + getId() 085 + " version " + getMementoDatetime(), e); 086 } catch (final PersistentStorageException | IOException e) { 087 throw new RepositoryRuntimeException(e.getMessage(), e); 088 } 089 } 090 091 @Override 092 public InputStream getRange(final long start, final long end) { 093 try { 094 if (isProxy() || isRedirect()) { 095 // non-external streams are already buffered 096 final long length = end + 1; 097 final var stream = new BoundedInputStream(URI.create(getExternalURL()).toURL().openStream(), length); 098 stream.skip(start); 099 return stream; 100 } else { 101 return getSession().getBinaryRange(getFedoraId().asResourceId(), getMementoDatetime(), start, end); 102 } 103 } catch (final PersistentItemNotFoundException e) { 104 throw new ItemNotFoundException("Unable to find content for " + getId() 105 + " version " + getMementoDatetime(), e); 106 } catch (final PersistentStorageException | IOException e) { 107 throw new RepositoryRuntimeException(e.getMessage(), e); 108 } 109 } 110 111 @Override 112 public long getContentSize() { 113 return contentSize; 114 } 115 116 @Override 117 public Collection<URI> getContentDigests() { 118 if (digests == null) { 119 return null; 120 } 121 return digests; 122 } 123 124 @Override 125 public Boolean isProxy() { 126 return PROXY.equals(externalHandling); 127 } 128 129 @Override 130 public Boolean isRedirect() { 131 return ExternalContent.REDIRECT.equals(externalHandling); 132 } 133 134 @Override 135 public String getExternalURL() { 136 return externalUrl; 137 } 138 139 @Override 140 public String getMimeType() { 141 return mimeType; 142 } 143 144 @Override 145 public String getFilename() { 146 return filename; 147 } 148 149 @Override 150 public FedoraResource getDescription() { 151 try { 152 final FedoraId descId = getFedoraId().asDescription(); 153 if (this.isMemento()) { 154 final var descIdAsMemento = descId.asMemento(getMementoDatetime()); 155 return resourceFactory.getResource(transaction, descIdAsMemento); 156 } 157 return resourceFactory.getResource(transaction, descId); 158 } catch (final PathNotFoundException e) { 159 throw new PathNotFoundRuntimeException(e.getMessage(), e); 160 } 161 } 162 163 /** 164 * @param externalHandling the externalHandling to set 165 */ 166 protected void setExternalHandling(final String externalHandling) { 167 this.externalHandling = externalHandling; 168 } 169 170 /** 171 * @param externalUrl the externalUrl to set 172 */ 173 protected void setExternalUrl(final String externalUrl) { 174 this.externalUrl = externalUrl; 175 } 176 177 /** 178 * @param contentSize the contentSize to set 179 */ 180 protected void setContentSize(final Long contentSize) { 181 this.contentSize = contentSize; 182 } 183 184 /** 185 * @param filename the filename to set 186 */ 187 protected void setFilename(final String filename) { 188 this.filename = filename; 189 } 190 191 /** 192 * @param mimeType the mimeType to set 193 */ 194 protected void setMimeType(final String mimeType) { 195 this.mimeType = mimeType; 196 } 197 198 /** 199 * @param digests the digests to set 200 */ 201 protected void setDigests(final Collection<URI> digests) { 202 this.digests = digests; 203 } 204 205 @Override 206 public List<URI> getSystemTypes(final boolean forRdf) { 207 var types = resolveSystemTypes(forRdf); 208 209 if (types == null) { 210 types = super.getSystemTypes(forRdf); 211 // Add fedora:Binary type. 212 types.add(FEDORA_BINARY_URI); 213 } 214 215 return types; 216 } 217 218 @Override 219 public RdfStream getTriples() { 220 return getDescription().getTriples(); 221 } 222}