package org.ovirt.mobile.movirt.rest; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.text.TextUtils; import org.androidannotations.annotations.AfterInject; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; import org.androidannotations.rest.spring.api.RestClientHeaders; import org.androidannotations.rest.spring.api.RestClientRootUrl; import org.androidannotations.rest.spring.api.RestClientSupport; import org.ovirt.mobile.movirt.Broadcasts; import org.ovirt.mobile.movirt.R; import org.ovirt.mobile.movirt.auth.properties.AccountProperty; import org.ovirt.mobile.movirt.auth.properties.manager.AccountPropertiesManager; import org.ovirt.mobile.movirt.auth.properties.property.version.Version; import org.ovirt.mobile.movirt.util.message.ErrorType; import org.ovirt.mobile.movirt.util.message.MessageHelper; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.ResourceAccessException; import static org.ovirt.mobile.movirt.rest.RestHelper.prepareAuthToken; @EBean(scope = EBean.Scope.Singleton) public class RequestHandler { private static final String TAG = RequestHandler.class.getSimpleName(); @RootContext Context context; @Bean AccountPropertiesManager accountPropertiesManager; @Bean MessageHelper messageHelper; private Version version; @AfterInject public void init() { accountPropertiesManager.notifyAndRegisterListener(new AccountProperty.VersionListener() { @Override public void onPropertyChange(Version newVersion) { version = newVersion; } }); } /** * has to be synced because of error handling - otherwise it would not be possible to bind the error */ public synchronized <T> void fireRestRequest(final Request<T> request, final Response<T> response) { if (response != null) { response.before(); } RestCallResult result = doFireRequestWithPersistentAuth(request, response); if (result == RestCallResult.AUTH_ERROR) { // if it is an expired session it has been cleared - try again. // If the credentials were filled well, now it will pass result = doFireRequestWithPersistentAuth(request, response); } if (result != RestCallResult.SUCCESS && response != null) { response.onError(); } if (response != null) { response.after(); } } private <T, U extends RestClientRootUrl & RestClientHeaders & RestClientSupport> RestCallResult doFireRequestWithPersistentAuth(Request<T> request, Response<T> response) { RestCallResult result = RestCallResult.OTHER_ERROR; U restClient = request.getRestClient(); try { Bundle bundle = accountPropertiesManager.getAuthToken().getResult(); if (bundle.containsKey(AccountManager.KEY_AUTHTOKEN)) { String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN); if (TextUtils.isEmpty(authToken)) { messageHelper.showError(ErrorType.REST_MAJOR, context.getString(R.string.rest_token_missing)); } else { prepareAuthToken(restClient, version, authToken); T restResponse = request.fire(); result = RestCallResult.SUCCESS; if (response != null) { response.onResponse(restResponse); } } } else if (bundle.containsKey(AccountManager.KEY_INTENT)) { Intent accountAuthenticatorResponse = bundle.getParcelable(AccountManager.KEY_INTENT); Intent editConnectionIntent = new Intent(Broadcasts.NO_CONNECTION_SPECIFIED); editConnectionIntent.putExtra(AccountManager.KEY_INTENT, accountAuthenticatorResponse); context.sendBroadcast(editConnectionIntent); result = RestCallResult.CONNECTION_ERROR; } } catch (ResourceAccessException | AuthenticatorException e) { messageHelper.showError(ErrorType.REST_MINOR, e); result = RestCallResult.CONNECTION_ERROR; } catch (HttpClientErrorException e) { String msg = e.getMessage(); switch (e.getStatusCode()) { case UNAUTHORIZED: // ok, session id is not valid anymore - invalidate it accountPropertiesManager.setAuthToken(null); result = RestCallResult.AUTH_ERROR; break; case NOT_FOUND: messageHelper.showError(ErrorType.REST_MAJOR, context.getString(R.string.rest_url_missing, msg, restClient.getRootUrl())); break; default: messageHelper.showError(ErrorType.REST_MAJOR, messageHelper.createMessage(e)); break; } } catch (Exception e) { messageHelper.showError(ErrorType.REST_MAJOR, e); } if (result == RestCallResult.SUCCESS) { messageHelper.resetMinorErrors(); } return result; } private enum RestCallResult { SUCCESS, AUTH_ERROR, CONNECTION_ERROR, OTHER_ERROR } }