Java tutorial
/** * * This is OpenTraining, an Android application for planning your your fitness training. * Copyright (C) 2012-2014 Christian Skubich * * This program 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. * * This program 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 de.skubware.opentraining.activity.settings.sync; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.util.Log; import android.util.SparseArray; import de.skubware.opentraining.basic.ExerciseType; import de.skubware.opentraining.basic.ExerciseType.ExerciseSource; import de.skubware.opentraining.basic.License.LicenseType; import de.skubware.opentraining.basic.Muscle; import de.skubware.opentraining.basic.SportsEquipment; import de.skubware.opentraining.db.IDataProvider; /** * A class for parsing the JSON-data from wger. * */ public class WgerJSONParser { private List<ExerciseType> mNewExerciseList = new ArrayList<ExerciseType>(); /* The exercise builder objects, for modifying the exercises after parsing (e.g. changing image) */ private List<ExerciseType.Builder> mNewExerciseBuilderList = new ArrayList<ExerciseType.Builder>(); //TODO Find better solution, remove static methods and fields private static IDataProvider mDataProvider; /** Tag for logging */ private static final String TAG = "WgerJSONParser"; /** * Constructor. Will start download immediately. * * @param exerciseJSONString * The exercises as JSON-String * @param languageJSONString * The languages as JSON-String * @param muscleJSONString * The muscles as JSON-String * @param dataProvider * @throws JSONException */ public WgerJSONParser(String exerciseJSONString, String languageJSONString, String muscleJSONString, String equipmentJSONString, String licenseJSONString, IDataProvider dataProvider) throws JSONException { mDataProvider = dataProvider; // parse languages SparseArray<Locale> localeSparseArray = parseLanguages(languageJSONString); // parse muscles SparseArray<Muscle> muscleSparseArray = parseMuscles(muscleJSONString); // parse licenses SparseArray<LicenseType> licenseSparseArray = parseLicenses(licenseJSONString); // parse equipment (not required until REST-API supports this) // SparseArray<SportsEquipment> equipmentSparseArray = parseEquipment(equipmentJSONString); JSONObject mainObject = new JSONObject(exerciseJSONString); Log.d(TAG, mainObject.toString()); JSONArray exerciseArray = mainObject.getJSONArray("objects"); // parse each exercise of the JSON Array for (int i = 0; i < exerciseArray.length(); i++) { JSONObject jsonExercise = exerciseArray.getJSONObject(i); // get name and check if exercise already exists String name = jsonExercise.getString("name"); if (dataProvider.exerciseExists(name)) continue; ExerciseType.Builder builder = new ExerciseType.Builder(name, ExerciseSource.SYNCED); // category (unused) // String category = jsonExercise.getString("category"); // comments (unused) // JSONArray commentArray = jsonExercise.getJSONArray("comments"); // for (int k = 0; k < commentArray.length(); k++) { // String comment = commentArray.getString(k); //} // description String description = jsonExercise.getString("description"); builder.description(description); // id (unused) //String id = jsonExercise.getString("id"); // language // the json-language String might look like this: // '/api/v1/language/1/' // only the number at the end is required String language = jsonExercise.getString("language"); int languageNumber = getLastNumberOfJson(language); Map<Locale, String> translationMap = new HashMap<Locale, String>(); translationMap.put(localeSparseArray.get(languageNumber), name); builder.translationMap(translationMap); // resource_uri (unused) //String resource_uri = jsonExercise.getString("resource_uri"); // muscles SortedSet<Muscle> muscleSet = new TreeSet<Muscle>(); JSONArray muscleArray = jsonExercise.getJSONArray("muscles"); for (int l = 0; l < muscleArray.length(); l++) { String muscleString = muscleArray.getString(l); Muscle muscle = muscleSparseArray.get(getLastNumberOfJson(muscleString)); muscleSet.add(muscle); } builder.activatedMuscles(muscleSet); // licenses // the json-language String might look like this: // '/api/v1/license/1/' // only the number at the end is required if (jsonExercise.has("license")) { int licenseNumber = getLastNumberOfJson(jsonExercise.getString("license")); LicenseType licenseType = licenseSparseArray.get(licenseNumber); String license_author = jsonExercise.getString("license_author"); Log.v(TAG, "license=" + licenseType + " license_author=" + license_author); } // equipment // not yet supported by REST-API /*SortedSet<SportsEquipment> equipmentSet = new TreeSet<SportsEquipment>(); JSONArray equipmentArray = jsonExercise.getJSONArray("equipment"); for (int l = 0; l < equipmentArray.length(); l++) { String equipmentString = equipmentArray.getString(l); SportsEquipment equipment = equipmentSparseArray.get(getLastNumberOfJson(equipmentString)); equipmentSet.add(equipment); }*/ builder.activatedMuscles(muscleSet); // images List<File> imageList = new ArrayList<File>(); JSONArray imageArray = jsonExercise.getJSONArray("images"); for (int l = 0; l < imageArray.length(); l++) { String imageString = imageArray.getString(l); imageList.add(new File(imageString)); } builder.imagePath(imageList); mNewExerciseList.add(builder.build()); mNewExerciseBuilderList.add(builder); } } /** * Returns the last number of a JSON-String. * * E.g.: for '/api/v1/something/1/' '1' will be returned. * * @param jsonString * * @return the last number of a JSON-String */ public static int getLastNumberOfJson(String jsonString) { String[] split = jsonString.split("/"); return Integer.parseInt(split[split.length - 1]); } /** * Parses the JSON-language(locale)-String and returns an SparseArray that maps the * language numbers to {@link Locale} objects */ private SparseArray<Locale> parseLanguages(String languagesJSONString) throws JSONException { return parse(languagesJSONString, Locale.class); } /** * Parses the JSON-muscle-String and returns an SparseArray that maps the * muscle numbers to {@link Muscle} objects * * Example for muscle JSON: * * {"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, * "total_count": 15}, "objects": [{"id": 2, "is_front": true, "name": * "Anterior deltoid", "resource_uri": "/api/v1/muscle/2/"}]} * */ private SparseArray<Muscle> parseMuscles(String musclesJSONString) throws JSONException { return parse(musclesJSONString, Muscle.class); } public static SparseArray<LicenseType> parseLicenses(String licenseJSONString) throws JSONException { return parse(licenseJSONString, LicenseType.class); } private SparseArray<SportsEquipment> parseEquipment(String equipmentJSONString) throws JSONException { return parse(equipmentJSONString, SportsEquipment.class); } /** * A generic parsing method for parsing JSON to SportsEquipment, Muscle or Locale. */ private static <T> SparseArray<T> parse(String jsonString, Class<T> c) throws JSONException { JSONObject mainObject = new JSONObject(jsonString); Log.d(TAG, "jsonString: " + mainObject.toString()); JSONArray mainArray = mainObject.getJSONArray("objects"); SparseArray<T> sparseArray = new SparseArray<T>(); // parse each exercise of the JSON Array for (int i = 0; i < mainArray.length(); i++) { JSONObject singleObject = mainArray.getJSONObject(i); Integer id = singleObject.getInt("id"); Object parsedObject; if (c.equals(Muscle.class)) { // handle Muscles String name = singleObject.getString("name"); parsedObject = mDataProvider.getMuscleByName(name); if (parsedObject == null) Log.e(TAG, "Could not find Muscle: " + name); } else if (c.equals(SportsEquipment.class)) { // handle SportsEquipment String name = singleObject.getString("name"); parsedObject = mDataProvider.getEquipmentByName(name); if (parsedObject == null) Log.e(TAG, "Could not find SportsEquipment: " + name); } else if (c.equals(Locale.class)) { // handle Locales String short_name = singleObject.getString("short_name"); parsedObject = new Locale(short_name); if (short_name == null || short_name.equals("")) Log.e(TAG, "Error, no short_name=" + short_name); } else if (c.equals(LicenseType.class)) { // handle licenses String short_name = singleObject.getString("short_name"); parsedObject = mDataProvider.getLicenseTypeByName(short_name); if (short_name == null || short_name.equals("")) Log.e(TAG, "Error, no short_name=" + short_name); } else { throw new IllegalStateException( "parse(String, Class<T>) cannot be applied for class: " + c.toString()); } sparseArray.put(id, (T) parsedObject); } return sparseArray; } /** * Returns the list with the new exercises. * * * @return A list containing all new exercises. */ public ArrayList<ExerciseType> getNewExercises() { return new ArrayList<ExerciseType>(mNewExerciseList); } /** * Returns the list with the builder objects for the new exercises * * * @return A list containing all builder objects for the new exercises */ public ArrayList<ExerciseType.Builder> getNewExercisesBuilder() { return new ArrayList<ExerciseType.Builder>(mNewExerciseBuilderList); } }