001/*
002 * (C) Copyright 2015-2017 Nuxeo (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Florent Guillaume
018 *     Nelson Silva
019 *     Gabriel Barata
020 */
021package org.nuxeo.ecm.core.blob;
022
023import java.io.File;
024import java.io.IOException;
025import java.io.InputStream;
026import java.net.URI;
027import java.util.Collections;
028import java.util.List;
029import java.util.Map;
030
031import javax.servlet.http.HttpServletRequest;
032
033import org.nuxeo.ecm.core.api.Blob;
034import org.nuxeo.ecm.core.api.NuxeoException;
035import org.nuxeo.ecm.core.blob.BlobManager.UsageHint;
036import org.nuxeo.ecm.core.blob.apps.AppLink;
037import org.nuxeo.ecm.core.blob.binary.BinaryGarbageCollector;
038import org.nuxeo.ecm.core.blob.binary.BinaryManager;
039
040/**
041 * Interface for a provider of {@link Blob}s, which knows how to read and write them.
042 *
043 * @since 7.2
044 */
045public interface BlobProvider {
046
047    /**
048     * Initializes the blob provider.
049     *
050     * @param blobProviderId the blob provider id for this binary manager
051     * @param properties initialization properties
052     *
053     * @since 7.3
054     */
055    void initialize(String blobProviderId, Map<String, String> properties) throws IOException;
056
057    /**
058     * Closes this blob provider and releases resources that may be held by it.
059     *
060     * @since 7.3
061     */
062    void close();
063
064    /**
065     * Checks whether this blob provider uses "record mode".
066     * <p>
067     * Record mode has the following characteristics:
068     * <ul>
069     * <li>transactional (blobs aren't actually written/deleted until the transaction commits, and transaction rollback
070     * is possible),
071     * <li>can replace or delete a document's blob.
072     * </ul>
073     *
074     * @since 11.1
075     */
076    default boolean isRecordMode() {
077        return false;
078    }
079
080    /**
081     * Checks whether this blob provider is transactional.
082     * <p>
083     * A transactional blob provider only writes blobs to final storage at commit time.
084     *
085     * @since 11.1
086     */
087    default boolean isTransactional() {
088        return false;
089    }
090
091    /**
092     * Checks whether this blob provider is transient: blobs may disappear after a while, so a caller should not rely on
093     * them being available forever.
094     *
095     * @since 10.1
096     */
097    default boolean isTransient() {
098        return false;
099    }
100
101    /**
102     * Checks whether this blob provider allows byte ranges in keys.
103     *
104     * @since 11.1
105     */
106    default boolean allowByteRange() {
107        return false;
108    }
109
110    /**
111     * Reads a {@link Blob} from storage.
112     *
113     * @param blobInfoContext the blob information context
114     * @return the blob
115     * @since 11.1
116     */
117    default Blob readBlob(BlobInfoContext blobInfoContext) throws IOException {
118        return readBlob(blobInfoContext.blobInfo);
119    }
120
121    /**
122     * Reads a {@link Blob} from storage.
123     *
124     * @param blobInfo the blob information
125     * @return the blob
126     */
127    Blob readBlob(BlobInfo blobInfo) throws IOException;
128
129    /**
130     * Writes a {@link Blob} to storage and returns information about it.
131     * <p>
132     * Called to store a user-created blob.
133     *
134     * @param blobContext the blob context
135     * @return the blob key
136     * @since 11.1
137     */
138    default String writeBlob(BlobContext blobContext) throws IOException {
139        return writeBlob(blobContext.blob);
140    }
141
142    /**
143     * Writes a {@link Blob} to storage and returns information about it.
144     * <p>
145     * Called to store a user-created blob.
146     *
147     * @param blob the blob
148     * @return the blob key
149     * @since 9.2
150     */
151    String writeBlob(Blob blob) throws IOException;
152
153    /**
154     * Updates a blob's properties in storage.
155     *
156     * @param blobUpdateContext the blob update context
157     * @since 11.1
158     */
159    default void updateBlob(BlobUpdateContext blobUpdateContext) throws IOException {
160        // ignore properties updates by default
161    }
162
163    /**
164     * Deletes a blob from storage. Only meaningful for a record blob provider.
165     *
166     * @param blobContext the blob context
167     * @see #isRecordMode
168     * @since 11.1
169     */
170    default void deleteBlob(BlobContext blobContext) {
171        throw new UnsupportedOperationException();
172    }
173
174    /**
175     * Gets the status of a blob.
176     *
177     * @param blob the blob
178     * @since 11.1
179     */
180    default BlobStatus getStatus(ManagedBlob blob) throws IOException {
181        return new BlobStatus();
182    }
183
184    /**
185     * Checks if user update is supported.
186     * <p>
187     * A user update refers to the fact that a blob from this provider may be overwritten with another blob, wherever
188     * the original blob may occur (usually in a document property).
189     *
190     * @return {@code true} if user update is supported
191     * @since 7.10
192     */
193    boolean supportsUserUpdate();
194
195    /**
196     * Checks if sync is supported.
197     * <p>
198     * Sync refers to the fact that a blob from this provider may be synced with a remote system (like Nuxeo Drive) or
199     * with a process that updates things in the blob (like Binary Metadata, or WOPI).
200     *
201     * @return {@code true} if sync is supported
202     * @since 11.1
203     */
204    default boolean supportsSync() {
205        return supportsUserUpdate() && getBinaryManager() != null;
206    }
207
208    /**
209     * Gets an {@link InputStream} for a byte range of a managed blob.
210     *
211     * @param blobKey the blob key
212     * @param byteRange the byte range
213     * @return the stream
214     * @since 11.1
215     */
216    default InputStream getStream(String blobKey, ByteRange byteRange) throws IOException {
217        throw new UnsupportedOperationException();
218    }
219
220    /**
221     * Gets an {@link InputStream} for the data of a managed blob.
222     * <p>
223     * Like all {@link InputStream}, the result must be closed when done with it to avoid resource leaks.
224     *
225     * @param blob the managed blob
226     * @return the stream
227     * @since 7.3
228     */
229    default InputStream getStream(ManagedBlob blob) throws IOException {
230        return null;
231    }
232
233    /**
234     * Gets a {@link File} (if one exists) for the data of a managed blob.
235     *
236     * @param blob the managed blob
237     * @return the file, or {@code null} if no underlying file is available
238     * @since 11.1
239     */
240    default File getFile(ManagedBlob blob) {
241        return null;
242    }
243
244    /**
245     * Gets an {@link InputStream} for a thumbnail of a managed blob.
246     * <p>
247     * Like all {@link InputStream}, the result must be closed when done with it to avoid resource leaks.
248     *
249     * @param blob the managed blob
250     * @return the stream
251     * @since 7.3
252     */
253    default InputStream getThumbnail(ManagedBlob blob) throws IOException {
254        return null;
255    }
256
257    /**
258     * Gets an {@link URI} for the content of a managed blob.
259     *
260     * @param blob the managed blob
261     * @param hint {@link UsageHint}
262     * @param servletRequest the servlet request, or {@code null}
263     * @return the {@link URI}, or {@code null} if none available
264     * @since 7.4
265     */
266    default URI getURI(ManagedBlob blob, UsageHint hint, HttpServletRequest servletRequest) throws IOException {
267        return null;
268    }
269
270    /**
271     * Gets a map of available MIME type conversions and corresponding {@link URI} for a managed blob.
272     *
273     * @param blob the managed blob
274     * @param hint {@link UsageHint}
275     * @return a map of MIME types and {@link URI}, which may be empty
276     * @since 7.3
277     */
278    default Map<String, URI> getAvailableConversions(ManagedBlob blob, UsageHint hint) throws IOException {
279        return Collections.emptyMap();
280    }
281
282    /**
283     * Checks if the conversion to the given {@code mimeType} is supported by the {@code blob}.
284     *
285     * @param blob the managed blob
286     * @param mimeType the destination mime type
287     * @return {@code true} if this managed blob supports the conversion to the given mime type
288     * @since 10.1
289     */
290    default boolean canConvert(ManagedBlob blob, String mimeType) {
291        try {
292            Map<String, URI> availableConversions = getAvailableConversions(blob, UsageHint.STREAM);
293            return availableConversions.containsKey(mimeType);
294        } catch (IOException e) {
295            throw new NuxeoException(e);
296        }
297    }
298
299    /**
300     * Returns true if version of the blob is a version.
301     * <p>
302     *
303     * @param blob the managed blob
304     * @return true if the blob is a version or a revision
305     * @since 7.3
306     */
307    default boolean isVersion(ManagedBlob blob) {
308        return false;
309    }
310
311    /**
312     * Returns a list of application links for the given blob.
313     *
314     * @since 7.3
315     */
316    default List<AppLink> getAppLinks(String user, ManagedBlob blob) throws IOException {
317        return Collections.emptyList();
318    }
319
320    /**
321     * Gets the associated binary manager, if any.
322     *
323     * @return the binary manager, or {@code null}
324     * @since 7.4
325     */
326    default BinaryManager getBinaryManager() {
327        return null;
328    }
329
330    /**
331     * Gets the associated garbage collector, if any.
332     *
333     * @return the garbage collector, or {@code null}
334     * @since 11.1
335     */
336    default BinaryGarbageCollector getBinaryGarbageCollector() {
337        BinaryManager binaryManager = getBinaryManager();
338        return binaryManager == null ? null : binaryManager.getGarbageCollector();
339    }
340
341    /**
342     * Checks if the blob provider performs external access control checks.
343     *
344     * @param blobInfo the blob information to be read
345     * @return {@code true} if the provider performs security checks before reading a blob, {@code false} otherwise
346     * @since 8.4
347     */
348    default boolean performsExternalAccessControl(BlobInfo blobInfo) {
349        return false;
350    }
351
352    /**
353     * Returns the properties of the blob provider.
354     *
355     * @since 10.2
356     */
357    Map<String, String> getProperties();
358
359    /**
360     * Checks if current user has the rights to create blobs in the blob provider using a key.
361     *
362     * @since 10.2
363     */
364    default boolean hasCreateFromKeyPermission() {
365        return false;
366    }
367
368}