001/*
002 * (C) Copyright 2015-2016 Nuxeo SA (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 *     Andre Justo
018 */
019package org.nuxeo.ecm.liveconnect.dropbox;
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.net.URI;
024import java.util.Collections;
025import java.util.Locale;
026import java.util.Map;
027
028import javax.servlet.http.HttpServletRequest;
029
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.nuxeo.ecm.core.api.DocumentModel;
033import org.nuxeo.ecm.core.blob.BlobManager.UsageHint;
034import org.nuxeo.ecm.core.blob.ManagedBlob;
035import org.nuxeo.ecm.core.model.Document;
036import org.nuxeo.ecm.liveconnect.core.AbstractLiveConnectBlobProvider;
037import org.nuxeo.ecm.liveconnect.core.LiveConnectFile;
038import org.nuxeo.ecm.liveconnect.core.LiveConnectFileInfo;
039import org.nuxeo.ecm.platform.oauth2.providers.OAuth2ServiceProvider;
040
041import com.dropbox.core.v2.files.FileMetadata;
042import com.dropbox.core.DbxException;
043import com.dropbox.core.DbxDownloader;
044import com.dropbox.core.v2.DbxClientV2;
045import com.dropbox.core.DbxRequestConfig;
046import com.dropbox.core.v2.files.ThumbnailFormat;
047import com.dropbox.core.v2.files.ThumbnailSize;
048
049import com.google.api.client.auth.oauth2.Credential;
050import com.google.api.client.http.GenericUrl;
051import com.google.api.client.http.HttpRequestFactory;
052import com.google.api.client.http.HttpResponse;
053
054/**
055 * Provider for blobs getting information from Dropbox.
056 *
057 * @since 7.3
058 */
059public class DropboxBlobProvider extends AbstractLiveConnectBlobProvider<DropboxOAuth2ServiceProvider> {
060
061    private static final Log log = LogFactory.getLog(DropboxBlobProvider.class);
062
063    private static final String APPLICATION_NAME = "Nuxeo/0";
064
065    private static final String FILE_CACHE_NAME = "dropbox";
066
067    private static final String DROPBOX_DOCUMENT_TO_BE_UPDATED_PP = "dropbox_document_to_be_updated";
068
069    @Override
070    protected String getCacheName() {
071        return FILE_CACHE_NAME;
072    }
073
074    @Override
075    public String getPageProviderNameForUpdate() {
076        return DROPBOX_DOCUMENT_TO_BE_UPDATED_PP;
077    }
078
079    @Override
080    public URI getURI(ManagedBlob blob, UsageHint usage, HttpServletRequest servletRequest) throws IOException {
081        LiveConnectFileInfo fileInfo = toFileInfo(blob);
082        String filePath = fileInfo.getFileId();
083        String url = null;
084        DbxClientV2 client = getDropboxClient(getCredential(fileInfo));
085        try {
086            switch (usage) {
087            case STREAM:
088                url = client.files().getTemporaryLink(filePath).getLink();
089                break;
090            case DOWNLOAD:
091                url = client.files().getTemporaryLink(filePath).getLink();
092                break;
093            case VIEW:
094                url = client.files().getTemporaryLink(filePath).getLink();
095                break;
096            }
097        } catch (DbxException e) {
098            throw new IOException("Failed to get Dropbox file URI " + e);
099        }
100        return url == null ? null : asURI(url);
101    }
102
103    @Override
104    public Map<String, URI> getAvailableConversions(ManagedBlob blob, UsageHint hint) throws IOException {
105        return Collections.emptyMap();
106    }
107
108    @Override
109    public InputStream getThumbnail(ManagedBlob blob) throws IOException {
110        LiveConnectFileInfo fileInfo = toFileInfo(blob);
111        String filePath = fileInfo.getFileId();
112        try {
113            DbxDownloader downloader = getDropboxClient(getCredential(fileInfo)).files()
114                    .getThumbnailBuilder(filePath)
115                    .withFormat(ThumbnailFormat.JPEG)
116                    .withSize(ThumbnailSize.W64H64)
117                    .start();
118            if (downloader == null) {
119                return null;
120            }
121            return downloader.getInputStream();
122        } catch (DbxException e) {
123            log.warn(String.format("Failed to get thumbnail for file %s", filePath), e);
124            return null;
125        }
126    }
127
128    @Override
129    public InputStream getStream(ManagedBlob blob) throws IOException {
130        URI uri = getURI(blob, UsageHint.STREAM, null);
131        return uri == null ? null : doGet(uri);
132    }
133
134    @Override
135    public InputStream getConvertedStream(ManagedBlob blob, String mimeType, DocumentModel doc) throws IOException {
136        Map<String, URI> conversions = getAvailableConversions(blob, UsageHint.STREAM);
137        URI uri = conversions.get(mimeType);
138        if (uri == null) {
139            return null;
140        }
141        return doGet(uri);
142    }
143
144    @Override
145    public ManagedBlob freezeVersion(ManagedBlob blob, Document doc) throws IOException {
146        return null;
147    }
148
149    protected DbxClientV2 getDropboxClient(Credential credential) throws IOException {
150        return getDropboxClient(credential.getAccessToken());
151    }
152
153    protected DbxClientV2 getDropboxClient(String accessToken) throws IOException {
154        DbxRequestConfig config = new DbxRequestConfig(APPLICATION_NAME, Locale.getDefault().toString());
155        return new DbxClientV2(config, accessToken);
156    }
157
158    /**
159     * Executes a GET request
160     */
161    protected InputStream doGet(URI url) throws IOException {
162        HttpRequestFactory requestFactory = getOAuth2Provider().getRequestFactory();
163        HttpResponse response = requestFactory.buildGetRequest(new GenericUrl(url)).execute();
164        return response.getContent();
165    }
166
167    protected String getClientId() {
168        OAuth2ServiceProvider provider = getOAuth2Provider();
169        return provider != null ? provider.getClientId() : null;
170    }
171
172    @Override
173    protected LiveConnectFile retrieveFile(LiveConnectFileInfo fileInfo) throws IOException {
174        try {
175            FileMetadata fileMetadata = getDropboxClient(getCredential(fileInfo))
176                    .files()
177                    .download(fileInfo.getFileId())
178                    .getResult();
179
180            if (fileMetadata == null) {
181                return null;
182            }
183            return new DropboxLiveConnectFile(fileInfo, fileMetadata);
184        } catch (DbxException e) {
185            throw new IOException("Failed to retrieve Dropbox file metadata", e);
186        }
187    }
188
189}