/* * #%L * Wheelmap - App * %% * Copyright (C) 2011 - 2012 Michal Harakal - Michael Kroez - Sozialhelden e.V. * %% * Wheelmap App based on the Wheelmap Service by Sozialhelden e.V. * * 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. * #L% */ package org.wheelmap.android.net; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageConversionException; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestClientException; import org.springframework.web.util.UriUtils; import org.wheelmap.android.app.WheelmapApp; import org.wheelmap.android.mapping.Base; import org.wheelmap.android.mapping.node.Nodes; import org.wheelmap.android.mapping.node.Photo; import org.wheelmap.android.mapping.node.Photos; import org.wheelmap.android.mapping.node.SingleNode; import org.wheelmap.android.model.Extra; import org.wheelmap.android.model.Extra.What; import org.wheelmap.android.modules.IAppProperties; import org.wheelmap.android.modules.ICredentials; import org.wheelmap.android.modules.IHttpUserAgent; import org.wheelmap.android.modules.UserCredentials; import org.wheelmap.android.net.request.RequestBuilder; import org.wheelmap.android.net.request.RequestProcessor; import org.wheelmap.android.online.BuildConfig; import org.wheelmap.android.service.RestServiceException; import android.content.ContentResolver; import android.content.Context; import android.os.Bundle; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import de.akquinet.android.androlog.Log; import roboguice.RoboGuice; public abstract class AbstractExecutor<T extends Base> implements IExecutor { protected final static RequestProcessor mRequestProcessor = new RequestProcessor(); private final static int statusBadRequest = 400; private final static int statusAuthRequired = 401; private final static int statusRequestForbidden = 403; private final static int statusNotFound = 404; private final static int statusNotAcceptable = 406; private final static int statusInternalServerError = 500; private final static int statusDownMaintenance = 503; private final int fMaxRetryCount; private final Context mContext; private final Bundle mBundle; private final Class<T> mClazz; protected IAppProperties mAppProperties; protected ICredentials mCredentials; public AbstractExecutor(Context context, Bundle bundle, Class<T> clazz, int maxRetryCount) { mContext = context; mBundle = bundle; mClazz = clazz; fMaxRetryCount = maxRetryCount; mCredentials = new UserCredentials(mContext); } public static IExecutor create(Context context, Bundle bundle, IAppProperties appProperties, ICredentials credentials, IHttpUserAgent httpUserAgent) { if (bundle == null || !bundle.containsKey(Extra.WHAT)) { return null; } int what = bundle.getInt(Extra.WHAT); IExecutor executor; switch (what) { case What.RETRIEVE_NODE: executor = new NodeExecutor(context, bundle); break; case What.RETRIEVE_MARKER_ICONS: executor = new MarkerIconExecutor(context,bundle); break; case What.RETRIEVE_NODES: case What.SEARCH_NODES: case What.SEARCH_NODES_IN_BOX: executor = new NodesExecutor(context, bundle); break; case What.RETRIEVE_TOTAL_NODE_COUNT: executor = new TotalNodeCountExecutor(context,bundle); break; case What.RETRIEVE_LOCALES: executor = new LocalesExecutor(context, bundle); break; case What.RETRIEVE_CATEGORIES: executor = new CategoriesExecutor(context, bundle); break; case What.RETRIEVE_NODETYPES: executor = new NodeTypesExecutor(context, bundle); break; case What.UPDATE_SERVER: executor = new NodeUpdateOrNewExecutor(context); break; case What.RETRIEVE_APIKEY: executor = new ApiKeyExecutor(context, bundle); break; case What.RETRIEVE_PHOTO: executor = new PhotosExecutor(context, bundle); break; case What.UPDATE_PHOTO: executor = new PhotoExecutor(context, bundle); break; default: return null; // noop no instruction, no operation; } executor.setAppProperties(appProperties); executor.setCredentials(credentials); executor.setUserAgent(httpUserAgent.getAppUserAgent()); return executor; } @Override public void setAppProperties(IAppProperties appProperties) { mAppProperties = appProperties; } @Override public void setCredentials(ICredentials credentials) { mCredentials = credentials; } @Override public void setUserAgent(String userAgent) { mRequestProcessor.setUserAgent(userAgent); } protected String getEtag() { return mRequestProcessor.getEtag(); } protected void setEtag(String etag) { mRequestProcessor.setEtag(etag); } protected Context getContext() { return mContext; } protected ContentResolver getResolver() { return mContext.getContentResolver(); } protected Bundle getBundle() { return mBundle; } public abstract void prepareContent(); public abstract void execute(long id) throws RestServiceException; public abstract void prepareDatabase() throws RestServiceException; @Override public String getServer() { return BuildConfig.API_BASE_URL; } protected String getTag() { return getClass().getSimpleName(); } protected String getApiKey() { return mCredentials.getApiKey(); } protected T executeRequest(RequestBuilder requestBuilder) throws RestServiceException { T content = null; String request = null; try { if (requestBuilder.urlIsAlreadyUrlEncoded()) { request = requestBuilder.buildRequestUri(); } else { request = UriUtils.encodeQuery(requestBuilder.buildRequestUri(), "utf-8"); } } catch (UnsupportedEncodingException e) { processException( RestServiceException.ERROR_INTERNAL_ERROR, e, true); } Log.d("Executer",request); if (request == null) { // workaround for compiling not recognizing that request will be initialized return null; } int retryCount = 0; while (retryCount < fMaxRetryCount) { try { if (requestBuilder.getRequestType() == RequestBuilder.REQUEST_GET) { Log.d(getTag(), "getRequest = *" + request + "*"); content = mRequestProcessor.get(new URI(request), mClazz); } else if (requestBuilder.getRequestType() == RequestBuilder.REQUEST_POST) { Log.d(getTag(), "postRequest = *" + request + "*"); content = (T) mRequestProcessor.post(new URI(request), null, mClazz); } else if(requestBuilder.getRequestType() == RequestBuilder.REQUEST_PUT_PHOTO){ Log.d(getTag(), "uploadPhoto = *" + request + "+"); content = (T) mRequestProcessor.post(new URI(request),null,mClazz); } else if(requestBuilder.getRequestType() == RequestBuilder.REQUEST_MAX_NODE_COUNT){ Log.d(getTag(), "getTotalNodeCount = *" + request + "+"); content = (T) mRequestProcessor.get(new URI(request),mClazz); } else { Log.d(getTag(), "putRequest = *" + request + "*"); mRequestProcessor.put(new URI(request), null); } break; } catch (URISyntaxException e) { processException( RestServiceException.ERROR_INTERNAL_ERROR, e, true); } catch (ResourceAccessException e) { retryCount++; if (retryCount < fMaxRetryCount) { Log.d(getTag(), "request timed out - retrying"); try { Thread.sleep(200); } catch (InterruptedException e1) { // do nothing, just // continue and try // again } continue; } else { processException( RestServiceException.ERROR_NETWORK_FAILURE, e, true); } } catch (HttpClientErrorException e) { HttpStatus status = e.getStatusCode(); checkApiCallClientErrors(e); if (status.value() == statusAuthRequired || (this instanceof ApiKeyExecutor && status.value() == statusBadRequest)) { Log.e(getTag(), "authorization failed - apikey not valid"); processException( RestServiceException.ERROR_AUTHORIZATION_FAILED, e, true); } else if (status.value() == statusRequestForbidden) { Log.e(getTag(), "request forbidden"); processException( RestServiceException.ERROR_REQUEST_FORBIDDEN, e, true); } else if ((status.value() == statusBadRequest) || (status.value() == statusNotFound) || (status.value() == statusNotAcceptable)) { Log.e(getTag(), "request error"); processException( RestServiceException.ERROR_CLIENT_FAILURE, e, true); } else { processException( RestServiceException.ERROR_CLIENT_FAILURE, e, true); } } catch (HttpServerErrorException e) { HttpStatus status = e.getStatusCode(); if (status.value() == statusDownMaintenance) { processException( RestServiceException.ERROR_SERVER_DOWN, e, true); } else { processException( RestServiceException.ERROR_SERVER_FAILURE, e, true); } } catch (HttpMessageConversionException e) { processException( RestServiceException.ERROR_NETWORK_FAILURE, e, false); } catch (Exception e) { processException( RestServiceException.ERROR_NETWORK_UNKNOWN_FAILURE, e, true); } } Log.d(getTag(), "executeRequest successful"); if(content != null){ WheelmapApp app = (WheelmapApp) this.getContext().getApplicationContext(); if(content.getClass().toString().equals("class org.wheelmap.android.mapping.node.Photos")){ Log.d("Photos"); try { for(Photo p : ((Photos)content).getPhotos()){ p.getImages().remove(9); p.getImages().remove(8); p.getImages().remove(7); p.getImages().remove(6); p.getImages().remove(5); p.getImages().remove(0); p.getImages().remove(0); p.getImages().remove(0); p.getImages().remove(0); } app.setPhotos((Photos)content); } catch (Exception e) { e.printStackTrace(); } } else if(content.getClass().toString().equals("class org.wheelmap.android.mapping.node.SingleNode")){ Log.d("Node"); try{ app.setNode(((SingleNode)content).getNode()); }catch(Exception ex){ ex.printStackTrace(); } } else if(content.getClass().toString().equals("class org.wheelmap.android.mapping.node.Nodes")){ int size = ((Nodes)content).getNodes().size(); if(size == 0){ if(app.isSearching() == true) app.setSearchSuccessfully(false); else app.setSearchSuccessfully(true); } } } return content; } protected void checkApiCallClientErrors(HttpClientErrorException e) throws RestServiceException { } protected void processException(int errorCode, Throwable t, boolean sendToBugsense) throws RestServiceException { throw new RestServiceException(errorCode, t); } }