/*
* Copyright 2012 Evernote Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.evernote.client.android;
import android.util.Log;
import com.evernote.client.android.asyncclient.EvernoteUserStoreClient;
import com.evernote.edam.userstore.BootstrapInfo;
import com.evernote.edam.userstore.BootstrapProfile;
import com.evernote.thrift.TException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* A class that provides access to check the current
* {@link com.evernote.edam.userstore.Constants#EDAM_VERSION_MAJOR} and
* the {@link com.evernote.edam.userstore.Constants#EDAM_VERSION_MINOR} against the Evernote Web serivice for API
* Compatibility
*
* It provides access to the {@link List} of {@link BootstrapProfile} representing the possible server connections
* for the user. This list must be requested from the server on any type of authentication attempt
*
* @author @tylersmithnet
*/
@SuppressWarnings({"JavaDoc", "unused"})
/*package*/ class BootstrapManager {
private static final String LOGTAG = "EvernoteSession";
/**
* List of locales that match china.
*/
public static final List<Locale> CHINA_LOCALES = Collections.unmodifiableList(Arrays.asList(
Locale.TRADITIONAL_CHINESE,
Locale.CHINESE,
Locale.CHINA,
Locale.SIMPLIFIED_CHINESE
));
private ArrayList<String> mBootstrapServerUrls = new ArrayList<>();
private Locale mLocale;
private String mBootstrapServerUsed;
private final EvernoteSession mEvernoteSession;
/**
* package-scope constructor.
*/
BootstrapManager(EvernoteSession session) {
this(session.getEvernoteService(), session);
}
BootstrapManager(EvernoteSession.EvernoteService service, EvernoteSession session) {
this(service, session, Locale.getDefault());
}
/**
* package-scope constructor.
*
* @param service {@link com.evernote.client.android.EvernoteSession.EvernoteService#PRODUCTION} when using
* production and {@link com.evernote.client.android.EvernoteSession.EvernoteService#SANDBOX} when using sandbox
* @param locale Used to detect if the china servers need to be checked
*/
BootstrapManager(EvernoteSession.EvernoteService service, EvernoteSession session, Locale locale) {
mEvernoteSession = session;
mLocale = locale;
mBootstrapServerUrls.clear();
switch (service) {
case PRODUCTION:
if (CHINA_LOCALES.contains(mLocale)) {
mBootstrapServerUrls.add(EvernoteSession.HOST_CHINA);
}
mBootstrapServerUrls.add(EvernoteSession.HOST_PRODUCTION);
break;
case SANDBOX:
mBootstrapServerUrls.add(EvernoteSession.HOST_SANDBOX);
break;
}
}
/**
* Initialized the User Store to check for supported version of the API.
*
* @throws ClientUnsupportedException on unsupported version
* @throws Exception on generic errors
*/
private void initializeUserStoreAndCheckVersion() throws Exception {
int i = 0;
String version = com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR + "."
+ com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR;
for (String url : mBootstrapServerUrls) {
i++;
try {
EvernoteUserStoreClient userStoreClient = mEvernoteSession.getEvernoteClientFactory().getUserStoreClient(getUserStoreUrl(url), null);
if (!userStoreClient.checkVersion(EvernoteUtil.generateUserAgentString(mEvernoteSession.getApplicationContext()),
com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR)) {
throw new ClientUnsupportedException(version);
}
mBootstrapServerUsed = url;
return;
} catch (ClientUnsupportedException cue) {
Log.e(LOGTAG, "Invalid Version", cue);
throw cue;
} catch (Exception e) {
if (i < mBootstrapServerUrls.size()) {
Log.e(LOGTAG, "Error contacting bootstrap server=" + url, e);
} else {
throw e;
}
}
}
}
/**
* Makes a web request to get the latest bootstrap information.
* This is a requirement during the oauth process
*
* @return {@link BootstrapInfoWrapper}
* @throws Exception
*/
BootstrapInfoWrapper getBootstrapInfo() throws Exception {
Log.d(LOGTAG, "getBootstrapInfo()");
BootstrapInfo bsInfo = null;
try {
if (mBootstrapServerUsed == null) {
initializeUserStoreAndCheckVersion();
}
bsInfo = mEvernoteSession.getEvernoteClientFactory().getUserStoreClient(getUserStoreUrl(mBootstrapServerUsed), null).getBootstrapInfo(mLocale.toString());
printBootstrapInfo(bsInfo);
} catch (TException e) {
Log.e(LOGTAG, "error getting bootstrap info", e);
}
return new BootstrapInfoWrapper(mBootstrapServerUsed, bsInfo);
}
/**
* Log the {@link BootstrapProfile} list.
* @param bsInfo
*/
void printBootstrapInfo(BootstrapInfo bsInfo) {
if (bsInfo == null) return;
Log.d(LOGTAG, "printBootstrapInfo");
List<BootstrapProfile> profiles = bsInfo.getProfiles();
if (profiles != null) {
for (BootstrapProfile profile : profiles) {
Log.d(LOGTAG, profile.toString());
}
} else {
Log.d(LOGTAG, "Profiles are null");
}
}
/**
* Wrapper class to hold the Evernote API server URL and the {@link BootstrapProfile} object.
*/
static class BootstrapInfoWrapper {
private String mServerUrl;
private BootstrapInfo mBootstrapInfo;
BootstrapInfoWrapper(String serverUrl, BootstrapInfo info) {
mServerUrl = serverUrl;
mBootstrapInfo = info;
}
@SuppressWarnings("unused")
String getServerUrl() {
return mServerUrl;
}
BootstrapInfo getBootstrapInfo() {
return mBootstrapInfo;
}
}
public static class ClientUnsupportedException extends Exception {
public ClientUnsupportedException(String version) {
super("Client version " + version + " not supported.");
}
}
private String getUserStoreUrl(String bootstrapServer) {
return bootstrapServer + "/edam/user";
}
}