package de.geeksfactory.opacclient.webservice; import com.squareup.moshi.FromJson; import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.JsonReader; import com.squareup.moshi.JsonWriter; import com.squareup.moshi.Moshi; import com.squareup.moshi.ToJson; import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Iterator; import java.util.Set; import de.geeksfactory.opacclient.objects.Library; import de.geeksfactory.opacclient.utils.DebugTools; import okhttp3.OkHttpClient; import retrofit2.Retrofit; import retrofit2.converter.moshi.MoshiConverterFactory; public class WebServiceManager { private static final String BASE_URL = "https://info.opacapp.net"; private static WebService service; public static WebService getInstance() { if (service == null) { Moshi moshi = new Moshi.Builder() .add(new JSONAdapterFactory()) .add(new DateTimeAdapter()) .add(new LibraryAdapter()) .build(); Retrofit retrofit = new Retrofit.Builder() .client(DebugTools.prepareHttpClient(new OkHttpClient.Builder()).build()) .baseUrl(BASE_URL) .addConverterFactory(MoshiConverterFactory.create(moshi)) .build(); service = retrofit.create(WebService.class); } return service; } private static class LibraryAdapter { @FromJson public Library fromJson(JsonReader reader) throws IOException { JSONObject json = new JSONObjectAdapter().fromJson(reader); try { return Library.fromJSON(json.getString("_id"), json); } catch (JSONException e) { e.printStackTrace(); return null; } } @ToJson public void toJson(JsonWriter writer, Library value) throws IOException { try { JSONObject json = value.toJSON(); json.put("_id", value.getIdent()); new JSONObjectAdapter().toJson(writer, json); } catch (JSONException e) { throw new IOException(e); } } } private static class JSONObjectAdapter extends JsonAdapter<JSONObject> { @Override public JSONObject fromJson(JsonReader reader) throws IOException { try { JSONObject object = new JSONObject(); reader.beginObject(); while (reader.hasNext()) { String name = reader.nextName(); JsonReader.Token token = reader.peek(); if (token == JsonReader.Token.NULL) { reader.nextNull(); object.put(name, null); } else if (token == JsonReader.Token.BEGIN_ARRAY) { object.put(name, new JSONArrayAdapter().fromJson(reader)); } else if (token == JsonReader.Token.BEGIN_OBJECT) { object.put(name, new JSONObjectAdapter().fromJson(reader)); } else if (token == JsonReader.Token.BOOLEAN) { object.put(name, reader.nextBoolean()); } else if (token == JsonReader.Token.STRING) { object.put(name, reader.nextString()); } else if (token == JsonReader.Token.NUMBER) { object.put(name, reader.nextDouble()); } } reader.endObject(); return object; } catch (JSONException e) { throw new IOException(e); } } @Override public void toJson(JsonWriter writer, JSONObject value) throws IOException { try { writer.beginObject(); Iterator<String> iterator = value.keys(); while (iterator.hasNext()) { String name = iterator.next(); writer.name(name); Object val = value.get(name); if (val == null) { writer.nullValue(); } if (val instanceof JSONArray) { new JSONArrayAdapter().toJson(writer, (JSONArray) val); } else if (val instanceof JSONObject) { new JSONObjectAdapter().toJson(writer, (JSONObject) val); } else if (val instanceof Boolean) { writer.value((Boolean) val); } else if (val instanceof String) { writer.value((String) val); } else if (val instanceof Number) { writer.value((Number) val); } } writer.endObject(); } catch (JSONException e) { throw new IOException(e); } } } private static class JSONArrayAdapter extends JsonAdapter<JSONArray> { @Override public JSONArray fromJson(JsonReader reader) throws IOException { try { JSONArray array = new JSONArray(); reader.beginArray(); while (reader.hasNext()) { JsonReader.Token token = reader.peek(); if (token == JsonReader.Token.BEGIN_ARRAY) { array.put(new JSONArrayAdapter().fromJson(reader)); } else if (token == JsonReader.Token.BEGIN_OBJECT) { array.put(new JSONObjectAdapter().fromJson(reader)); } else if (token == JsonReader.Token.BOOLEAN) { array.put(reader.nextBoolean()); } else if (token == JsonReader.Token.NULL) { reader.nextNull(); array.put(null); } else if (token == JsonReader.Token.STRING) { array.put(reader.nextString()); } else if (token == JsonReader.Token.NUMBER) { array.put(reader.nextDouble()); } } reader.endArray(); return array; } catch (JSONException e) { throw new IOException(e); } } @Override public void toJson(JsonWriter writer, JSONArray value) throws IOException { try { writer.beginArray(); for (int i = 0; i < value.length(); i++) { Object val = value.get(i); if (val == null) { writer.nullValue(); } if (val instanceof JSONArray) { new JSONArrayAdapter().toJson(writer, (JSONArray) val); } else if (val instanceof JSONObject) { new JSONObjectAdapter().toJson(writer, (JSONObject) val); } else if (val instanceof Boolean) { writer.value((Boolean) val); } else if (val instanceof String) { writer.value((String) val); } else if (val instanceof Number) { writer.value((Number) val); } } writer.endArray(); } catch (JSONException e) { throw new IOException(e); } } } private static class DateTimeAdapter { @ToJson String toJson(DateTime dateTime) { return ISODateTimeFormat.dateTime().print(dateTime); } @FromJson DateTime fromJson(String string) { return ISODateTimeFormat.dateTime().parseDateTime(string); } } private static class JSONAdapterFactory implements JsonAdapter.Factory { @Override public JsonAdapter<?> create(Type type, Set<? extends Annotation> annotations, Moshi moshi) { if (type == JSONObject.class) { return new JSONObjectAdapter(); } else if (type == JSONArray.class) { return new JSONArrayAdapter(); } else { return null; } } } }