/*
* Copyright (C) 2013 uPhyca Inc. http://www.uphyca.com/
*
* 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 com.uphyca.kitkat.storage.internal.impl;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import com.microsoft.live.LiveAuthClient;
import com.microsoft.live.LiveAuthException;
import com.microsoft.live.LiveAuthListener;
import com.microsoft.live.LiveConnectClient;
import com.microsoft.live.LiveConnectSession;
import com.microsoft.live.LiveDownloadOperation;
import com.microsoft.live.LiveOperation;
import com.microsoft.live.LiveOperationException;
import com.microsoft.live.LiveStatus;
import com.microsoft.live.OverwriteOption;
import com.uphyca.kitkat.storage.internal.SkyDriveClient;
import com.uphyca.kitkat.storage.skydrive.JsonKeys;
import com.uphyca.kitkat.storage.skydrive.Scopes;
import com.uphyca.kitkat.storage.skydrive.SkyDriveObject;
/**
* LiveSDK for Androidを使った実装。
*
* @see <a href="https://github.com/liveservices/LiveSDK-for-Android/">LiveSDK for Android</a>
* @author masui@uphyca.com
*/
public class LiveSdkSkyDriveClient implements SkyDriveClient {
private static final List<String> SCOPES = Arrays.asList(new String[] {
Scopes.SIGNIN, //
Scopes.OFFLINE_ACCESS, //
Scopes.SKYDRIVE_UPDATE
});
private final Context mContext;
private final LiveAuthClient mLiveAuthClient;
private LiveConnectClient mLiveConnectClient;
public LiveSdkSkyDriveClient(Context context, LiveAuthClient liveAuthClient) {
mContext = context;
mLiveAuthClient = liveAuthClient;
}
@Override
public void initializeIfNecessary() {
if (mLiveConnectClient != null) {
return;
}
final CountDownLatch lock = new CountDownLatch(1);
mLiveAuthClient.initialize(SCOPES, new LiveAuthListener() {
@Override
public void onAuthComplete(LiveStatus status, LiveConnectSession session, Object userState) {
if (status == LiveStatus.CONNECTED) {
mLiveConnectClient = new LiveConnectClient(session);
}
lock.countDown();
}
@Override
public void onAuthError(LiveAuthException exception, Object userState) {
lock.countDown();
}
});
try {
lock.await();
} catch (InterruptedException ignore) {
}
}
@Override
public void login(final Activity activity, final SkyDriveAuthListener listener) {
mLiveAuthClient.login(activity, SCOPES, new LiveAuthListener() {
@Override
public void onAuthComplete(LiveStatus status, LiveConnectSession session, Object userState) {
if (status == LiveStatus.CONNECTED) {
mLiveConnectClient = new LiveConnectClient(session);
listener.onAuthComplete();
return;
}
Exception e = new RuntimeException("Login did not connect. Status is " + status + ".");
e.fillInStackTrace();
listener.onAuthError(e);
}
@Override
public void onAuthError(LiveAuthException exception, Object userState) {
Exception e = new RuntimeException(exception);
listener.onAuthError(e);
}
});
}
@Override
public SkyDriveObject[] get(String documentId) {
initializeIfNecessary();
if (mLiveConnectClient == null) {
return empty();
}
final LiveOperation operation;
try {
operation = mLiveConnectClient.get(documentId);
} catch (LiveOperationException ignore) {
return empty();
}
JSONObject syncResult = operation.getResult();
if (syncResult.has(JsonKeys.ERROR)) {
return empty();
}
if (syncResult.has(JsonKeys.DATA)) {
JSONArray array = syncResult.optJSONArray(JsonKeys.DATA);
SkyDriveObject[] objects = new SkyDriveObject[array.length()];
for (int i = 0, length = array.length(); i < length; ++i) {
objects[i] = SkyDriveObject.create(array.optJSONObject(i));
}
return objects;
}
return new SkyDriveObject[] {
SkyDriveObject.create(syncResult)
};
}
@Override
public File download(String documentId) throws IOException {
initializeIfNecessary();
if (mLiveConnectClient == null) {
return null;
}
String path = documentId + "/content";
final LiveDownloadOperation download;
try {
download = mLiveConnectClient.download(path);
} catch (LiveOperationException ignore) {
return null;
}
InputStream in = null;
try {
File temp = File.createTempFile("document", null, mContext.getCacheDir());
in = download.getStream();
drain(in, temp);
return temp;
} finally {
closeQuietly(in);
}
}
@Override
public String upload(String path, String name, File file) throws IOException {
initializeIfNecessary();
if (mLiveConnectClient == null) {
return null;
}
try {
LiveOperation post = mLiveConnectClient.upload(path, name, file, OverwriteOption.Overwrite);
JSONObject result = post.getResult();
if (result.has(JsonKeys.ERROR)) {
JSONObject error = result.optJSONObject(JsonKeys.ERROR);
String message = error.optString(JsonKeys.MESSAGE);
IOException ioException = new IOException(message);
ioException.fillInStackTrace();
throw ioException;
}
try {
return result.getString(JsonKeys.ID);
} catch (JSONException e) {
IOException ioException = new IOException(e.getMessage());
ioException.initCause(e);
throw ioException;
}
} catch (LiveOperationException e) {
IOException ioException = new IOException(e.getMessage());
ioException.initCause(e);
throw ioException;
}
}
@Override
public String mkdir(String path, String name) throws IOException {
initializeIfNecessary();
if (mLiveConnectClient == null) {
return null;
}
Map<String, String> folder = new HashMap<>();
folder.put(JsonKeys.NAME, name);
folder.put(JsonKeys.DESCRIPTION, null);
try {
LiveOperation post = mLiveConnectClient.post(path, new JSONObject(folder));
JSONObject result = post.getResult();
if (result.has(JsonKeys.ERROR)) {
JSONObject error = result.optJSONObject(JsonKeys.ERROR);
String message = error.optString(JsonKeys.MESSAGE);
IOException ioException = new IOException(message);
ioException.fillInStackTrace();
throw ioException;
}
try {
return result.getString(JsonKeys.ID);
} catch (JSONException e) {
IOException ioException = new IOException(e.getMessage());
ioException.initCause(e);
throw ioException;
}
} catch (LiveOperationException e) {
IOException ioException = new IOException(e.getMessage());
ioException.initCause(e);
throw ioException;
}
}
@Override
public String touch(String path, String name) throws IOException {
initializeIfNecessary();
if (mLiveConnectClient == null) {
return null;
}
File temp = File.createTempFile("document", null, mContext.getCacheDir());
if (!temp.exists()) {
IOException ioException = new IOException("Failed to touch " + name);
ioException.fillInStackTrace();
throw ioException;
}
return upload(path, name, temp);
}
@Override
public void delete(String path) throws IOException {
initializeIfNecessary();
if (mLiveConnectClient == null) {
return;
}
try {
mLiveConnectClient.delete(path);
} catch (LiveOperationException e) {
IOException ioException = new IOException("Failed to delete " + path);
ioException.initCause(e);
throw ioException;
}
}
private static SkyDriveObject[] empty() {
return new SkyDriveObject[0];
}
private static void drain(InputStream in, File dest) throws IOException {
OutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
try {
byte[] buf = new byte[8192];
for (int c; (c = in.read(buf)) > -1;) {
out.write(buf, 0, c);
}
out.flush();
} finally {
closeQuietly(out);
}
}
private static void closeQuietly(Closeable res) {
if (res == null) {
return;
}
try {
res.close();
} catch (IOException e) {
}
}
}