/** * Copyright (C) 2013 Romain Guefveneu. * * This file is part of naonedbus. * * Naonedbus is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Naonedbus is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.naonedbus.rest.controller; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; import java.util.Locale; import net.naonedbus.BuildConfig; import net.naonedbus.rest.UrlBuilder; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import android.util.Log; /** * @author romain.guefveneu * */ public abstract class RestController<T> { private static final String LOG_TAG = "RestController"; private static final boolean DBG = BuildConfig.DEBUG; /** * Timeout en millisecondes */ private static int TIMEOUT = 15000; /** * Début de la plage de code d'erreur de HTTP */ private static int HTTP_ERROR_CODE_START = 400; private final String[] mRootNodes; public RestController(final String... rootNode) { mRootNodes = rootNode; } /** * Parser une chaîne Json. * * @param source * La chaîne Json * @return L'objet correspondant */ public T parseJsonObject(final String source) { T result = null; try { result = parseJsonObject(new JSONObject(source)); } catch (final JSONException e) { Log.e(getClass().getSimpleName(), e.getMessage()); } return result; } /** * Parser une chaîne Json. * * @param source * La chaîne Json * @return L'objet correspondant */ public List<T> parseJsonArray(final String source) throws JSONException { List<T> result = null; final JSONTokener tokener = new JSONTokener(source); final Object object = tokener.nextValue(); if (object instanceof JSONArray) { result = parseJsonArray(new JSONArray(source)); } else if (object instanceof JSONObject) { result = parseJsonArray(new JSONObject(source)); } else { throw new JSONException("L'élément n'est pas flux JSON valide."); } return result; } /** * Parser la réponse d'un webservice Rest json et récupérer une instance du * type passé en paramètre * * @param url * @return * @throws IOException */ protected T parseJsonObject(final URL url) throws IOException { return parseJsonObject(readJsonFromUrl(url)); } /** * Parser la réponse d'un webservice Rest json et récupérer une instance du * type passé en paramètre * * @param url * @return * @throws IOException */ protected List<T> parseJson(final URL url) throws IOException, JSONException { return parseJsonArray(readJsonFromUrl(url)); } /** * Lire un flux Json. * * @param url * L'url * @return Le fulx Json au format string * @throws IOException */ protected String readJsonFromUrl(final URL url) throws IOException { if (DBG) Log.d(LOG_TAG, "readJsonFromUrl " + url.toString()); final URLConnection conn = url.openConnection(); conn.setConnectTimeout(TIMEOUT); conn.setReadTimeout(TIMEOUT); conn.setRequestProperty("Accept-Language", Locale.getDefault().getLanguage()); final InputStreamReader comReader = new InputStreamReader(conn.getInputStream()); final String source = IOUtils.toString(comReader); IOUtils.closeQuietly(comReader); return source; } protected JSONArray getRootNode(final JSONObject json) throws JSONException { JSONObject object = json; for (final String node : mRootNodes) { if (object.get(node) instanceof JSONObject) object = object.getJSONObject(node); } return object.getJSONArray(mRootNodes[mRootNodes.length - 1]); } protected List<T> parseJsonArray(final JSONObject json) throws JSONException { final JSONArray jsonArray = getRootNode(json); return parseJsonArray(jsonArray); } protected List<T> parseJsonArray(final JSONArray jsonArray) throws JSONException { final List<T> result = new ArrayList<T>(); JSONObject c; for (int i = 0; i < jsonArray.length(); i++) { c = jsonArray.getJSONObject(i); result.add(parseJsonObject(c)); } return result; } public String toJson(final List<T> items) { final JSONArray list = new JSONArray(); JSONObject object; for (final T item : items) { try { object = toJsonObject(item); list.put(object); } catch (final JSONException e) { if (DBG) Log.e(getClass().getSimpleName(), e.getMessage()); } } return list.toString(); } public String toJson(final T item) { JSONObject object = new JSONObject(); try { object = toJsonObject(item); } catch (final JSONException e) { if (DBG) Log.e(getClass().getSimpleName(), e.getMessage()); } return object.toString(); } /** * Parser un object JsonElement.F * * @param object * L'objet à parser * @return L'objet reconstruit */ protected abstract T parseJsonObject(JSONObject object) throws JSONException; /** * Convertir un élément en élément json. * * @param item * L'élément à convertir * @return L'object Json */ protected abstract JSONObject toJsonObject(T item) throws JSONException; /** * @see RestController#post(URL) */ protected String post(final UrlBuilder url) throws IOException, HttpException { return post(url.getUrl()); } /** * Soumettre le formulaire au webservice * * @param url * @return * @throws IOException * @throws HttpException */ protected String post(final URL url) throws IOException, HttpException { final HttpParams httpParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT); HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT); final HttpClient httpClient = new DefaultHttpClient(httpParams); final HttpPost httppost = new HttpPost(url.toString()); final HttpResponse response = httpClient.execute(httppost); if (response.getStatusLine().getStatusCode() >= HTTP_ERROR_CODE_START) { throw new HttpException(response.getStatusLine().toString()); } final HttpEntity entity = response.getEntity(); return readResponse(entity); } /** * Lire la réponse du WebService * * @param entity * @return * @throws IllegalStateException * @throws IOException */ private String readResponse(final HttpEntity entity) throws IllegalStateException, IOException { final StringBuilder builder = new StringBuilder(); String line; if (entity != null) { final BufferedReader buffer = new BufferedReader(new InputStreamReader(entity.getContent())); while ((line = buffer.readLine()) != null) { builder.append(line); } buffer.close(); } return builder.toString(); } }