Commit f748670d96e0d63028fe8fb7f6b1d53b899ae154
1 parent
c249b9af01
Exists in
master
branch release
Showing 45 changed files with 0 additions and 4701 deletions Inline Diff
- TraceSDK/.classpath
- TraceSDK/.fatjar
- TraceSDK/.project
- TraceSDK/AndroidManifest.xml
- TraceSDK/libs/android-support-v4.jar
- TraceSDK/proguard-project.txt
- TraceSDK/project.properties
- TraceSDK/res/drawable-hdpi/ic_launcher.png
- TraceSDK/res/drawable-mdpi/ic_launcher.png
- TraceSDK/res/drawable-xhdpi/ic_launcher.png
- TraceSDK/res/values-v11/styles.xml
- TraceSDK/res/values-v14/styles.xml
- TraceSDK/res/values/strings.xml
- TraceSDK/res/values/styles.xml
- TraceSDK/src/com/mobithink/tracesdk/Conf.java
- TraceSDK/src/com/mobithink/tracesdk/TraceAgent.java
- TraceSDK/src/com/mobithink/tracesdk/event/Event.java
- TraceSDK/src/com/mobithink/tracesdk/event/EventDBUtil.java
- TraceSDK/src/com/mobithink/tracesdk/json/JSON.java
- TraceSDK/src/com/mobithink/tracesdk/json/JSONArray.java
- TraceSDK/src/com/mobithink/tracesdk/json/JSONException.java
- TraceSDK/src/com/mobithink/tracesdk/json/JSONObject.java
- TraceSDK/src/com/mobithink/tracesdk/json/JSONStringer.java
- TraceSDK/src/com/mobithink/tracesdk/json/JSONTokener.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/AbstractClient.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/DefaultRESTClient.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/EntityReader.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/EntityReaderImplJSON.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/EntityReaderImplString.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/HttpExecutor.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/HttpHeaders.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/IClient.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/MediaType.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/MetadataMap.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/MultivaluedMap.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/RESTClient.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/RequestEntity.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/RequestEntityImplJSON.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/RequestEntityImplString.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/Response.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/ResponseImpl.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/UriBuilder.java
- TraceSDK/src/com/mobithink/tracesdk/rest/client/Utils.java
- TraceSDK/src/com/mobithink/tracesdk/utils/LogUtil.java
- TraceSDK/src/com/mobithink/tracesdk/utils/Util.java
TraceSDK/.classpath
| 1 | <?xml version="1.0" encoding="UTF-8"?> | File was deleted | |
| 2 | <classpath> | ||
| 3 | <classpathentry kind="src" path="src"/> | ||
| 4 | <classpathentry kind="src" path="gen"/> | ||
| 5 | <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> | ||
| 6 | <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> | ||
| 7 | <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/> | ||
| 8 | <classpathentry kind="output" path="bin/classes"/> | ||
| 9 | </classpath> | ||
| 10 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
TraceSDK/.fatjar
| 1 | #Fat Jar Configuration File | File was deleted | |
| 2 | #Wed Sep 03 15:36:15 CST 2014 | ||
| 3 | onejar.license.required=true | ||
| 4 | manifest.classpath= | ||
| 5 | manifest.removesigners=true | ||
| 6 | onejar.checkbox=false | ||
| 7 | jarname=TraceSDK.jar | ||
| 8 | manifest.mergeall=true | ||
| 9 | manifest.mainclass= | ||
| 10 | manifest.file=<createnew> | ||
| 11 | jarname.isextern=false | ||
| 12 | onejar.expand= | ||
| 13 | excludes=<po|TraceSDK>~com/~mobithink/~tracksdk/;<jar|android-support-v4.jar> | ||
| 14 | includes= | ||
| 15 | 1 | #Fat Jar Configuration File |
TraceSDK/.project
| 1 | <?xml version="1.0" encoding="UTF-8"?> | File was deleted | |
| 2 | <projectDescription> | ||
| 3 | <name>TraceSDK</name> | ||
| 4 | <comment></comment> | ||
| 5 | <projects> | ||
| 6 | </projects> | ||
| 7 | <buildSpec> | ||
| 8 | <buildCommand> | ||
| 9 | <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> | ||
| 10 | <arguments> | ||
| 11 | </arguments> | ||
| 12 | </buildCommand> | ||
| 13 | <buildCommand> | ||
| 14 | <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> | ||
| 15 | <arguments> | ||
| 16 | </arguments> | ||
| 17 | </buildCommand> | ||
| 18 | <buildCommand> | ||
| 19 | <name>org.eclipse.jdt.core.javabuilder</name> | ||
| 20 | <arguments> | ||
| 21 | </arguments> | ||
| 22 | </buildCommand> | ||
| 23 | <buildCommand> | ||
| 24 | <name>com.android.ide.eclipse.adt.ApkBuilder</name> | ||
| 25 | <arguments> | ||
| 26 | </arguments> | ||
| 27 | </buildCommand> | ||
| 28 | </buildSpec> | ||
| 29 | <natures> | ||
| 30 | <nature>com.android.ide.eclipse.adt.AndroidNature</nature> | ||
| 31 | <nature>org.eclipse.jdt.core.javanature</nature> | ||
| 32 | </natures> | ||
| 33 | </projectDescription> | ||
| 34 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
TraceSDK/AndroidManifest.xml
| 1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | File was deleted | |
| 2 | package="com.mobithink.tracksdk" | ||
| 3 | android:versionCode="1" | ||
| 4 | android:versionName="1.0" > | ||
| 5 | |||
| 6 | <uses-sdk | ||
| 7 | android:minSdkVersion="8" | ||
| 8 | android:targetSdkVersion="19" /> | ||
| 9 | |||
| 10 | <application | ||
| 11 | android:allowBackup="true" | ||
| 12 | android:icon="@drawable/ic_launcher" | ||
| 13 | android:label="@string/app_name" | ||
| 14 | android:theme="@style/AppTheme" > | ||
| 15 | </application> | ||
| 16 | |||
| 17 | </manifest> | ||
| 18 | 1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
TraceSDK/libs/android-support-v4.jar
No preview for this file type
TraceSDK/proguard-project.txt
| 1 | # To enable ProGuard in your project, edit project.properties | File was deleted | |
| 2 | # to define the proguard.config property as described in that file. | ||
| 3 | # | ||
| 4 | # Add project specific ProGuard rules here. | ||
| 5 | # By default, the flags in this file are appended to flags specified | ||
| 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt | ||
| 7 | # You can edit the include path and order by changing the ProGuard | ||
| 8 | # include property in project.properties. | ||
| 9 | # | ||
| 10 | # For more details, see | ||
| 11 | # http://developer.android.com/guide/developing/tools/proguard.html | ||
| 12 | |||
| 13 | # Add any project specific keep options here: | ||
| 14 | |||
| 15 | # If your project uses WebView with JS, uncomment the following | ||
| 16 | # and specify the fully qualified class name to the JavaScript interface | ||
| 17 | # class: | ||
| 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
| 19 | # public *; | ||
| 20 | #} | ||
| 21 | 1 | # To enable ProGuard in your project, edit project.properties |
TraceSDK/project.properties
| 1 | # This file is automatically generated by Android Tools. | File was deleted | |
| 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! | ||
| 3 | # | ||
| 4 | # This file must be checked in Version Control Systems. | ||
| 5 | # | ||
| 6 | # To customize properties used by the Ant build system edit | ||
| 7 | # "ant.properties", and override values to adapt the script to your | ||
| 8 | # project structure. | ||
| 9 | # | ||
| 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): | ||
| 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt | ||
| 12 | |||
| 13 | # Project target. | ||
| 14 | target=android-19 | ||
| 15 | android.library=true | ||
| 16 | 1 | # This file is automatically generated by Android Tools. |
TraceSDK/res/drawable-hdpi/ic_launcher.png
9.18 KB
TraceSDK/res/drawable-mdpi/ic_launcher.png
5.11 KB
TraceSDK/res/drawable-xhdpi/ic_launcher.png
14 KB
TraceSDK/res/values-v11/styles.xml
| 1 | <resources> | File was deleted | |
| 2 | |||
| 3 | <!-- | ||
| 4 | Base application theme for API 11+. This theme completely replaces | ||
| 5 | AppBaseTheme from res/values/styles.xml on API 11+ devices. | ||
| 6 | --> | ||
| 7 | <style name="AppBaseTheme" parent="android:Theme.Holo.Light"> | ||
| 8 | <!-- API 11 theme customizations can go here. --> | ||
| 9 | </style> | ||
| 10 | |||
| 11 | </resources> | ||
| 12 | 1 | <resources> |
TraceSDK/res/values-v14/styles.xml
| 1 | <resources> | File was deleted | |
| 2 | |||
| 3 | <!-- | ||
| 4 | Base application theme for API 14+. This theme completely replaces | ||
| 5 | AppBaseTheme from BOTH res/values/styles.xml and | ||
| 6 | res/values-v11/styles.xml on API 14+ devices. | ||
| 7 | --> | ||
| 8 | <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar"> | ||
| 9 | <!-- API 14 theme customizations can go here. --> | ||
| 10 | </style> | ||
| 11 | |||
| 12 | </resources> | ||
| 13 | 1 | <resources> |
TraceSDK/res/values/strings.xml
| 1 | <resources> | File was deleted | |
| 2 | |||
| 3 | <string name="app_name">TraceSDK</string> | ||
| 4 | |||
| 5 | </resources> | ||
| 6 | 1 | <resources> |
TraceSDK/res/values/styles.xml
| 1 | <resources> | File was deleted | |
| 2 | |||
| 3 | <!-- | ||
| 4 | Base application theme, dependent on API level. This theme is replaced | ||
| 5 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices. | ||
| 6 | --> | ||
| 7 | <style name="AppBaseTheme" parent="android:Theme.Light"> | ||
| 8 | <!-- | ||
| 9 | Theme customizations available in newer API levels can go in | ||
| 10 | res/values-vXX/styles.xml, while customizations related to | ||
| 11 | backward-compatibility can go here. | ||
| 12 | --> | ||
| 13 | </style> | ||
| 14 | |||
| 15 | <!-- Application theme. --> | ||
| 16 | <style name="AppTheme" parent="AppBaseTheme"> | ||
| 17 | <!-- All customizations that are NOT specific to a particular API-level can go here. --> | ||
| 18 | </style> | ||
| 19 | |||
| 20 | </resources> | ||
| 21 | 1 | <resources> |
TraceSDK/src/com/mobithink/tracesdk/Conf.java
| 1 | package com.mobithink.tracesdk; | File was deleted | |
| 2 | |||
| 3 | public class Conf { | ||
| 4 | |||
| 5 | public final class App { | ||
| 6 | public static final int VERSION = 1; | ||
| 7 | |||
| 8 | public static final String API_SERVER = "http://dt.mtafftracking.com/"; | ||
| 9 | } | ||
| 10 | |||
| 11 | public static class Env { | ||
| 12 | public static boolean LOG_ON = true; | ||
| 13 | } | ||
| 14 | } | ||
| 15 | 1 | package com.mobithink.tracesdk; |
TraceSDK/src/com/mobithink/tracesdk/TraceAgent.java
| 1 | package com.mobithink.tracesdk; | File was deleted | |
| 2 | |||
| 3 | import java.util.List; | ||
| 4 | import java.util.Map; | ||
| 5 | |||
| 6 | import org.apache.http.HttpStatus; | ||
| 7 | |||
| 8 | import android.content.Context; | ||
| 9 | import android.text.TextUtils; | ||
| 10 | import android.util.Log; | ||
| 11 | |||
| 12 | import com.mobithink.tracesdk.event.EventDBUtil; | ||
| 13 | import com.mobithink.tracesdk.event.Event; | ||
| 14 | import com.mobithink.tracesdk.json.JSONArray; | ||
| 15 | import com.mobithink.tracesdk.json.JSONException; | ||
| 16 | import com.mobithink.tracesdk.json.JSONObject; | ||
| 17 | import com.mobithink.tracesdk.rest.client.DefaultRESTClient; | ||
| 18 | import com.mobithink.tracesdk.rest.client.RequestEntityImplJSON; | ||
| 19 | import com.mobithink.tracesdk.rest.client.Response; | ||
| 20 | import com.mobithink.tracesdk.utils.LogUtil; | ||
| 21 | import com.mobithink.tracesdk.utils.Util; | ||
| 22 | |||
| 23 | public class TraceAgent { | ||
| 24 | |||
| 25 | private static final String TAG = "TraceAgent"; | ||
| 26 | |||
| 27 | private static long sessionPauseTime = 0L; | ||
| 28 | |||
| 29 | private static String ofId; | ||
| 30 | |||
| 31 | public static void active(final Context context, final String offerId) { | ||
| 32 | ofId = offerId; | ||
| 33 | new Thread() { | ||
| 34 | |||
| 35 | @Override | ||
| 36 | public void run() { | ||
| 37 | DefaultRESTClient client = DefaultRESTClient.create(); | ||
| 38 | client.path("conversion/").query("os", "android").query("version", android.os.Build.VERSION.RELEASE).query("manufacturer", android.os.Build.MANUFACTURER) | ||
| 39 | .query("model", android.os.Build.MODEL).query("build", android.os.Build.VERSION.INCREMENTAL).query("imei", Util.getIMEI(context)) | ||
| 40 | .query("device_id", Util.getAndroidId(context)).query("mac_addr", Util.getMacAddr(context)).query("sdk_version", Conf.App.VERSION) | ||
| 41 | .query("offer_id", offerId).query("uniq_id", Util.getUniqueId(context)).get(); | ||
| 42 | } | ||
| 43 | }.start(); | ||
| 44 | } | ||
| 45 | |||
| 46 | public static void setLogEnable(boolean enable) { | ||
| 47 | Conf.Env.LOG_ON = enable; | ||
| 48 | } | ||
| 49 | |||
| 50 | public static void onResume(final Context Act) { | ||
| 51 | long now = System.currentTimeMillis(); | ||
| 52 | if (now - sessionPauseTime > 10000) | ||
| 53 | new Thread() { | ||
| 54 | |||
| 55 | @Override | ||
| 56 | public void run() { | ||
| 57 | List<Event> events = null; | ||
| 58 | int retry = 0; | ||
| 59 | do { | ||
| 60 | events = EventDBUtil.getInstance(Act).getEvents(300); | ||
| 61 | if (events == null || events.isEmpty()) | ||
| 62 | break; | ||
| 63 | DefaultRESTClient client = DefaultRESTClient.create(); | ||
| 64 | client.setRequestEntity(new RequestEntityImplJSON()); | ||
| 65 | Response resp = client.path("event/index.php").query("os", "android").query("version", android.os.Build.VERSION.RELEASE) | ||
| 66 | .query("manufacturer", android.os.Build.MANUFACTURER).query("model", android.os.Build.MODEL).query("build", android.os.Build.VERSION.INCREMENTAL) | ||
| 67 | .query("imei", Util.getIMEI(Act)).query("device_id", Util.getAndroidId(Act)).query("mac_addr", Util.getMacAddr(Act)) | ||
| 68 | .query("sdk_version", Conf.App.VERSION).query("offer_id", ofId).query("uniq_id", Util.getUniqueId(Act)).query("event", formatJson(events)).post(); | ||
| 69 | Log.d(TAG, "resp code:" + resp.getHttpStatus()); | ||
| 70 | if (resp != null && resp.getHttpStatus() == HttpStatus.SC_OK) { | ||
| 71 | EventDBUtil.getInstance(Act).clearEvent(events); | ||
| 72 | retry = 0; | ||
| 73 | } else | ||
| 74 | retry++; | ||
| 75 | } while (events != null && !events.isEmpty() && retry < 3); | ||
| 76 | } | ||
| 77 | |||
| 78 | }.start(); | ||
| 79 | } | ||
| 80 | |||
| 81 | public static void onPause(Context act) { | ||
| 82 | sessionPauseTime = System.currentTimeMillis(); | ||
| 83 | } | ||
| 84 | |||
| 85 | public static void onEvent(Context context, String eventId) { | ||
| 86 | onEvent(context, eventId, ""); | ||
| 87 | } | ||
| 88 | |||
| 89 | public static void onEvent(Context context, String eventId, String label) { | ||
| 90 | Event event = new Event(eventId, label); | ||
| 91 | EventDBUtil dbUtil = EventDBUtil.getInstance(context.getApplicationContext()); | ||
| 92 | boolean result = dbUtil.saveEvent(event); | ||
| 93 | LogUtil.i(TAG, "record event " + (result ? "success" : "error")); | ||
| 94 | } | ||
| 95 | |||
| 96 | public static void onEvent(Context context, String eventId, Map<String, String> parameters) { | ||
| 97 | if (parameters != null) { | ||
| 98 | Event event = new Event(eventId, ""); | ||
| 99 | for (Map.Entry<String, String> entry : parameters.entrySet()) { | ||
| 100 | // obj.put(entry.getKey(), entry.getValue()); | ||
| 101 | event.addParam(entry.getKey(), entry.getValue()); | ||
| 102 | } | ||
| 103 | EventDBUtil dbUtil = EventDBUtil.getInstance(context.getApplicationContext()); | ||
| 104 | boolean result = dbUtil.saveEvent(event); | ||
| 105 | LogUtil.i(TAG, "record event " + (result ? "success" : "error")); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | private static JSONArray formatJson(List<Event> events) { | ||
| 110 | if (events != null && !events.isEmpty()) { | ||
| 111 | JSONArray array = new JSONArray(); | ||
| 112 | for (Event event : events) { | ||
| 113 | JSONObject item = new JSONObject(); | ||
| 114 | try { | ||
| 115 | item.put("type", event.getEventId()); | ||
| 116 | item.put("time", event.getOccurtime()); | ||
| 117 | item.put("timezone", event.getTimeZone()); | ||
| 118 | JSONObject param = event.getParams(); | ||
| 119 | if (!TextUtils.isEmpty(event.getLabel())) | ||
| 120 | param.put("def", event.getLabel()); | ||
| 121 | item.put("data", param); | ||
| 122 | array.put(item); | ||
| 123 | } catch (JSONException e) { | ||
| 124 | e.printStackTrace(); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | return array; | ||
| 128 | } | ||
| 129 | return new JSONArray(); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | 1 | package com.mobithink.tracesdk; |
TraceSDK/src/com/mobithink/tracesdk/event/Event.java
| 1 | package com.mobithink.tracesdk.event; | File was deleted | |
| 2 | |||
| 3 | import java.util.ArrayList; | ||
| 4 | import java.util.Calendar; | ||
| 5 | import java.util.List; | ||
| 6 | |||
| 7 | import android.content.ContentValues; | ||
| 8 | import android.database.Cursor; | ||
| 9 | import android.provider.BaseColumns; | ||
| 10 | |||
| 11 | import com.mobithink.tracesdk.json.JSONException; | ||
| 12 | import com.mobithink.tracesdk.json.JSONObject; | ||
| 13 | |||
| 14 | public class Event implements BaseColumns { | ||
| 15 | |||
| 16 | public static final String TABLE_NAME = "mt_trace"; | ||
| 17 | |||
| 18 | private long rid; | ||
| 19 | private String eventId; | ||
| 20 | private JSONObject params; | ||
| 21 | private String label = ""; | ||
| 22 | private long occurtime; | ||
| 23 | private String timeZone; | ||
| 24 | private int status; | ||
| 25 | |||
| 26 | private Event() { | ||
| 27 | } | ||
| 28 | |||
| 29 | public Event(String eventId, String label) { | ||
| 30 | this.eventId = eventId; | ||
| 31 | this.label = label; | ||
| 32 | occurtime = System.currentTimeMillis(); | ||
| 33 | timeZone = Calendar.getInstance().getTimeZone().getID(); | ||
| 34 | params = new JSONObject(); | ||
| 35 | } | ||
| 36 | |||
| 37 | public long getRid() { | ||
| 38 | return rid; | ||
| 39 | } | ||
| 40 | |||
| 41 | public void setRid(long rid) { | ||
| 42 | this.rid = rid; | ||
| 43 | } | ||
| 44 | |||
| 45 | public String getEventId() { | ||
| 46 | return eventId; | ||
| 47 | } | ||
| 48 | |||
| 49 | public String getLabel() { | ||
| 50 | return label; | ||
| 51 | } | ||
| 52 | |||
| 53 | public JSONObject getParams() { | ||
| 54 | return params; | ||
| 55 | } | ||
| 56 | |||
| 57 | // public void setParams(JSONObject params) { | ||
| 58 | // this.params = params; | ||
| 59 | // } | ||
| 60 | |||
| 61 | public String getTimeZone() { | ||
| 62 | return timeZone; | ||
| 63 | } | ||
| 64 | |||
| 65 | public long getOccurtime() { | ||
| 66 | return occurtime; | ||
| 67 | } | ||
| 68 | |||
| 69 | public int getStatus() { | ||
| 70 | return status; | ||
| 71 | } | ||
| 72 | |||
| 73 | public void setStatus(int status) { | ||
| 74 | this.status = status; | ||
| 75 | } | ||
| 76 | |||
| 77 | public void addParam(String key, String val) { | ||
| 78 | try { | ||
| 79 | params.put(key, val); | ||
| 80 | } catch (JSONException e) { | ||
| 81 | e.printStackTrace(); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public static String COLUMN_EVENT_ID = "event_id"; | ||
| 86 | public static String COLUMN_LABEL = "label"; | ||
| 87 | public static String COLUMN_PARAMS = "param_map"; | ||
| 88 | public static String COLUMN_OCCURTIME = "occurtime"; | ||
| 89 | public static String COLUMN_TIME_ZONE = "time_zone"; | ||
| 90 | public static String COLUMN_STATUS = "status"; | ||
| 91 | |||
| 92 | public static final String[] COLUMNS = { _ID, COLUMN_EVENT_ID, COLUMN_LABEL, COLUMN_OCCURTIME, COLUMN_PARAMS, COLUMN_TIME_ZONE, COLUMN_STATUS }; | ||
| 93 | |||
| 94 | public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(" + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"// | ||
| 95 | + COLUMN_EVENT_ID + " TEXT,"// | ||
| 96 | + COLUMN_LABEL + " TEXT,"// | ||
| 97 | + COLUMN_OCCURTIME + " INTEGER,"// | ||
| 98 | + COLUMN_TIME_ZONE + " TEXT,"// 时区 | ||
| 99 | + COLUMN_PARAMS + " TEXT,"// | ||
| 100 | + COLUMN_STATUS + " INTEGER"// | ||
| 101 | + ");"; | ||
| 102 | |||
| 103 | public ContentValues toContentValues() { | ||
| 104 | ContentValues values = new ContentValues(); | ||
| 105 | values.put(COLUMN_EVENT_ID, eventId); | ||
| 106 | values.put(COLUMN_LABEL, label); | ||
| 107 | values.put(COLUMN_OCCURTIME, occurtime); | ||
| 108 | values.put(COLUMN_STATUS, status); | ||
| 109 | values.put(COLUMN_TIME_ZONE, timeZone); | ||
| 110 | // if (params != null) | ||
| 111 | values.put(COLUMN_PARAMS, params.toString()); | ||
| 112 | return values; | ||
| 113 | } | ||
| 114 | |||
| 115 | public static List<Event> parseCursor(Cursor cursor) { | ||
| 116 | if (cursor == null) | ||
| 117 | return null; | ||
| 118 | List<Event> ret = new ArrayList<Event>(); | ||
| 119 | while (cursor.moveToNext()) { | ||
| 120 | Event event = new Event(); | ||
| 121 | event.rid = cursor.getLong(cursor.getColumnIndexOrThrow(_ID)); | ||
| 122 | event.eventId = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_EVENT_ID)); | ||
| 123 | event.label = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LABEL)); | ||
| 124 | event.occurtime = cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_OCCURTIME)); | ||
| 125 | event.timeZone = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_TIME_ZONE)); | ||
| 126 | event.status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS)); | ||
| 127 | String paramStr = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PARAMS)); | ||
| 128 | try { | ||
| 129 | event.params = new JSONObject(paramStr); | ||
| 130 | } catch (JSONException e) { | ||
| 131 | e.printStackTrace(); | ||
| 132 | } | ||
| 133 | ret.add(event); | ||
| 134 | } | ||
| 135 | return ret; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | 1 | package com.mobithink.tracesdk.event; |
TraceSDK/src/com/mobithink/tracesdk/event/EventDBUtil.java
| 1 | package com.mobithink.tracesdk.event; | File was deleted | |
| 2 | |||
| 3 | import java.util.List; | ||
| 4 | |||
| 5 | import android.content.Context; | ||
| 6 | import android.database.Cursor; | ||
| 7 | import android.database.sqlite.SQLiteDatabase; | ||
| 8 | import android.database.sqlite.SQLiteOpenHelper; | ||
| 9 | |||
| 10 | public class EventDBUtil { | ||
| 11 | |||
| 12 | private static final int version = 1; | ||
| 13 | |||
| 14 | private static final String DB_NAME = "mt_trace.db"; | ||
| 15 | |||
| 16 | private static EventDBUtil instance = null; | ||
| 17 | |||
| 18 | private DBHelper helper; | ||
| 19 | |||
| 20 | private EventDBUtil(Context context) { | ||
| 21 | helper = new DBHelper(context); | ||
| 22 | } | ||
| 23 | |||
| 24 | public static EventDBUtil getInstance(Context context) { | ||
| 25 | if (instance == null) | ||
| 26 | instance = new EventDBUtil(context); | ||
| 27 | return instance; | ||
| 28 | } | ||
| 29 | |||
| 30 | public boolean saveEvent(Event event) { | ||
| 31 | SQLiteDatabase db = helper.getWritableDatabase(); | ||
| 32 | long rowId = db.insert(Event.TABLE_NAME, null, event.toContentValues()); | ||
| 33 | return rowId != -1; | ||
| 34 | } | ||
| 35 | |||
| 36 | public boolean clearEvent(Event event) { | ||
| 37 | SQLiteDatabase db = helper.getWritableDatabase(); | ||
| 38 | int count = db.delete(Event.TABLE_NAME, Event._ID + "=?", new String[] { event.getRid() + "" }); | ||
| 39 | return count > 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | public void clearEvent(List<Event> events) { | ||
| 43 | SQLiteDatabase db = helper.getWritableDatabase(); | ||
| 44 | for (Event event : events) { | ||
| 45 | try { | ||
| 46 | db.delete(Event.TABLE_NAME, Event._ID + "=?", new String[] { event.getRid() + "" }); | ||
| 47 | } catch (Exception e) { | ||
| 48 | e.printStackTrace(); | ||
| 49 | event.setStatus(-1); | ||
| 50 | db.update(Event.TABLE_NAME, event.toContentValues(), Event._ID + "=" + event.getRid(), null); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | public boolean clearEventAll() { | ||
| 56 | SQLiteDatabase db = helper.getWritableDatabase(); | ||
| 57 | int count = db.delete(Event.TABLE_NAME, null, null); | ||
| 58 | return count > 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | public List<Event> getEvents(int limit) { | ||
| 62 | SQLiteDatabase db = helper.getWritableDatabase(); | ||
| 63 | Cursor cursor = db.query(Event.TABLE_NAME, Event.COLUMNS, Event.COLUMN_STATUS + ">-1", null, null, null, null, limit + ""); | ||
| 64 | List<Event> events = Event.parseCursor(cursor); | ||
| 65 | return events; | ||
| 66 | } | ||
| 67 | |||
| 68 | class DBHelper extends SQLiteOpenHelper { | ||
| 69 | |||
| 70 | public DBHelper(Context context) { | ||
| 71 | super(context, DB_NAME, null, version); | ||
| 72 | } | ||
| 73 | |||
| 74 | @Override | ||
| 75 | public void onCreate(SQLiteDatabase db) { | ||
| 76 | db.execSQL(Event.CREATE_TABLE); | ||
| 77 | } | ||
| 78 | |||
| 79 | @Override | ||
| 80 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { | ||
| 81 | |||
| 82 | } | ||
| 83 | |||
| 84 | } | ||
| 85 | } | ||
| 86 | 1 | package com.mobithink.tracesdk.event; |
TraceSDK/src/com/mobithink/tracesdk/json/JSON.java
| 1 | /* | File was deleted | |
| 2 | * Copyright (C) 2010 The Android Open Source Project | ||
| 3 | * | ||
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | * you may not use this file except in compliance with the License. | ||
| 6 | * You may obtain a copy of the License at | ||
| 7 | * | ||
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | * | ||
| 10 | * Unless required by applicable law or agreed to in writing, software | ||
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | * See the License for the specific language governing permissions and | ||
| 14 | * limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | package com.mobithink.tracesdk.json; | ||
| 18 | |||
| 19 | class JSON { | ||
| 20 | /** | ||
| 21 | * Returns the input if it is a JSON-permissible value; throws otherwise. | ||
| 22 | */ | ||
| 23 | static double checkDouble(double d) throws JSONException { | ||
| 24 | if (Double.isInfinite(d) || Double.isNaN(d)) { | ||
| 25 | throw new JSONException("Forbidden numeric value: " + d); | ||
| 26 | } | ||
| 27 | return d; | ||
| 28 | } | ||
| 29 | |||
| 30 | static Boolean toBoolean(Object value) { | ||
| 31 | if (value instanceof Boolean) { | ||
| 32 | return (Boolean) value; | ||
| 33 | } else if (value instanceof String) { | ||
| 34 | String stringValue = (String) value; | ||
| 35 | if ("true".equalsIgnoreCase(stringValue)) { | ||
| 36 | return true; | ||
| 37 | } else if ("false".equalsIgnoreCase(stringValue)) { | ||
| 38 | return false; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | return null; | ||
| 42 | } | ||
| 43 | |||
| 44 | static Double toDouble(Object value) { | ||
| 45 | if (value instanceof Double) { | ||
| 46 | return (Double) value; | ||
| 47 | } else if (value instanceof Number) { | ||
| 48 | return ((Number) value).doubleValue(); | ||
| 49 | } else if (value instanceof String) { | ||
| 50 | try { | ||
| 51 | return Double.valueOf((String) value); | ||
| 52 | } catch (NumberFormatException ignored) { | ||
| 53 | } | ||
| 54 | } | ||
| 55 | return null; | ||
| 56 | } | ||
| 57 | |||
| 58 | static Integer toInteger(Object value) { | ||
| 59 | if (value instanceof Integer) { | ||
| 60 | return (Integer) value; | ||
| 61 | } else if (value instanceof Number) { | ||
| 62 | return ((Number) value).intValue(); | ||
| 63 | } else if (value instanceof String) { | ||
| 64 | try { | ||
| 65 | return (int) Double.parseDouble((String) value); | ||
| 66 | } catch (NumberFormatException ignored) { | ||
| 67 | } | ||
| 68 | } | ||
| 69 | return null; | ||
| 70 | } | ||
| 71 | |||
| 72 | static Long toLong(Object value) { | ||
| 73 | if (value instanceof Long) { | ||
| 74 | return (Long) value; | ||
| 75 | } else if (value instanceof Number) { | ||
| 76 | return ((Number) value).longValue(); | ||
| 77 | } else if (value instanceof String) { | ||
| 78 | try { | ||
| 79 | return (long) Double.parseDouble((String) value); | ||
| 80 | } catch (NumberFormatException ignored) { | ||
| 81 | } | ||
| 82 | } | ||
| 83 | return null; | ||
| 84 | } | ||
| 85 | |||
| 86 | static String toString(Object value) { | ||
| 87 | if (value instanceof String) { | ||
| 88 | return (String) value; | ||
| 89 | } else if (value != null) { | ||
| 90 | return String.valueOf(value); | ||
| 91 | } | ||
| 92 | return null; | ||
| 93 | } | ||
| 94 | |||
| 95 | public static JSONException typeMismatch(Object indexOrName, Object actual, | ||
| 96 | String requiredType) throws JSONException { | ||
| 97 | if (actual == null) { | ||
| 98 | throw new JSONException("Value at " + indexOrName + " is null."); | ||
| 99 | } else { | ||
| 100 | throw new JSONException("Value " + actual + " at " + indexOrName | ||
| 101 | + " of type " + actual.getClass().getName() | ||
| 102 | + " cannot be converted to " + requiredType); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | public static JSONException typeMismatch(Object actual, String requiredType) | ||
| 107 | throws JSONException { | ||
| 108 | if (actual == null) { | ||
| 109 | throw new JSONException("Value is null."); | ||
| 110 | } else { | ||
| 111 | throw new JSONException("Value " + actual | ||
| 112 | + " of type " + actual.getClass().getName() | ||
| 113 | + " cannot be converted to " + requiredType); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | 1 | /* |
TraceSDK/src/com/mobithink/tracesdk/json/JSONArray.java
| 1 | /* | File was deleted | |
| 2 | * Copyright (C) 2010 The Android Open Source Project | ||
| 3 | * | ||
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | * you may not use this file except in compliance with the License. | ||
| 6 | * You may obtain a copy of the License at | ||
| 7 | * | ||
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | * | ||
| 10 | * Unless required by applicable law or agreed to in writing, software | ||
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | * See the License for the specific language governing permissions and | ||
| 14 | * limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | package com.mobithink.tracesdk.json; | ||
| 18 | |||
| 19 | import java.util.ArrayList; | ||
| 20 | import java.util.Collection; | ||
| 21 | import java.util.List; | ||
| 22 | |||
| 23 | // Note: this class was written without inspecting the non-free org.json sourcecode. | ||
| 24 | |||
| 25 | /** | ||
| 26 | * A dense indexed sequence of values. Values may be any mix of | ||
| 27 | * {@link JSONObject JSONObjects}, other {@link JSONArray JSONArrays}, Strings, | ||
| 28 | * Booleans, Integers, Longs, Doubles, {@code null} or {@link JSONObject#NULL}. | ||
| 29 | * Values may not be {@link Double#isNaN() NaNs}, {@link Double#isInfinite() | ||
| 30 | * infinities}, or of any type not listed here. | ||
| 31 | * | ||
| 32 | * <p>{@code JSONArray} has the same type coercion behavior and | ||
| 33 | * optional/mandatory accessors as {@link JSONObject}. See that class' | ||
| 34 | * documentation for details. | ||
| 35 | * | ||
| 36 | * <p><strong>Warning:</strong> this class represents null in two incompatible | ||
| 37 | * ways: the standard Java {@code null} reference, and the sentinel value {@link | ||
| 38 | * JSONObject#NULL}. In particular, {@code get} fails if the requested index | ||
| 39 | * holds the null reference, but succeeds if it holds {@code JSONObject.NULL}. | ||
| 40 | * | ||
| 41 | * <p>Instances of this class are not thread safe. Although this class is | ||
| 42 | * nonfinal, it was not designed for inheritance and should not be subclassed. | ||
| 43 | * In particular, self-use by overridable methods is not specified. See | ||
| 44 | * <i>Effective Java</i> Item 17, "Design and Document or inheritance or else | ||
| 45 | * prohibit it" for further information. | ||
| 46 | */ | ||
| 47 | public class JSONArray { | ||
| 48 | |||
| 49 | private final List<Object> values; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Creates a {@code JSONArray} with no values. | ||
| 53 | */ | ||
| 54 | public JSONArray() { | ||
| 55 | values = new ArrayList<Object>(); | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Creates a new {@code JSONArray} by copying all values from the given | ||
| 60 | * collection. | ||
| 61 | * | ||
| 62 | * @param copyFrom a collection whose values are of supported types. | ||
| 63 | * Unsupported values are not permitted and will yield an array in an | ||
| 64 | * inconsistent state. | ||
| 65 | */ | ||
| 66 | /* Accept a raw type for API compatibility */ | ||
| 67 | public JSONArray(Collection copyFrom) { | ||
| 68 | this(); | ||
| 69 | Collection<?> copyFromTyped = (Collection<?>) copyFrom; | ||
| 70 | values.addAll(copyFromTyped); | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Creates a new {@code JSONArray} with values from the next array in the | ||
| 75 | * tokener. | ||
| 76 | * | ||
| 77 | * @param readFrom a tokener whose nextValue() method will yield a | ||
| 78 | * {@code JSONArray}. | ||
| 79 | * @throws JSONException if the parse fails or doesn't yield a | ||
| 80 | * {@code JSONArray}. | ||
| 81 | */ | ||
| 82 | public JSONArray(JSONTokener readFrom) throws JSONException { | ||
| 83 | /* | ||
| 84 | * Getting the parser to populate this could get tricky. Instead, just | ||
| 85 | * parse to temporary JSONArray and then steal the data from that. | ||
| 86 | */ | ||
| 87 | Object object = readFrom.nextValue(); | ||
| 88 | if (object instanceof JSONArray) { | ||
| 89 | values = ((JSONArray) object).values; | ||
| 90 | } else { | ||
| 91 | throw JSON.typeMismatch(object, "JSONArray"); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | /** | ||
| 96 | * Creates a new {@code JSONArray} with values from the JSON string. | ||
| 97 | * | ||
| 98 | * @param json a JSON-encoded string containing an array. | ||
| 99 | * @throws JSONException if the parse fails or doesn't yield a {@code | ||
| 100 | * JSONArray}. | ||
| 101 | */ | ||
| 102 | public JSONArray(String json) throws JSONException { | ||
| 103 | this(new JSONTokener(json)); | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Returns the number of values in this array. | ||
| 108 | */ | ||
| 109 | public int length() { | ||
| 110 | return values.size(); | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Appends {@code value} to the end of this array. | ||
| 115 | * | ||
| 116 | * @return this array. | ||
| 117 | */ | ||
| 118 | public JSONArray put(boolean value) { | ||
| 119 | values.add(value); | ||
| 120 | return this; | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * Appends {@code value} to the end of this array. | ||
| 125 | * | ||
| 126 | * @param value a finite value. May not be {@link Double#isNaN() NaNs} or | ||
| 127 | * {@link Double#isInfinite() infinities}. | ||
| 128 | * @return this array. | ||
| 129 | */ | ||
| 130 | public JSONArray put(double value) throws JSONException { | ||
| 131 | values.add(JSON.checkDouble(value)); | ||
| 132 | return this; | ||
| 133 | } | ||
| 134 | |||
| 135 | /** | ||
| 136 | * Appends {@code value} to the end of this array. | ||
| 137 | * | ||
| 138 | * @return this array. | ||
| 139 | */ | ||
| 140 | public JSONArray put(int value) { | ||
| 141 | values.add(value); | ||
| 142 | return this; | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Appends {@code value} to the end of this array. | ||
| 147 | * | ||
| 148 | * @return this array. | ||
| 149 | */ | ||
| 150 | public JSONArray put(long value) { | ||
| 151 | values.add(value); | ||
| 152 | return this; | ||
| 153 | } | ||
| 154 | |||
| 155 | /** | ||
| 156 | * Appends {@code value} to the end of this array. | ||
| 157 | * | ||
| 158 | * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, | ||
| 159 | * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May | ||
| 160 | * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() | ||
| 161 | * infinities}. Unsupported values are not permitted and will cause the | ||
| 162 | * array to be in an inconsistent state. | ||
| 163 | * @return this array. | ||
| 164 | */ | ||
| 165 | public JSONArray put(Object value) { | ||
| 166 | values.add(value); | ||
| 167 | return this; | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * Sets the value at {@code index} to {@code value}, null padding this array | ||
| 172 | * to the required length if necessary. If a value already exists at {@code | ||
| 173 | * index}, it will be replaced. | ||
| 174 | * | ||
| 175 | * @return this array. | ||
| 176 | */ | ||
| 177 | public JSONArray put(int index, boolean value) throws JSONException { | ||
| 178 | return put(index, (Boolean) value); | ||
| 179 | } | ||
| 180 | |||
| 181 | /** | ||
| 182 | * Sets the value at {@code index} to {@code value}, null padding this array | ||
| 183 | * to the required length if necessary. If a value already exists at {@code | ||
| 184 | * index}, it will be replaced. | ||
| 185 | * | ||
| 186 | * @param value a finite value. May not be {@link Double#isNaN() NaNs} or | ||
| 187 | * {@link Double#isInfinite() infinities}. | ||
| 188 | * @return this array. | ||
| 189 | */ | ||
| 190 | public JSONArray put(int index, double value) throws JSONException { | ||
| 191 | return put(index, (Double) value); | ||
| 192 | } | ||
| 193 | |||
| 194 | /** | ||
| 195 | * Sets the value at {@code index} to {@code value}, null padding this array | ||
| 196 | * to the required length if necessary. If a value already exists at {@code | ||
| 197 | * index}, it will be replaced. | ||
| 198 | * | ||
| 199 | * @return this array. | ||
| 200 | */ | ||
| 201 | public JSONArray put(int index, int value) throws JSONException { | ||
| 202 | return put(index, (Integer) value); | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * Sets the value at {@code index} to {@code value}, null padding this array | ||
| 207 | * to the required length if necessary. If a value already exists at {@code | ||
| 208 | * index}, it will be replaced. | ||
| 209 | * | ||
| 210 | * @return this array. | ||
| 211 | */ | ||
| 212 | public JSONArray put(int index, long value) throws JSONException { | ||
| 213 | return put(index, (Long) value); | ||
| 214 | } | ||
| 215 | |||
| 216 | /** | ||
| 217 | * Sets the value at {@code index} to {@code value}, null padding this array | ||
| 218 | * to the required length if necessary. If a value already exists at {@code | ||
| 219 | * index}, it will be replaced. | ||
| 220 | * | ||
| 221 | * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, | ||
| 222 | * Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May | ||
| 223 | * not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() | ||
| 224 | * infinities}. | ||
| 225 | * @return this array. | ||
| 226 | */ | ||
| 227 | public JSONArray put(int index, Object value) throws JSONException { | ||
| 228 | if (value instanceof Number) { | ||
| 229 | // deviate from the original by checking all Numbers, not just floats & doubles | ||
| 230 | JSON.checkDouble(((Number) value).doubleValue()); | ||
| 231 | } | ||
| 232 | while (values.size() <= index) { | ||
| 233 | values.add(null); | ||
| 234 | } | ||
| 235 | values.set(index, value); | ||
| 236 | return this; | ||
| 237 | } | ||
| 238 | |||
| 239 | /** | ||
| 240 | * Returns true if this array has no value at {@code index}, or if its value | ||
| 241 | * is the {@code null} reference or {@link JSONObject#NULL}. | ||
| 242 | */ | ||
| 243 | public boolean isNull(int index) { | ||
| 244 | Object value = opt(index); | ||
| 245 | return value == null || value == JSONObject.NULL; | ||
| 246 | } | ||
| 247 | |||
| 248 | /** | ||
| 249 | * Returns the value at {@code index}. | ||
| 250 | * | ||
| 251 | * @throws JSONException if this array has no value at {@code index}, or if | ||
| 252 | * that value is the {@code null} reference. This method returns | ||
| 253 | * normally if the value is {@code JSONObject#NULL}. | ||
| 254 | */ | ||
| 255 | public Object get(int index) throws JSONException { | ||
| 256 | try { | ||
| 257 | Object value = values.get(index); | ||
| 258 | if (value == null) { | ||
| 259 | throw new JSONException("Value at " + index + " is null."); | ||
| 260 | } | ||
| 261 | return value; | ||
| 262 | } catch (IndexOutOfBoundsException e) { | ||
| 263 | throw new JSONException("Index " + index + " out of range [0.." + values.size() + ")"); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | /** | ||
| 268 | * Returns the value at {@code index}, or null if the array has no value | ||
| 269 | * at {@code index}. | ||
| 270 | */ | ||
| 271 | public Object opt(int index) { | ||
| 272 | if (index < 0 || index >= values.size()) { | ||
| 273 | return null; | ||
| 274 | } | ||
| 275 | return values.get(index); | ||
| 276 | } | ||
| 277 | |||
| 278 | /** | ||
| 279 | * Returns the value at {@code index} if it exists and is a boolean or can | ||
| 280 | * be coerced to a boolean. | ||
| 281 | * | ||
| 282 | * @throws JSONException if the value at {@code index} doesn't exist or | ||
| 283 | * cannot be coerced to a boolean. | ||
| 284 | */ | ||
| 285 | public boolean getBoolean(int index) throws JSONException { | ||
| 286 | Object object = get(index); | ||
| 287 | Boolean result = JSON.toBoolean(object); | ||
| 288 | if (result == null) { | ||
| 289 | throw JSON.typeMismatch(index, object, "boolean"); | ||
| 290 | } | ||
| 291 | return result; | ||
| 292 | } | ||
| 293 | |||
| 294 | /** | ||
| 295 | * Returns the value at {@code index} if it exists and is a boolean or can | ||
| 296 | * be coerced to a boolean. Returns false otherwise. | ||
| 297 | */ | ||
| 298 | public boolean optBoolean(int index) { | ||
| 299 | return optBoolean(index, false); | ||
| 300 | } | ||
| 301 | |||
| 302 | /** | ||
| 303 | * Returns the value at {@code index} if it exists and is a boolean or can | ||
| 304 | * be coerced to a boolean. Returns {@code fallback} otherwise. | ||
| 305 | */ | ||
| 306 | public boolean optBoolean(int index, boolean fallback) { | ||
| 307 | Object object = opt(index); | ||
| 308 | Boolean result = JSON.toBoolean(object); | ||
| 309 | return result != null ? result : fallback; | ||
| 310 | } | ||
| 311 | |||
| 312 | /** | ||
| 313 | * Returns the value at {@code index} if it exists and is a double or can | ||
| 314 | * be coerced to a double. | ||
| 315 | * | ||
| 316 | * @throws JSONException if the value at {@code index} doesn't exist or | ||
| 317 | * cannot be coerced to a double. | ||
| 318 | */ | ||
| 319 | public double getDouble(int index) throws JSONException { | ||
| 320 | Object object = get(index); | ||
| 321 | Double result = JSON.toDouble(object); | ||
| 322 | if (result == null) { | ||
| 323 | throw JSON.typeMismatch(index, object, "double"); | ||
| 324 | } | ||
| 325 | return result; | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Returns the value at {@code index} if it exists and is a double or can | ||
| 330 | * be coerced to a double. Returns {@code NaN} otherwise. | ||
| 331 | */ | ||
| 332 | public double optDouble(int index) { | ||
| 333 | return optDouble(index, Double.NaN); | ||
| 334 | } | ||
| 335 | |||
| 336 | /** | ||
| 337 | * Returns the value at {@code index} if it exists and is a double or can | ||
| 338 | * be coerced to a double. Returns {@code fallback} otherwise. | ||
| 339 | */ | ||
| 340 | public double optDouble(int index, double fallback) { | ||
| 341 | Object object = opt(index); | ||
| 342 | Double result = JSON.toDouble(object); | ||
| 343 | return result != null ? result : fallback; | ||
| 344 | } | ||
| 345 | |||
| 346 | /** | ||
| 347 | * Returns the value at {@code index} if it exists and is an int or | ||
| 348 | * can be coerced to an int. | ||
| 349 | * | ||
| 350 | * @throws JSONException if the value at {@code index} doesn't exist or | ||
| 351 | * cannot be coerced to a int. | ||
| 352 | */ | ||
| 353 | public int getInt(int index) throws JSONException { | ||
| 354 | Object object = get(index); | ||
| 355 | Integer result = JSON.toInteger(object); | ||
| 356 | if (result == null) { | ||
| 357 | throw JSON.typeMismatch(index, object, "int"); | ||
| 358 | } | ||
| 359 | return result; | ||
| 360 | } | ||
| 361 | |||
| 362 | /** | ||
| 363 | * Returns the value at {@code index} if it exists and is an int or | ||
| 364 | * can be coerced to an int. Returns 0 otherwise. | ||
| 365 | */ | ||
| 366 | public int optInt(int index) { | ||
| 367 | return optInt(index, 0); | ||
| 368 | } | ||
| 369 | |||
| 370 | /** | ||
| 371 | * Returns the value at {@code index} if it exists and is an int or | ||
| 372 | * can be coerced to an int. Returns {@code fallback} otherwise. | ||
| 373 | */ | ||
| 374 | public int optInt(int index, int fallback) { | ||
| 375 | Object object = opt(index); | ||
| 376 | Integer result = JSON.toInteger(object); | ||
| 377 | return result != null ? result : fallback; | ||
| 378 | } | ||
| 379 | |||
| 380 | /** | ||
| 381 | * Returns the value at {@code index} if it exists and is a long or | ||
| 382 | * can be coerced to a long. | ||
| 383 | * | ||
| 384 | * @throws JSONException if the value at {@code index} doesn't exist or | ||
| 385 | * cannot be coerced to a long. | ||
| 386 | */ | ||
| 387 | public long getLong(int index) throws JSONException { | ||
| 388 | Object object = get(index); | ||
| 389 | Long result = JSON.toLong(object); | ||
| 390 | if (result == null) { | ||
| 391 | throw JSON.typeMismatch(index, object, "long"); | ||
| 392 | } | ||
| 393 | return result; | ||
| 394 | } | ||
| 395 | |||
| 396 | /** | ||
| 397 | * Returns the value at {@code index} if it exists and is a long or | ||
| 398 | * can be coerced to a long. Returns 0 otherwise. | ||
| 399 | */ | ||
| 400 | public long optLong(int index) { | ||
| 401 | return optLong(index, 0L); | ||
| 402 | } | ||
| 403 | |||
| 404 | /** | ||
| 405 | * Returns the value at {@code index} if it exists and is a long or | ||
| 406 | * can be coerced to a long. Returns {@code fallback} otherwise. | ||
| 407 | */ | ||
| 408 | public long optLong(int index, long fallback) { | ||
| 409 | Object object = opt(index); | ||
| 410 | Long result = JSON.toLong(object); | ||
| 411 | return result != null ? result : fallback; | ||
| 412 | } | ||
| 413 | |||
| 414 | /** | ||
| 415 | * Returns the value at {@code index} if it exists, coercing it if | ||
| 416 | * necessary. | ||
| 417 | * | ||
| 418 | * @throws JSONException if no such value exists. | ||
| 419 | */ | ||
| 420 | public String getString(int index) throws JSONException { | ||
| 421 | Object object = get(index); | ||
| 422 | String result = JSON.toString(object); | ||
| 423 | if (result == null) { | ||
| 424 | throw JSON.typeMismatch(index, object, "String"); | ||
| 425 | } | ||
| 426 | return result; | ||
| 427 | } | ||
| 428 | |||
| 429 | /** | ||
| 430 | * Returns the value at {@code index} if it exists, coercing it if | ||
| 431 | * necessary. Returns the empty string if no such value exists. | ||
| 432 | */ | ||
| 433 | public String optString(int index) { | ||
| 434 | return optString(index, ""); | ||
| 435 | } | ||
| 436 | |||
| 437 | /** | ||
| 438 | * Returns the value at {@code index} if it exists, coercing it if | ||
| 439 | * necessary. Returns {@code fallback} if no such value exists. | ||
| 440 | */ | ||
| 441 | public String optString(int index, String fallback) { | ||
| 442 | Object object = opt(index); | ||
| 443 | String result = JSON.toString(object); | ||
| 444 | return result != null ? result : fallback; | ||
| 445 | } | ||
| 446 | |||
| 447 | /** | ||
| 448 | * Returns the value at {@code index} if it exists and is a {@code | ||
| 449 | * JSONArray}. | ||
| 450 | * | ||
| 451 | * @throws JSONException if the value doesn't exist or is not a {@code | ||
| 452 | * JSONArray}. | ||
| 453 | */ | ||
| 454 | public JSONArray getJSONArray(int index) throws JSONException { | ||
| 455 | Object object = get(index); | ||
| 456 | if (object instanceof JSONArray) { | ||
| 457 | return (JSONArray) object; | ||
| 458 | } else { | ||
| 459 | throw JSON.typeMismatch(index, object, "JSONArray"); | ||
| 460 | } | ||
| 461 | } | ||
| 462 | |||
| 463 | /** | ||
| 464 | * Returns the value at {@code index} if it exists and is a {@code | ||
| 465 | * JSONArray}. Returns null otherwise. | ||
| 466 | */ | ||
| 467 | public JSONArray optJSONArray(int index) { | ||
| 468 | Object object = opt(index); | ||
| 469 | return object instanceof JSONArray ? (JSONArray) object : null; | ||
| 470 | } | ||
| 471 | |||
| 472 | /** | ||
| 473 | * Returns the value at {@code index} if it exists and is a {@code | ||
| 474 | * JSONObject}. | ||
| 475 | * | ||
| 476 | * @throws JSONException if the value doesn't exist or is not a {@code | ||
| 477 | * JSONObject}. | ||
| 478 | */ | ||
| 479 | public JSONObject getJSONObject(int index) throws JSONException { | ||
| 480 | Object object = get(index); | ||
| 481 | if (object instanceof JSONObject) { | ||
| 482 | return (JSONObject) object; | ||
| 483 | } else { | ||
| 484 | throw JSON.typeMismatch(index, object, "JSONObject"); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | /** | ||
| 489 | * Returns the value at {@code index} if it exists and is a {@code | ||
| 490 | * JSONObject}. Returns null otherwise. | ||
| 491 | */ | ||
| 492 | public JSONObject optJSONObject(int index) { | ||
| 493 | Object object = opt(index); | ||
| 494 | return object instanceof JSONObject ? (JSONObject) object : null; | ||
| 495 | } | ||
| 496 | |||
| 497 | /** | ||
| 498 | * Returns a new object whose values are the values in this array, and whose | ||
| 499 | * names are the values in {@code names}. Names and values are paired up by | ||
| 500 | * index from 0 through to the shorter array's length. Names that are not | ||
| 501 | * strings will be coerced to strings. This method returns null if either | ||
| 502 | * array is empty. | ||
| 503 | */ | ||
| 504 | public JSONObject toJSONObject(JSONArray names) throws JSONException { | ||
| 505 | JSONObject result = new JSONObject(); | ||
| 506 | int length = Math.min(names.length(), values.size()); | ||
| 507 | if (length == 0) { | ||
| 508 | return null; | ||
| 509 | } | ||
| 510 | for (int i = 0; i < length; i++) { | ||
| 511 | String name = JSON.toString(names.opt(i)); | ||
| 512 | result.put(name, opt(i)); | ||
| 513 | } | ||
| 514 | return result; | ||
| 515 | } | ||
| 516 | |||
| 517 | /** | ||
| 518 | * Returns a new string by alternating this array's values with {@code | ||
| 519 | * separator}. This array's string values are quoted and have their special | ||
| 520 | * characters escaped. For example, the array containing the strings '12" | ||
| 521 | * pizza', 'taco' and 'soda' joined on '+' returns this: | ||
| 522 | * <pre>"12\" pizza"+"taco"+"soda"</pre> | ||
| 523 | */ | ||
| 524 | public String join(String separator) throws JSONException { | ||
| 525 | JSONStringer stringer = new JSONStringer(); | ||
| 526 | stringer.open(JSONStringer.Scope.NULL, ""); | ||
| 527 | for (int i = 0, size = values.size(); i < size; i++) { | ||
| 528 | if (i > 0) { | ||
| 529 | stringer.out.append(separator); | ||
| 530 | } | ||
| 531 | stringer.value(values.get(i)); | ||
| 532 | } | ||
| 533 | stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, ""); | ||
| 534 | return stringer.out.toString(); | ||
| 535 | } | ||
| 536 | |||
| 537 | /** | ||
| 538 | * Encodes this array as a compact JSON string, such as: | ||
| 539 | * <pre>[94043,90210]</pre> | ||
| 540 | */ | ||
| 541 | @Override public String toString() { | ||
| 542 | try { | ||
| 543 | JSONStringer stringer = new JSONStringer(); | ||
| 544 | writeTo(stringer); | ||
| 545 | return stringer.toString(); | ||
| 546 | } catch (JSONException e) { | ||
| 547 | return null; | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | /** | ||
| 552 | * Encodes this array as a human readable JSON string for debugging, such | ||
| 553 | * as: | ||
| 554 | * <pre> | ||
| 555 | * [ | ||
| 556 | * 94043, | ||
| 557 | * 90210 | ||
| 558 | * ]</pre> | ||
| 559 | * | ||
| 560 | * @param indentSpaces the number of spaces to indent for each level of | ||
| 561 | * nesting. | ||
| 562 | */ | ||
| 563 | public String toString(int indentSpaces) throws JSONException { | ||
| 564 | JSONStringer stringer = new JSONStringer(indentSpaces); | ||
| 565 | writeTo(stringer); | ||
| 566 | return stringer.toString(); | ||
| 567 | } | ||
| 568 | |||
| 569 | void writeTo(JSONStringer stringer) throws JSONException { | ||
| 570 | stringer.array(); | ||
| 571 | for (Object value : values) { | ||
| 572 | stringer.value(value); | ||
| 573 | } | ||
| 574 | stringer.endArray(); | ||
| 575 | } | ||
| 576 | |||
| 577 | @Override public boolean equals(Object o) { | ||
| 578 | return o instanceof JSONArray && ((JSONArray) o).values.equals(values); | ||
| 579 | } | ||
| 580 | |||
| 581 | @Override public int hashCode() { | ||
| 582 | // diverge from the original, which doesn't implement hashCode | ||
| 583 | return values.hashCode(); | ||
| 584 | } | ||
| 585 | } | ||
| 586 | 1 | /* |
TraceSDK/src/com/mobithink/tracesdk/json/JSONException.java
| 1 | /* | File was deleted | |
| 2 | * Copyright (C) 2010 The Android Open Source Project | ||
| 3 | * | ||
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | * you may not use this file except in compliance with the License. | ||
| 6 | * You may obtain a copy of the License at | ||
| 7 | * | ||
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | * | ||
| 10 | * Unless required by applicable law or agreed to in writing, software | ||
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | * See the License for the specific language governing permissions and | ||
| 14 | * limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | package com.mobithink.tracesdk.json; | ||
| 18 | |||
| 19 | // Note: this class was written without inspecting the non-free org.json sourcecode. | ||
| 20 | |||
| 21 | /** | ||
| 22 | * Thrown to indicate a problem with the JSON API. Such problems include: | ||
| 23 | * <ul> | ||
| 24 | * <li>Attempts to parse or construct malformed documents | ||
| 25 | * <li>Use of null as a name | ||
| 26 | * <li>Use of numeric types not available to JSON, such as {@link | ||
| 27 | * Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. | ||
| 28 | * <li>Lookups using an out of range index or nonexistent name | ||
| 29 | * <li>Type mismatches on lookups | ||
| 30 | * </ul> | ||
| 31 | * | ||
| 32 | * <p>Although this is a checked exception, it is rarely recoverable. Most | ||
| 33 | * callers should simply wrap this exception in an unchecked exception and | ||
| 34 | * rethrow: | ||
| 35 | * <pre> public JSONArray toJSONObject() { | ||
| 36 | * try { | ||
| 37 | * JSONObject result = new JSONObject(); | ||
| 38 | * ... | ||
| 39 | * } catch (JSONException e) { | ||
| 40 | * throw new RuntimeException(e); | ||
| 41 | * } | ||
| 42 | * }</pre> | ||
| 43 | */ | ||
| 44 | public class JSONException extends Exception { | ||
| 45 | |||
| 46 | public JSONException(String s) { | ||
| 47 | super(s); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | 1 | /* |
TraceSDK/src/com/mobithink/tracesdk/json/JSONObject.java
| 1 | /* | File was deleted | |
| 2 | * Copyright (C) 2010 The Android Open Source Project | ||
| 3 | * | ||
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | * you may not use this file except in compliance with the License. | ||
| 6 | * You may obtain a copy of the License at | ||
| 7 | * | ||
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | * | ||
| 10 | * Unless required by applicable law or agreed to in writing, software | ||
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | * See the License for the specific language governing permissions and | ||
| 14 | * limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | package com.mobithink.tracesdk.json; | ||
| 18 | |||
| 19 | import java.util.ArrayList; | ||
| 20 | import java.util.HashMap; | ||
| 21 | import java.util.Iterator; | ||
| 22 | import java.util.Map; | ||
| 23 | |||
| 24 | // Note: this class was written without inspecting the non-free org.json sourcecode. | ||
| 25 | |||
| 26 | /** | ||
| 27 | * A modifiable set of name/value mappings. Names are unique, non-null strings. | ||
| 28 | * Values may be any mix of {@link JSONObject JSONObjects}, {@link JSONArray | ||
| 29 | * JSONArrays}, Strings, Booleans, Integers, Longs, Doubles or {@link #NULL}. | ||
| 30 | * Values may not be {@code null}, {@link Double#isNaN() NaNs}, {@link | ||
| 31 | * Double#isInfinite() infinities}, or of any type not listed here. | ||
| 32 | * | ||
| 33 | * <p>This class can coerce values to another type when requested. | ||
| 34 | * <ul> | ||
| 35 | * <li>When the requested type is a boolean, strings will be coerced using a | ||
| 36 | * case-insensitive comparison to "true" and "false". | ||
| 37 | * <li>When the requested type is a double, other {@link Number} types will | ||
| 38 | * be coerced using {@link Number#doubleValue() doubleValue}. Strings | ||
| 39 | * that can be coerced using {@link Double#valueOf(String)} will be. | ||
| 40 | * <li>When the requested type is an int, other {@link Number} types will | ||
| 41 | * be coerced using {@link Number#intValue() intValue}. Strings | ||
| 42 | * that can be coerced using {@link Double#valueOf(String)} will be, | ||
| 43 | * and then cast to int. | ||
| 44 | * <li>When the requested type is a long, other {@link Number} types will | ||
| 45 | * be coerced using {@link Number#longValue() longValue}. Strings | ||
| 46 | * that can be coerced using {@link Double#valueOf(String)} will be, | ||
| 47 | * and then cast to long. This two-step conversion is lossy for very | ||
| 48 | * large values. For example, the string "9223372036854775806" yields the | ||
| 49 | * long 9223372036854775807. | ||
| 50 | * <li>When the requested type is a String, other non-null values will be | ||
| 51 | * coerced using {@link String#valueOf(Object)}. Although null cannot be | ||
| 52 | * coerced, the sentinel value {@link JSONObject#NULL} is coerced to the | ||
| 53 | * string "null". | ||
| 54 | * </ul> | ||
| 55 | * | ||
| 56 | * <p>This class can look up both mandatory and optional values: | ||
| 57 | * <ul> | ||
| 58 | * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This | ||
| 59 | * fails with a {@code JSONException} if the requested name has no value | ||
| 60 | * or if the value cannot be coerced to the requested type. | ||
| 61 | * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This | ||
| 62 | * returns a system- or user-supplied default if the requested name has no | ||
| 63 | * value or if the value cannot be coerced to the requested type. | ||
| 64 | * </ul> | ||
| 65 | * | ||
| 66 | * <p><strong>Warning:</strong> this class represents null in two incompatible | ||
| 67 | * ways: the standard Java {@code null} reference, and the sentinel value {@link | ||
| 68 | * JSONObject#NULL}. In particular, calling {@code put(name, null)} removes the | ||
| 69 | * named entry from the object but {@code put(name, JSONObject.NULL)} stores an | ||
| 70 | * entry whose value is {@code JSONObject.NULL}. | ||
| 71 | * | ||
| 72 | * <p>Instances of this class are not thread safe. Although this class is | ||
| 73 | * nonfinal, it was not designed for inheritance and should not be subclassed. | ||
| 74 | * In particular, self-use by overrideable methods is not specified. See | ||
| 75 | * <i>Effective Java</i> Item 17, "Design and Document or inheritance or else | ||
| 76 | * prohibit it" for further information. | ||
| 77 | */ | ||
| 78 | public class JSONObject { | ||
| 79 | |||
| 80 | private static final Double NEGATIVE_ZERO = -0d; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * A sentinel value used to explicitly define a name with no value. Unlike | ||
| 84 | * {@code null}, names with this value: | ||
| 85 | * <ul> | ||
| 86 | * <li>show up in the {@link #names} array | ||
| 87 | * <li>show up in the {@link #keys} iterator | ||
| 88 | * <li>return {@code true} for {@link #has(String)} | ||
| 89 | * <li>do not throw on {@link #get(String)} | ||
| 90 | * <li>are included in the encoded JSON string. | ||
| 91 | * </ul> | ||
| 92 | * | ||
| 93 | * <p>This value violates the general contract of {@link Object#equals} by | ||
| 94 | * returning true when compared to {@code null}. Its {@link #toString} | ||
| 95 | * method returns "null". | ||
| 96 | */ | ||
| 97 | public static final Object NULL = new Object() { | ||
| 98 | @Override public boolean equals(Object o) { | ||
| 99 | return o == this || o == null; // API specifies this broken equals implementation | ||
| 100 | } | ||
| 101 | @Override public String toString() { | ||
| 102 | return "null"; | ||
| 103 | } | ||
| 104 | }; | ||
| 105 | |||
| 106 | private final Map<String, Object> nameValuePairs; | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Creates a {@code JSONObject} with no name/value mappings. | ||
| 110 | */ | ||
| 111 | public JSONObject() { | ||
| 112 | nameValuePairs = new HashMap<String, Object>(); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Creates a new {@code JSONObject} by copying all name/value mappings from | ||
| 117 | * the given map. | ||
| 118 | * | ||
| 119 | * @param copyFrom a map whose keys are of type {@link String} and whose | ||
| 120 | * values are of supported types. | ||
| 121 | * @throws NullPointerException if any of the map's keys are null. | ||
| 122 | */ | ||
| 123 | /* (accept a raw type for API compatibility) */ | ||
| 124 | public JSONObject(Map copyFrom) { | ||
| 125 | this(); | ||
| 126 | Map<?, ?> contentsTyped = (Map<?, ?>) copyFrom; | ||
| 127 | for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) { | ||
| 128 | /* | ||
| 129 | * Deviate from the original by checking that keys are non-null and | ||
| 130 | * of the proper type. (We still defer validating the values). | ||
| 131 | */ | ||
| 132 | String key = (String) entry.getKey(); | ||
| 133 | if (key == null) { | ||
| 134 | throw new NullPointerException(); | ||
| 135 | } | ||
| 136 | nameValuePairs.put(key, entry.getValue()); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Creates a new {@code JSONObject} with name/value mappings from the next | ||
| 142 | * object in the tokener. | ||
| 143 | * | ||
| 144 | * @param readFrom a tokener whose nextValue() method will yield a | ||
| 145 | * {@code JSONObject}. | ||
| 146 | * @throws JSONException if the parse fails or doesn't yield a | ||
| 147 | * {@code JSONObject}. | ||
| 148 | */ | ||
| 149 | public JSONObject(JSONTokener readFrom) throws JSONException { | ||
| 150 | /* | ||
| 151 | * Getting the parser to populate this could get tricky. Instead, just | ||
| 152 | * parse to temporary JSONObject and then steal the data from that. | ||
| 153 | */ | ||
| 154 | Object object = readFrom.nextValue(); | ||
| 155 | if (object instanceof JSONObject) { | ||
| 156 | this.nameValuePairs = ((JSONObject) object).nameValuePairs; | ||
| 157 | } else { | ||
| 158 | throw JSON.typeMismatch(object, "JSONObject"); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | /** | ||
| 163 | * Creates a new {@code JSONObject} with name/value mappings from the JSON | ||
| 164 | * string. | ||
| 165 | * | ||
| 166 | * @param json a JSON-encoded string containing an object. | ||
| 167 | * @throws JSONException if the parse fails or doesn't yield a {@code | ||
| 168 | * JSONObject}. | ||
| 169 | */ | ||
| 170 | public JSONObject(String json) throws JSONException { | ||
| 171 | this(new JSONTokener(json)); | ||
| 172 | } | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Creates a new {@code JSONObject} by copying mappings for the listed names | ||
| 176 | * from the given object. Names that aren't present in {@code copyFrom} will | ||
| 177 | * be skipped. | ||
| 178 | */ | ||
| 179 | public JSONObject(JSONObject copyFrom, String[] names) throws JSONException { | ||
| 180 | this(); | ||
| 181 | for (String name : names) { | ||
| 182 | Object value = copyFrom.opt(name); | ||
| 183 | if (value != null) { | ||
| 184 | nameValuePairs.put(name, value); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Returns the number of name/value mappings in this object. | ||
| 191 | */ | ||
| 192 | public int length() { | ||
| 193 | return nameValuePairs.size(); | ||
| 194 | } | ||
| 195 | |||
| 196 | /** | ||
| 197 | * Maps {@code name} to {@code value}, clobbering any existing name/value | ||
| 198 | * mapping with the same name. | ||
| 199 | * | ||
| 200 | * @return this object. | ||
| 201 | */ | ||
| 202 | public JSONObject put(String name, boolean value) throws JSONException { | ||
| 203 | nameValuePairs.put(checkName(name), value); | ||
| 204 | return this; | ||
| 205 | } | ||
| 206 | |||
| 207 | /** | ||
| 208 | * Maps {@code name} to {@code value}, clobbering any existing name/value | ||
| 209 | * mapping with the same name. | ||
| 210 | * | ||
| 211 | * @param value a finite value. May not be {@link Double#isNaN() NaNs} or | ||
| 212 | * {@link Double#isInfinite() infinities}. | ||
| 213 | * @return this object. | ||
| 214 | */ | ||
| 215 | public JSONObject put(String name, double value) throws JSONException { | ||
| 216 | nameValuePairs.put(checkName(name), JSON.checkDouble(value)); | ||
| 217 | return this; | ||
| 218 | } | ||
| 219 | |||
| 220 | /** | ||
| 221 | * Maps {@code name} to {@code value}, clobbering any existing name/value | ||
| 222 | * mapping with the same name. | ||
| 223 | * | ||
| 224 | * @return this object. | ||
| 225 | */ | ||
| 226 | public JSONObject put(String name, int value) throws JSONException { | ||
| 227 | nameValuePairs.put(checkName(name), value); | ||
| 228 | return this; | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Maps {@code name} to {@code value}, clobbering any existing name/value | ||
| 233 | * mapping with the same name. | ||
| 234 | * | ||
| 235 | * @return this object. | ||
| 236 | */ | ||
| 237 | public JSONObject put(String name, long value) throws JSONException { | ||
| 238 | nameValuePairs.put(checkName(name), value); | ||
| 239 | return this; | ||
| 240 | } | ||
| 241 | |||
| 242 | /** | ||
| 243 | * Maps {@code name} to {@code value}, clobbering any existing name/value | ||
| 244 | * mapping with the same name. If the value is {@code null}, any existing | ||
| 245 | * mapping for {@code name} is removed. | ||
| 246 | * | ||
| 247 | * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, | ||
| 248 | * Integer, Long, Double, {@link #NULL}, or {@code null}. May not be | ||
| 249 | * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() | ||
| 250 | * infinities}. | ||
| 251 | * @return this object. | ||
| 252 | */ | ||
| 253 | public JSONObject put(String name, Object value) throws JSONException { | ||
| 254 | if (value == null) { | ||
| 255 | nameValuePairs.remove(name); | ||
| 256 | return this; | ||
| 257 | } | ||
| 258 | if (value instanceof Number) { | ||
| 259 | // deviate from the original by checking all Numbers, not just floats & doubles | ||
| 260 | JSON.checkDouble(((Number) value).doubleValue()); | ||
| 261 | } | ||
| 262 | nameValuePairs.put(checkName(name), value); | ||
| 263 | return this; | ||
| 264 | } | ||
| 265 | |||
| 266 | /** | ||
| 267 | * Equivalent to {@code put(name, value)} when both parameters are non-null; | ||
| 268 | * does nothing otherwise. | ||
| 269 | */ | ||
| 270 | public JSONObject putOpt(String name, Object value) throws JSONException { | ||
| 271 | if (name == null || value == null) { | ||
| 272 | return this; | ||
| 273 | } | ||
| 274 | return put(name, value); | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * Appends {@code value} to the array already mapped to {@code name}. If | ||
| 279 | * this object has no mapping for {@code name}, this inserts a new mapping. | ||
| 280 | * If the mapping exists but its value is not an array, the existing | ||
| 281 | * and new values are inserted in order into a new array which is itself | ||
| 282 | * mapped to {@code name}. In aggregate, this allows values to be added to a | ||
| 283 | * mapping one at a time. | ||
| 284 | * | ||
| 285 | * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, | ||
| 286 | * Integer, Long, Double, {@link #NULL} or null. May not be {@link | ||
| 287 | * Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. | ||
| 288 | */ | ||
| 289 | public JSONObject accumulate(String name, Object value) throws JSONException { | ||
| 290 | Object current = nameValuePairs.get(checkName(name)); | ||
| 291 | if (current == null) { | ||
| 292 | return put(name, value); | ||
| 293 | } | ||
| 294 | |||
| 295 | // check in accumulate, since array.put(Object) doesn't do any checking | ||
| 296 | if (value instanceof Number) { | ||
| 297 | JSON.checkDouble(((Number) value).doubleValue()); | ||
| 298 | } | ||
| 299 | |||
| 300 | if (current instanceof JSONArray) { | ||
| 301 | JSONArray array = (JSONArray) current; | ||
| 302 | array.put(value); | ||
| 303 | } else { | ||
| 304 | JSONArray array = new JSONArray(); | ||
| 305 | array.put(current); | ||
| 306 | array.put(value); | ||
| 307 | nameValuePairs.put(name, array); | ||
| 308 | } | ||
| 309 | return this; | ||
| 310 | } | ||
| 311 | |||
| 312 | String checkName(String name) throws JSONException { | ||
| 313 | if (name == null) { | ||
| 314 | throw new JSONException("Names must be non-null"); | ||
| 315 | } | ||
| 316 | return name; | ||
| 317 | } | ||
| 318 | |||
| 319 | /** | ||
| 320 | * Removes the named mapping if it exists; does nothing otherwise. | ||
| 321 | * | ||
| 322 | * @return the value previously mapped by {@code name}, or null if there was | ||
| 323 | * no such mapping. | ||
| 324 | */ | ||
| 325 | public Object remove(String name) { | ||
| 326 | return nameValuePairs.remove(name); | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * Returns true if this object has no mapping for {@code name} or if it has | ||
| 331 | * a mapping whose value is {@link #NULL}. | ||
| 332 | */ | ||
| 333 | public boolean isNull(String name) { | ||
| 334 | Object value = nameValuePairs.get(name); | ||
| 335 | return value == null || value == NULL; | ||
| 336 | } | ||
| 337 | |||
| 338 | /** | ||
| 339 | * Returns true if this object has a mapping for {@code name}. The mapping | ||
| 340 | * may be {@link #NULL}. | ||
| 341 | */ | ||
| 342 | public boolean has(String name) { | ||
| 343 | return nameValuePairs.containsKey(name); | ||
| 344 | } | ||
| 345 | |||
| 346 | /** | ||
| 347 | * Returns the value mapped by {@code name}. | ||
| 348 | * | ||
| 349 | * @throws JSONException if no such mapping exists. | ||
| 350 | */ | ||
| 351 | public Object get(String name) throws JSONException { | ||
| 352 | Object result = nameValuePairs.get(name); | ||
| 353 | if (result == null) { | ||
| 354 | throw new JSONException("No value for " + name); | ||
| 355 | } | ||
| 356 | return result; | ||
| 357 | } | ||
| 358 | |||
| 359 | /** | ||
| 360 | * Returns the value mapped by {@code name}, or null if no such mapping | ||
| 361 | * exists. | ||
| 362 | */ | ||
| 363 | public Object opt(String name) { | ||
| 364 | return nameValuePairs.get(name); | ||
| 365 | } | ||
| 366 | |||
| 367 | /** | ||
| 368 | * Returns the value mapped by {@code name} if it exists and is a boolean or | ||
| 369 | * can be coerced to a boolean. | ||
| 370 | * | ||
| 371 | * @throws JSONException if the mapping doesn't exist or cannot be coerced | ||
| 372 | * to a boolean. | ||
| 373 | */ | ||
| 374 | public boolean getBoolean(String name) throws JSONException { | ||
| 375 | Object object = get(name); | ||
| 376 | Boolean result = JSON.toBoolean(object); | ||
| 377 | if (result == null) { | ||
| 378 | throw JSON.typeMismatch(name, object, "boolean"); | ||
| 379 | } | ||
| 380 | return result; | ||
| 381 | } | ||
| 382 | |||
| 383 | /** | ||
| 384 | * Returns the value mapped by {@code name} if it exists and is a boolean or | ||
| 385 | * can be coerced to a boolean. Returns false otherwise. | ||
| 386 | */ | ||
| 387 | public boolean optBoolean(String name) { | ||
| 388 | return optBoolean(name, false); | ||
| 389 | } | ||
| 390 | |||
| 391 | /** | ||
| 392 | * Returns the value mapped by {@code name} if it exists and is a boolean or | ||
| 393 | * can be coerced to a boolean. Returns {@code fallback} otherwise. | ||
| 394 | */ | ||
| 395 | public boolean optBoolean(String name, boolean fallback) { | ||
| 396 | Object object = opt(name); | ||
| 397 | Boolean result = JSON.toBoolean(object); | ||
| 398 | return result != null ? result : fallback; | ||
| 399 | } | ||
| 400 | |||
| 401 | /** | ||
| 402 | * Returns the value mapped by {@code name} if it exists and is a double or | ||
| 403 | * can be coerced to a double. | ||
| 404 | * | ||
| 405 | * @throws JSONException if the mapping doesn't exist or cannot be coerced | ||
| 406 | * to a double. | ||
| 407 | */ | ||
| 408 | public double getDouble(String name) throws JSONException { | ||
| 409 | Object object = get(name); | ||
| 410 | Double result = JSON.toDouble(object); | ||
| 411 | if (result == null) { | ||
| 412 | throw JSON.typeMismatch(name, object, "double"); | ||
| 413 | } | ||
| 414 | return result; | ||
| 415 | } | ||
| 416 | |||
| 417 | /** | ||
| 418 | * Returns the value mapped by {@code name} if it exists and is a double or | ||
| 419 | * can be coerced to a double. Returns {@code NaN} otherwise. | ||
| 420 | */ | ||
| 421 | public double optDouble(String name) { | ||
| 422 | return optDouble(name, Double.NaN); | ||
| 423 | } | ||
| 424 | |||
| 425 | /** | ||
| 426 | * Returns the value mapped by {@code name} if it exists and is a double or | ||
| 427 | * can be coerced to a double. Returns {@code fallback} otherwise. | ||
| 428 | */ | ||
| 429 | public double optDouble(String name, double fallback) { | ||
| 430 | Object object = opt(name); | ||
| 431 | Double result = JSON.toDouble(object); | ||
| 432 | return result != null ? result : fallback; | ||
| 433 | } | ||
| 434 | |||
| 435 | /** | ||
| 436 | * Returns the value mapped by {@code name} if it exists and is an int or | ||
| 437 | * can be coerced to an int. | ||
| 438 | * | ||
| 439 | * @throws JSONException if the mapping doesn't exist or cannot be coerced | ||
| 440 | * to an int. | ||
| 441 | */ | ||
| 442 | public int getInt(String name) throws JSONException { | ||
| 443 | Object object = get(name); | ||
| 444 | Integer result = JSON.toInteger(object); | ||
| 445 | if (result == null) { | ||
| 446 | throw JSON.typeMismatch(name, object, "int"); | ||
| 447 | } | ||
| 448 | return result; | ||
| 449 | } | ||
| 450 | |||
| 451 | /** | ||
| 452 | * Returns the value mapped by {@code name} if it exists and is an int or | ||
| 453 | * can be coerced to an int. Returns 0 otherwise. | ||
| 454 | */ | ||
| 455 | public int optInt(String name) { | ||
| 456 | return optInt(name, 0); | ||
| 457 | } | ||
| 458 | |||
| 459 | /** | ||
| 460 | * Returns the value mapped by {@code name} if it exists and is an int or | ||
| 461 | * can be coerced to an int. Returns {@code fallback} otherwise. | ||
| 462 | */ | ||
| 463 | public int optInt(String name, int fallback) { | ||
| 464 | Object object = opt(name); | ||
| 465 | Integer result = JSON.toInteger(object); | ||
| 466 | return result != null ? result : fallback; | ||
| 467 | } | ||
| 468 | |||
| 469 | /** | ||
| 470 | * Returns the value mapped by {@code name} if it exists and is a long or | ||
| 471 | * can be coerced to a long. | ||
| 472 | * | ||
| 473 | * @throws JSONException if the mapping doesn't exist or cannot be coerced | ||
| 474 | * to a long. | ||
| 475 | */ | ||
| 476 | public long getLong(String name) throws JSONException { | ||
| 477 | Object object = get(name); | ||
| 478 | Long result = JSON.toLong(object); | ||
| 479 | if (result == null) { | ||
| 480 | throw JSON.typeMismatch(name, object, "long"); | ||
| 481 | } | ||
| 482 | return result; | ||
| 483 | } | ||
| 484 | |||
| 485 | /** | ||
| 486 | * Returns the value mapped by {@code name} if it exists and is a long or | ||
| 487 | * can be coerced to a long. Returns 0 otherwise. | ||
| 488 | */ | ||
| 489 | public long optLong(String name) { | ||
| 490 | return optLong(name, 0L); | ||
| 491 | } | ||
| 492 | |||
| 493 | /** | ||
| 494 | * Returns the value mapped by {@code name} if it exists and is a long or | ||
| 495 | * can be coerced to a long. Returns {@code fallback} otherwise. | ||
| 496 | */ | ||
| 497 | public long optLong(String name, long fallback) { | ||
| 498 | Object object = opt(name); | ||
| 499 | Long result = JSON.toLong(object); | ||
| 500 | return result != null ? result : fallback; | ||
| 501 | } | ||
| 502 | |||
| 503 | /** | ||
| 504 | * Returns the value mapped by {@code name} if it exists, coercing it if | ||
| 505 | * necessary. | ||
| 506 | * | ||
| 507 | * @throws JSONException if no such mapping exists. | ||
| 508 | */ | ||
| 509 | public String getString(String name) throws JSONException { | ||
| 510 | Object object = get(name); | ||
| 511 | String result = JSON.toString(object); | ||
| 512 | if (result == null) { | ||
| 513 | throw JSON.typeMismatch(name, object, "String"); | ||
| 514 | } | ||
| 515 | return result; | ||
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | * Returns the value mapped by {@code name} if it exists, coercing it if | ||
| 520 | * necessary. Returns the empty string if no such mapping exists. | ||
| 521 | */ | ||
| 522 | public String optString(String name) { | ||
| 523 | return optString(name, ""); | ||
| 524 | } | ||
| 525 | |||
| 526 | /** | ||
| 527 | * Returns the value mapped by {@code name} if it exists, coercing it if | ||
| 528 | * necessary. Returns {@code fallback} if no such mapping exists. | ||
| 529 | */ | ||
| 530 | public String optString(String name, String fallback) { | ||
| 531 | Object object = opt(name); | ||
| 532 | String result = JSON.toString(object); | ||
| 533 | return result != null ? result : fallback; | ||
| 534 | } | ||
| 535 | |||
| 536 | /** | ||
| 537 | * Returns the value mapped by {@code name} if it exists and is a {@code | ||
| 538 | * JSONArray}. | ||
| 539 | * | ||
| 540 | * @throws JSONException if the mapping doesn't exist or is not a {@code | ||
| 541 | * JSONArray}. | ||
| 542 | */ | ||
| 543 | public JSONArray getJSONArray(String name) throws JSONException { | ||
| 544 | Object object = get(name); | ||
| 545 | if (object instanceof JSONArray) { | ||
| 546 | return (JSONArray) object; | ||
| 547 | } else { | ||
| 548 | throw JSON.typeMismatch(name, object, "JSONArray"); | ||
| 549 | } | ||
| 550 | } | ||
| 551 | |||
| 552 | /** | ||
| 553 | * Returns the value mapped by {@code name} if it exists and is a {@code | ||
| 554 | * JSONArray}. Returns null otherwise. | ||
| 555 | */ | ||
| 556 | public JSONArray optJSONArray(String name) { | ||
| 557 | Object object = opt(name); | ||
| 558 | return object instanceof JSONArray ? (JSONArray) object : null; | ||
| 559 | } | ||
| 560 | |||
| 561 | /** | ||
| 562 | * Returns the value mapped by {@code name} if it exists and is a {@code | ||
| 563 | * JSONObject}. | ||
| 564 | * | ||
| 565 | * @throws JSONException if the mapping doesn't exist or is not a {@code | ||
| 566 | * JSONObject}. | ||
| 567 | */ | ||
| 568 | public JSONObject getJSONObject(String name) throws JSONException { | ||
| 569 | Object object = get(name); | ||
| 570 | if (object instanceof JSONObject) { | ||
| 571 | return (JSONObject) object; | ||
| 572 | } else { | ||
| 573 | throw JSON.typeMismatch(name, object, "JSONObject"); | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | /** | ||
| 578 | * Returns the value mapped by {@code name} if it exists and is a {@code | ||
| 579 | * JSONObject}. Returns null otherwise. | ||
| 580 | */ | ||
| 581 | public JSONObject optJSONObject(String name) { | ||
| 582 | Object object = opt(name); | ||
| 583 | return object instanceof JSONObject ? (JSONObject) object : null; | ||
| 584 | } | ||
| 585 | |||
| 586 | /** | ||
| 587 | * Returns an array with the values corresponding to {@code names}. The | ||
| 588 | * array contains null for names that aren't mapped. This method returns | ||
| 589 | * null if {@code names} is either null or empty. | ||
| 590 | */ | ||
| 591 | public JSONArray toJSONArray(JSONArray names) throws JSONException { | ||
| 592 | JSONArray result = new JSONArray(); | ||
| 593 | if (names == null) { | ||
| 594 | return null; | ||
| 595 | } | ||
| 596 | int length = names.length(); | ||
| 597 | if (length == 0) { | ||
| 598 | return null; | ||
| 599 | } | ||
| 600 | for (int i = 0; i < length; i++) { | ||
| 601 | String name = JSON.toString(names.opt(i)); | ||
| 602 | result.put(opt(name)); | ||
| 603 | } | ||
| 604 | return result; | ||
| 605 | } | ||
| 606 | |||
| 607 | /** | ||
| 608 | * Returns an iterator of the {@code String} names in this object. The | ||
| 609 | * returned iterator supports {@link Iterator#remove() remove}, which will | ||
| 610 | * remove the corresponding mapping from this object. If this object is | ||
| 611 | * modified after the iterator is returned, the iterator's behavior is | ||
| 612 | * undefined. The order of the keys is undefined. | ||
| 613 | */ | ||
| 614 | /* Return a raw type for API compatibility */ | ||
| 615 | public Iterator keys() { | ||
| 616 | return nameValuePairs.keySet().iterator(); | ||
| 617 | } | ||
| 618 | |||
| 619 | /** | ||
| 620 | * Returns an array containing the string names in this object. This method | ||
| 621 | * returns null if this object contains no mappings. | ||
| 622 | */ | ||
| 623 | public JSONArray names() { | ||
| 624 | return nameValuePairs.isEmpty() | ||
| 625 | ? null | ||
| 626 | : new JSONArray(new ArrayList<String>(nameValuePairs.keySet())); | ||
| 627 | } | ||
| 628 | |||
| 629 | /** | ||
| 630 | * Encodes this object as a compact JSON string, such as: | ||
| 631 | * <pre>{"query":"Pizza","locations":[94043,90210]}</pre> | ||
| 632 | */ | ||
| 633 | @Override public String toString() { | ||
| 634 | try { | ||
| 635 | JSONStringer stringer = new JSONStringer(); | ||
| 636 | writeTo(stringer); | ||
| 637 | return stringer.toString(); | ||
| 638 | } catch (JSONException e) { | ||
| 639 | return null; | ||
| 640 | } | ||
| 641 | } | ||
| 642 | |||
| 643 | /** | ||
| 644 | * Encodes this object as a human readable JSON string for debugging, such | ||
| 645 | * as: | ||
| 646 | * <pre> | ||
| 647 | * { | ||
| 648 | * "query": "Pizza", | ||
| 649 | * "locations": [ | ||
| 650 | * 94043, | ||
| 651 | * 90210 | ||
| 652 | * ] | ||
| 653 | * }</pre> | ||
| 654 | * | ||
| 655 | * @param indentSpaces the number of spaces to indent for each level of | ||
| 656 | * nesting. | ||
| 657 | */ | ||
| 658 | public String toString(int indentSpaces) throws JSONException { | ||
| 659 | JSONStringer stringer = new JSONStringer(indentSpaces); | ||
| 660 | writeTo(stringer); | ||
| 661 | return stringer.toString(); | ||
| 662 | } | ||
| 663 | |||
| 664 | void writeTo(JSONStringer stringer) throws JSONException { | ||
| 665 | stringer.object(); | ||
| 666 | for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) { | ||
| 667 | stringer.key(entry.getKey()).value(entry.getValue()); | ||
| 668 | } | ||
| 669 | stringer.endObject(); | ||
| 670 | } | ||
| 671 | |||
| 672 | /** | ||
| 673 | * Encodes the number as a JSON string. | ||
| 674 | * | ||
| 675 | * @param number a finite value. May not be {@link Double#isNaN() NaNs} or | ||
| 676 | * {@link Double#isInfinite() infinities}. | ||
| 677 | */ | ||
| 678 | public static String numberToString(Number number) throws JSONException { | ||
| 679 | if (number == null) { | ||
| 680 | throw new JSONException("Number must be non-null"); | ||
| 681 | } | ||
| 682 | |||
| 683 | double doubleValue = number.doubleValue(); | ||
| 684 | JSON.checkDouble(doubleValue); | ||
| 685 | |||
| 686 | // the original returns "-0" instead of "-0.0" for negative zero | ||
| 687 | if (number.equals(NEGATIVE_ZERO)) { | ||
| 688 | return "-0"; | ||
| 689 | } | ||
| 690 | |||
| 691 | long longValue = number.longValue(); | ||
| 692 | if (doubleValue == (double) longValue) { | ||
| 693 | return Long.toString(longValue); | ||
| 694 | } | ||
| 695 | |||
| 696 | return number.toString(); | ||
| 697 | } | ||
| 698 | |||
| 699 | /** | ||
| 700 | * Encodes {@code data} as a JSON string. This applies quotes and any | ||
| 701 | * necessary character escaping. | ||
| 702 | * | ||
| 703 | * @param data the string to encode. Null will be interpreted as an empty | ||
| 704 | * string. | ||
| 705 | */ | ||
| 706 | public static String quote(String data) { | ||
| 707 | if (data == null) { | ||
| 708 | return "\"\""; | ||
| 709 | } | ||
| 710 | try { | ||
| 711 | JSONStringer stringer = new JSONStringer(); | ||
| 712 | stringer.open(JSONStringer.Scope.NULL, ""); | ||
| 713 | stringer.value(data); | ||
| 714 | stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, ""); | ||
| 715 | return stringer.toString(); | ||
| 716 | } catch (JSONException e) { | ||
| 717 | throw new AssertionError(); | ||
| 718 | } | ||
| 719 | } | ||
| 720 | } | ||
| 721 | 1 | /* |
TraceSDK/src/com/mobithink/tracesdk/json/JSONStringer.java
| 1 | /* | File was deleted | |
| 2 | * Copyright (C) 2010 The Android Open Source Project | ||
| 3 | * | ||
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | * you may not use this file except in compliance with the License. | ||
| 6 | * You may obtain a copy of the License at | ||
| 7 | * | ||
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | * | ||
| 10 | * Unless required by applicable law or agreed to in writing, software | ||
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | * See the License for the specific language governing permissions and | ||
| 14 | * limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | package com.mobithink.tracesdk.json; | ||
| 18 | |||
| 19 | import java.util.ArrayList; | ||
| 20 | import java.util.Arrays; | ||
| 21 | import java.util.List; | ||
| 22 | |||
| 23 | // Note: this class was written without inspecting the non-free org.json sourcecode. | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most | ||
| 27 | * application developers should use those methods directly and disregard this | ||
| 28 | * API. For example:<pre> | ||
| 29 | * JSONObject object = ... | ||
| 30 | * String json = object.toString();</pre> | ||
| 31 | * | ||
| 32 | * <p>Stringers only encode well-formed JSON strings. In particular: | ||
| 33 | * <ul> | ||
| 34 | * <li>The stringer must have exactly one top-level array or object. | ||
| 35 | * <li>Lexical scopes must be balanced: every call to {@link #array} must | ||
| 36 | * have a matching call to {@link #endArray} and every call to {@link | ||
| 37 | * #object} must have a matching call to {@link #endObject}. | ||
| 38 | * <li>Arrays may not contain keys (property names). | ||
| 39 | * <li>Objects must alternate keys (property names) and values. | ||
| 40 | * <li>Values are inserted with either literal {@link #value(Object) value} | ||
| 41 | * calls, or by nesting arrays or objects. | ||
| 42 | * </ul> | ||
| 43 | * Calls that would result in a malformed JSON string will fail with a | ||
| 44 | * {@link JSONException}. | ||
| 45 | * | ||
| 46 | * <p>This class provides no facility for pretty-printing (ie. indenting) | ||
| 47 | * output. To encode indented output, use {@link JSONObject#toString(int)} or | ||
| 48 | * {@link JSONArray#toString(int)}. | ||
| 49 | * | ||
| 50 | * <p>Some implementations of the API support at most 20 levels of nesting. | ||
| 51 | * Attempts to create more than 20 levels of nesting may fail with a {@link | ||
| 52 | * JSONException}. | ||
| 53 | * | ||
| 54 | * <p>Each stringer may be used to encode a single top level value. Instances of | ||
| 55 | * this class are not thread safe. Although this class is nonfinal, it was not | ||
| 56 | * designed for inheritance and should not be subclassed. In particular, | ||
| 57 | * self-use by overrideable methods is not specified. See <i>Effective Java</i> | ||
| 58 | * Item 17, "Design and Document or inheritance or else prohibit it" for further | ||
| 59 | * information. | ||
| 60 | */ | ||
| 61 | public class JSONStringer { | ||
| 62 | |||
| 63 | /** The output data, containing at most one top-level array or object. */ | ||
| 64 | final StringBuilder out = new StringBuilder(); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Lexical scoping elements within this stringer, necessary to insert the | ||
| 68 | * appropriate separator characters (ie. commas and colons) and to detect | ||
| 69 | * nesting errors. | ||
| 70 | */ | ||
| 71 | enum Scope { | ||
| 72 | |||
| 73 | /** | ||
| 74 | * An array with no elements requires no separators or newlines before | ||
| 75 | * it is closed. | ||
| 76 | */ | ||
| 77 | EMPTY_ARRAY, | ||
| 78 | |||
| 79 | /** | ||
| 80 | * A array with at least one value requires a comma and newline before | ||
| 81 | * the next element. | ||
| 82 | */ | ||
| 83 | NONEMPTY_ARRAY, | ||
| 84 | |||
| 85 | /** | ||
| 86 | * An object with no keys or values requires no separators or newlines | ||
| 87 | * before it is closed. | ||
| 88 | */ | ||
| 89 | EMPTY_OBJECT, | ||
| 90 | |||
| 91 | /** | ||
| 92 | * An object whose most recent element is a key. The next element must | ||
| 93 | * be a value. | ||
| 94 | */ | ||
| 95 | DANGLING_KEY, | ||
| 96 | |||
| 97 | /** | ||
| 98 | * An object with at least one name/value pair requires a comma and | ||
| 99 | * newline before the next element. | ||
| 100 | */ | ||
| 101 | NONEMPTY_OBJECT, | ||
| 102 | |||
| 103 | /** | ||
| 104 | * A special bracketless array needed by JSONStringer.join() and | ||
| 105 | * JSONObject.quote() only. Not used for JSON encoding. | ||
| 106 | */ | ||
| 107 | NULL, | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Unlike the original implementation, this stack isn't limited to 20 | ||
| 112 | * levels of nesting. | ||
| 113 | */ | ||
| 114 | private final List<Scope> stack = new ArrayList<Scope>(); | ||
| 115 | |||
| 116 | /** | ||
| 117 | * A string containing a full set of spaces for a single level of | ||
| 118 | * indentation, or null for no pretty printing. | ||
| 119 | */ | ||
| 120 | private final String indent; | ||
| 121 | |||
| 122 | public JSONStringer() { | ||
| 123 | indent = null; | ||
| 124 | } | ||
| 125 | |||
| 126 | JSONStringer(int indentSpaces) { | ||
| 127 | char[] indentChars = new char[indentSpaces]; | ||
| 128 | Arrays.fill(indentChars, ' '); | ||
| 129 | indent = new String(indentChars); | ||
| 130 | } | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Begins encoding a new array. Each call to this method must be paired with | ||
| 134 | * a call to {@link #endArray}. | ||
| 135 | * | ||
| 136 | * @return this stringer. | ||
| 137 | */ | ||
| 138 | public JSONStringer array() throws JSONException { | ||
| 139 | return open(Scope.EMPTY_ARRAY, "["); | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * Ends encoding the current array. | ||
| 144 | * | ||
| 145 | * @return this stringer. | ||
| 146 | */ | ||
| 147 | public JSONStringer endArray() throws JSONException { | ||
| 148 | return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]"); | ||
| 149 | } | ||
| 150 | |||
| 151 | /** | ||
| 152 | * Begins encoding a new object. Each call to this method must be paired | ||
| 153 | * with a call to {@link #endObject}. | ||
| 154 | * | ||
| 155 | * @return this stringer. | ||
| 156 | */ | ||
| 157 | public JSONStringer object() throws JSONException { | ||
| 158 | return open(Scope.EMPTY_OBJECT, "{"); | ||
| 159 | } | ||
| 160 | |||
| 161 | /** | ||
| 162 | * Ends encoding the current object. | ||
| 163 | * | ||
| 164 | * @return this stringer. | ||
| 165 | */ | ||
| 166 | public JSONStringer endObject() throws JSONException { | ||
| 167 | return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}"); | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * Enters a new scope by appending any necessary whitespace and the given | ||
| 172 | * bracket. | ||
| 173 | */ | ||
| 174 | JSONStringer open(Scope empty, String openBracket) throws JSONException { | ||
| 175 | if (stack.isEmpty() && out.length() > 0) { | ||
| 176 | throw new JSONException("Nesting problem: multiple top-level roots"); | ||
| 177 | } | ||
| 178 | beforeValue(); | ||
| 179 | stack.add(empty); | ||
| 180 | out.append(openBracket); | ||
| 181 | return this; | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Closes the current scope by appending any necessary whitespace and the | ||
| 186 | * given bracket. | ||
| 187 | */ | ||
| 188 | JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException { | ||
| 189 | Scope context = peek(); | ||
| 190 | if (context != nonempty && context != empty) { | ||
| 191 | throw new JSONException("Nesting problem"); | ||
| 192 | } | ||
| 193 | |||
| 194 | stack.remove(stack.size() - 1); | ||
| 195 | if (context == nonempty) { | ||
| 196 | newline(); | ||
| 197 | } | ||
| 198 | out.append(closeBracket); | ||
| 199 | return this; | ||
| 200 | } | ||
| 201 | |||
| 202 | /** | ||
| 203 | * Returns the value on the top of the stack. | ||
| 204 | */ | ||
| 205 | private Scope peek() throws JSONException { | ||
| 206 | if (stack.isEmpty()) { | ||
| 207 | throw new JSONException("Nesting problem"); | ||
| 208 | } | ||
| 209 | return stack.get(stack.size() - 1); | ||
| 210 | } | ||
| 211 | |||
| 212 | /** | ||
| 213 | * Replace the value on the top of the stack with the given value. | ||
| 214 | */ | ||
| 215 | private void replaceTop(Scope topOfStack) { | ||
| 216 | stack.set(stack.size() - 1, topOfStack); | ||
| 217 | } | ||
| 218 | |||
| 219 | /** | ||
| 220 | * Encodes {@code value}. | ||
| 221 | * | ||
| 222 | * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, | ||
| 223 | * Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs} | ||
| 224 | * or {@link Double#isInfinite() infinities}. | ||
| 225 | * @return this stringer. | ||
| 226 | */ | ||
| 227 | public JSONStringer value(Object value) throws JSONException { | ||
| 228 | if (stack.isEmpty()) { | ||
| 229 | throw new JSONException("Nesting problem"); | ||
| 230 | } | ||
| 231 | |||
| 232 | if (value instanceof JSONArray) { | ||
| 233 | ((JSONArray) value).writeTo(this); | ||
| 234 | return this; | ||
| 235 | |||
| 236 | } else if (value instanceof JSONObject) { | ||
| 237 | ((JSONObject) value).writeTo(this); | ||
| 238 | return this; | ||
| 239 | } | ||
| 240 | |||
| 241 | beforeValue(); | ||
| 242 | |||
| 243 | if (value == null | ||
| 244 | || value instanceof Boolean | ||
| 245 | || value == JSONObject.NULL) { | ||
| 246 | out.append(value); | ||
| 247 | |||
| 248 | } else if (value instanceof Number) { | ||
| 249 | out.append(JSONObject.numberToString((Number) value)); | ||
| 250 | |||
| 251 | } else { | ||
| 252 | string(value.toString()); | ||
| 253 | } | ||
| 254 | |||
| 255 | return this; | ||
| 256 | } | ||
| 257 | |||
| 258 | /** | ||
| 259 | * Encodes {@code value} to this stringer. | ||
| 260 | * | ||
| 261 | * @return this stringer. | ||
| 262 | */ | ||
| 263 | public JSONStringer value(boolean value) throws JSONException { | ||
| 264 | if (stack.isEmpty()) { | ||
| 265 | throw new JSONException("Nesting problem"); | ||
| 266 | } | ||
| 267 | beforeValue(); | ||
| 268 | out.append(value); | ||
| 269 | return this; | ||
| 270 | } | ||
| 271 | |||
| 272 | /** | ||
| 273 | * Encodes {@code value} to this stringer. | ||
| 274 | * | ||
| 275 | * @param value a finite value. May not be {@link Double#isNaN() NaNs} or | ||
| 276 | * {@link Double#isInfinite() infinities}. | ||
| 277 | * @return this stringer. | ||
| 278 | */ | ||
| 279 | public JSONStringer value(double value) throws JSONException { | ||
| 280 | if (stack.isEmpty()) { | ||
| 281 | throw new JSONException("Nesting problem"); | ||
| 282 | } | ||
| 283 | beforeValue(); | ||
| 284 | out.append(JSONObject.numberToString(value)); | ||
| 285 | return this; | ||
| 286 | } | ||
| 287 | |||
| 288 | /** | ||
| 289 | * Encodes {@code value} to this stringer. | ||
| 290 | * | ||
| 291 | * @return this stringer. | ||
| 292 | */ | ||
| 293 | public JSONStringer value(long value) throws JSONException { | ||
| 294 | if (stack.isEmpty()) { | ||
| 295 | throw new JSONException("Nesting problem"); | ||
| 296 | } | ||
| 297 | beforeValue(); | ||
| 298 | out.append(value); | ||
| 299 | return this; | ||
| 300 | } | ||
| 301 | |||
| 302 | private void string(String value) { | ||
| 303 | out.append("\""); | ||
| 304 | for (int i = 0, length = value.length(); i < length; i++) { | ||
| 305 | char c = value.charAt(i); | ||
| 306 | |||
| 307 | /* | ||
| 308 | * From RFC 4627, "All Unicode characters may be placed within the | ||
| 309 | * quotation marks except for the characters that must be escaped: | ||
| 310 | * quotation mark, reverse solidus, and the control characters | ||
| 311 | * (U+0000 through U+001F)." | ||
| 312 | */ | ||
| 313 | switch (c) { | ||
| 314 | case '"': | ||
| 315 | case '\\': | ||
| 316 | case '/': | ||
| 317 | out.append('\\').append(c); | ||
| 318 | break; | ||
| 319 | |||
| 320 | case '\t': | ||
| 321 | out.append("\\t"); | ||
| 322 | break; | ||
| 323 | |||
| 324 | case '\b': | ||
| 325 | out.append("\\b"); | ||
| 326 | break; | ||
| 327 | |||
| 328 | case '\n': | ||
| 329 | out.append("\\n"); | ||
| 330 | break; | ||
| 331 | |||
| 332 | case '\r': | ||
| 333 | out.append("\\r"); | ||
| 334 | break; | ||
| 335 | |||
| 336 | case '\f': | ||
| 337 | out.append("\\f"); | ||
| 338 | break; | ||
| 339 | |||
| 340 | default: | ||
| 341 | if (c <= 0x1F) { | ||
| 342 | out.append(String.format("\\u%04x", (int) c)); | ||
| 343 | } else { | ||
| 344 | out.append(c); | ||
| 345 | } | ||
| 346 | break; | ||
| 347 | } | ||
| 348 | |||
| 349 | } | ||
| 350 | out.append("\""); | ||
| 351 | } | ||
| 352 | |||
| 353 | private void newline() { | ||
| 354 | if (indent == null) { | ||
| 355 | return; | ||
| 356 | } | ||
| 357 | |||
| 358 | out.append("\n"); | ||
| 359 | for (int i = 0; i < stack.size(); i++) { | ||
| 360 | out.append(indent); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | /** | ||
| 365 | * Encodes the key (property name) to this stringer. | ||
| 366 | * | ||
| 367 | * @param name the name of the forthcoming value. May not be null. | ||
| 368 | * @return this stringer. | ||
| 369 | */ | ||
| 370 | public JSONStringer key(String name) throws JSONException { | ||
| 371 | if (name == null) { | ||
| 372 | throw new JSONException("Names must be non-null"); | ||
| 373 | } | ||
| 374 | beforeKey(); | ||
| 375 | string(name); | ||
| 376 | return this; | ||
| 377 | } | ||
| 378 | |||
| 379 | /** | ||
| 380 | * Inserts any necessary separators and whitespace before a name. Also | ||
| 381 | * adjusts the stack to expect the key's value. | ||
| 382 | */ | ||
| 383 | private void beforeKey() throws JSONException { | ||
| 384 | Scope context = peek(); | ||
| 385 | if (context == Scope.NONEMPTY_OBJECT) { // first in object | ||
| 386 | out.append(','); | ||
| 387 | } else if (context != Scope.EMPTY_OBJECT) { // not in an object! | ||
| 388 | throw new JSONException("Nesting problem"); | ||
| 389 | } | ||
| 390 | newline(); | ||
| 391 | replaceTop(Scope.DANGLING_KEY); | ||
| 392 | } | ||
| 393 | |||
| 394 | /** | ||
| 395 | * Inserts any necessary separators and whitespace before a literal value, | ||
| 396 | * inline array, or inline object. Also adjusts the stack to expect either a | ||
| 397 | * closing bracket or another element. | ||
| 398 | */ | ||
| 399 | private void beforeValue() throws JSONException { | ||
| 400 | if (stack.isEmpty()) { | ||
| 401 | return; | ||
| 402 | } | ||
| 403 | |||
| 404 | Scope context = peek(); | ||
| 405 | if (context == Scope.EMPTY_ARRAY) { // first in array | ||
| 406 | replaceTop(Scope.NONEMPTY_ARRAY); | ||
| 407 | newline(); | ||
| 408 | } else if (context == Scope.NONEMPTY_ARRAY) { // another in array | ||
| 409 | out.append(','); | ||
| 410 | newline(); | ||
| 411 | } else if (context == Scope.DANGLING_KEY) { // value for key | ||
| 412 | out.append(indent == null ? ":" : ": "); | ||
| 413 | replaceTop(Scope.NONEMPTY_OBJECT); | ||
| 414 | } else if (context != Scope.NULL) { | ||
| 415 | throw new JSONException("Nesting problem"); | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 419 | /** | ||
| 420 | * Returns the encoded JSON string. | ||
| 421 | * | ||
| 422 | * <p>If invoked with unterminated arrays or unclosed objects, this method's | ||
| 423 | * return value is undefined. | ||
| 424 | * | ||
| 425 | * <p><strong>Warning:</strong> although it contradicts the general contract | ||
| 426 | * of {@link Object#toString}, this method returns null if the stringer | ||
| 427 | * contains no data. | ||
| 428 | */ | ||
| 429 | @Override public String toString() { | ||
| 430 | return out.length() == 0 ? null : out.toString(); | ||
| 431 | } | ||
| 432 | } | ||
| 433 | 1 | /* |
TraceSDK/src/com/mobithink/tracesdk/json/JSONTokener.java
| 1 | /* | File was deleted | |
| 2 | * Copyright (C) 2010 The Android Open Source Project | ||
| 3 | * | ||
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | * you may not use this file except in compliance with the License. | ||
| 6 | * You may obtain a copy of the License at | ||
| 7 | * | ||
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | * | ||
| 10 | * Unless required by applicable law or agreed to in writing, software | ||
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | * See the License for the specific language governing permissions and | ||
| 14 | * limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | package com.mobithink.tracesdk.json; | ||
| 18 | |||
| 19 | // Note: this class was written without inspecting the non-free org.json sourcecode. | ||
| 20 | |||
| 21 | /** | ||
| 22 | * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>) | ||
| 23 | * encoded string into the corresponding object. Most clients of | ||
| 24 | * this class will use only need the {@link #JSONTokener(String) constructor} | ||
| 25 | * and {@link #nextValue} method. Example usage: <pre> | ||
| 26 | * String json = "{" | ||
| 27 | * + " \"query\": \"Pizza\", " | ||
| 28 | * + " \"locations\": [ 94043, 90210 ] " | ||
| 29 | * + "}"; | ||
| 30 | * | ||
| 31 | * JSONObject object = (JSONObject) new JSONTokener(json).nextValue(); | ||
| 32 | * String query = object.getString("query"); | ||
| 33 | * JSONArray locations = object.getJSONArray("locations");</pre> | ||
| 34 | * | ||
| 35 | * <p>For best interoperability and performance use JSON that complies with | ||
| 36 | * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons | ||
| 37 | * this parser is lenient, so a successful parse does not indicate that the | ||
| 38 | * input string was valid JSON. All of the following syntax errors will be | ||
| 39 | * ignored: | ||
| 40 | * <ul> | ||
| 41 | * <li>End of line comments starting with {@code //} or {@code #} and ending | ||
| 42 | * with a newline character. | ||
| 43 | * <li>C-style comments starting with {@code /*} and ending with | ||
| 44 | * {@code *}{@code /}. Such comments may not be nested. | ||
| 45 | * <li>Strings that are unquoted or {@code 'single quoted'}. | ||
| 46 | * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}. | ||
| 47 | * <li>Octal integers prefixed with {@code 0}. | ||
| 48 | * <li>Array elements separated by {@code ;}. | ||
| 49 | * <li>Unnecessary array separators. These are interpreted as if null was the | ||
| 50 | * omitted value. | ||
| 51 | * <li>Key-value pairs separated by {@code =} or {@code =>}. | ||
| 52 | * <li>Key-value pairs separated by {@code ;}. | ||
| 53 | * </ul> | ||
| 54 | * | ||
| 55 | * <p>Each tokener may be used to parse a single JSON string. Instances of this | ||
| 56 | * class are not thread safe. Although this class is nonfinal, it was not | ||
| 57 | * designed for inheritance and should not be subclassed. In particular, | ||
| 58 | * self-use by overrideable methods is not specified. See <i>Effective Java</i> | ||
| 59 | * Item 17, "Design and Document or inheritance or else prohibit it" for further | ||
| 60 | * information. | ||
| 61 | */ | ||
| 62 | public class JSONTokener { | ||
| 63 | |||
| 64 | /** The input JSON. */ | ||
| 65 | private final String in; | ||
| 66 | |||
| 67 | /** | ||
| 68 | * The index of the next character to be returned by {@link #next}. When | ||
| 69 | * the input is exhausted, this equals the input's length. | ||
| 70 | */ | ||
| 71 | private int pos; | ||
| 72 | |||
| 73 | /** | ||
| 74 | * @param in JSON encoded string. Null is not permitted and will yield a | ||
| 75 | * tokener that throws {@code NullPointerExceptions} when methods are | ||
| 76 | * called. | ||
| 77 | */ | ||
| 78 | public JSONTokener(String in) { | ||
| 79 | // consume an optional byte order mark (BOM) if it exists | ||
| 80 | if (in != null && in.startsWith("\ufeff")) { | ||
| 81 | in = in.substring(1); | ||
| 82 | } | ||
| 83 | this.in = in; | ||
| 84 | } | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Returns the next value from the input. | ||
| 88 | * | ||
| 89 | * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, | ||
| 90 | * Integer, Long, Double or {@link JSONObject#NULL}. | ||
| 91 | * @throws JSONException if the input is malformed. | ||
| 92 | */ | ||
| 93 | public Object nextValue() throws JSONException { | ||
| 94 | int c = nextCleanInternal(); | ||
| 95 | switch (c) { | ||
| 96 | case -1: | ||
| 97 | throw syntaxError("End of input"); | ||
| 98 | |||
| 99 | case '{': | ||
| 100 | return readObject(); | ||
| 101 | |||
| 102 | case '[': | ||
| 103 | return readArray(); | ||
| 104 | |||
| 105 | case '\'': | ||
| 106 | case '"': | ||
| 107 | return nextString((char) c); | ||
| 108 | |||
| 109 | default: | ||
| 110 | pos--; | ||
| 111 | return readLiteral(); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | private int nextCleanInternal() throws JSONException { | ||
| 116 | while (pos < in.length()) { | ||
| 117 | int c = in.charAt(pos++); | ||
| 118 | switch (c) { | ||
| 119 | case '\t': | ||
| 120 | case ' ': | ||
| 121 | case '\n': | ||
| 122 | case '\r': | ||
| 123 | continue; | ||
| 124 | |||
| 125 | case '/': | ||
| 126 | if (pos == in.length()) { | ||
| 127 | return c; | ||
| 128 | } | ||
| 129 | |||
| 130 | char peek = in.charAt(pos); | ||
| 131 | switch (peek) { | ||
| 132 | case '*': | ||
| 133 | // skip a /* c-style comment */ | ||
| 134 | pos++; | ||
| 135 | int commentEnd = in.indexOf("*/", pos); | ||
| 136 | if (commentEnd == -1) { | ||
| 137 | throw syntaxError("Unterminated comment"); | ||
| 138 | } | ||
| 139 | pos = commentEnd + 2; | ||
| 140 | continue; | ||
| 141 | |||
| 142 | case '/': | ||
| 143 | // skip a // end-of-line comment | ||
| 144 | pos++; | ||
| 145 | skipToEndOfLine(); | ||
| 146 | continue; | ||
| 147 | |||
| 148 | default: | ||
| 149 | return c; | ||
| 150 | } | ||
| 151 | |||
| 152 | case '#': | ||
| 153 | /* | ||
| 154 | * Skip a # hash end-of-line comment. The JSON RFC doesn't | ||
| 155 | * specify this behavior, but it's required to parse | ||
| 156 | * existing documents. See http://b/2571423. | ||
| 157 | */ | ||
| 158 | skipToEndOfLine(); | ||
| 159 | continue; | ||
| 160 | |||
| 161 | default: | ||
| 162 | return c; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | return -1; | ||
| 167 | } | ||
| 168 | |||
| 169 | /** | ||
| 170 | * Advances the position until after the next newline character. If the line | ||
| 171 | * is terminated by "\r\n", the '\n' must be consumed as whitespace by the | ||
| 172 | * caller. | ||
| 173 | */ | ||
| 174 | private void skipToEndOfLine() { | ||
| 175 | for (; pos < in.length(); pos++) { | ||
| 176 | char c = in.charAt(pos); | ||
| 177 | if (c == '\r' || c == '\n') { | ||
| 178 | pos++; | ||
| 179 | break; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Returns the string up to but not including {@code quote}, unescaping any | ||
| 186 | * character escape sequences encountered along the way. The opening quote | ||
| 187 | * should have already been read. This consumes the closing quote, but does | ||
| 188 | * not include it in the returned string. | ||
| 189 | * | ||
| 190 | * @param quote either ' or ". | ||
| 191 | * @throws NumberFormatException if any unicode escape sequences are | ||
| 192 | * malformed. | ||
| 193 | */ | ||
| 194 | public String nextString(char quote) throws JSONException { | ||
| 195 | /* | ||
| 196 | * For strings that are free of escape sequences, we can just extract | ||
| 197 | * the result as a substring of the input. But if we encounter an escape | ||
| 198 | * sequence, we need to use a StringBuilder to compose the result. | ||
| 199 | */ | ||
| 200 | StringBuilder builder = null; | ||
| 201 | |||
| 202 | /* the index of the first character not yet appended to the builder. */ | ||
| 203 | int start = pos; | ||
| 204 | |||
| 205 | while (pos < in.length()) { | ||
| 206 | int c = in.charAt(pos++); | ||
| 207 | if (c == quote) { | ||
| 208 | if (builder == null) { | ||
| 209 | // a new string avoids leaking memory | ||
| 210 | return new String(in.substring(start, pos - 1)); | ||
| 211 | } else { | ||
| 212 | builder.append(in, start, pos - 1); | ||
| 213 | return builder.toString(); | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | if (c == '\\') { | ||
| 218 | if (pos == in.length()) { | ||
| 219 | throw syntaxError("Unterminated escape sequence"); | ||
| 220 | } | ||
| 221 | if (builder == null) { | ||
| 222 | builder = new StringBuilder(); | ||
| 223 | } | ||
| 224 | builder.append(in, start, pos - 1); | ||
| 225 | builder.append(readEscapeCharacter()); | ||
| 226 | start = pos; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | throw syntaxError("Unterminated string"); | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Unescapes the character identified by the character or characters that | ||
| 235 | * immediately follow a backslash. The backslash '\' should have already | ||
| 236 | * been read. This supports both unicode escapes "u000A" and two-character | ||
| 237 | * escapes "\n". | ||
| 238 | * | ||
| 239 | * @throws NumberFormatException if any unicode escape sequences are | ||
| 240 | * malformed. | ||
| 241 | */ | ||
| 242 | private char readEscapeCharacter() throws JSONException { | ||
| 243 | char escaped = in.charAt(pos++); | ||
| 244 | switch (escaped) { | ||
| 245 | case 'u': | ||
| 246 | if (pos + 4 > in.length()) { | ||
| 247 | throw syntaxError("Unterminated escape sequence"); | ||
| 248 | } | ||
| 249 | String hex = in.substring(pos, pos + 4); | ||
| 250 | pos += 4; | ||
| 251 | return (char) Integer.parseInt(hex, 16); | ||
| 252 | |||
| 253 | case 't': | ||
| 254 | return '\t'; | ||
| 255 | |||
| 256 | case 'b': | ||
| 257 | return '\b'; | ||
| 258 | |||
| 259 | case 'n': | ||
| 260 | return '\n'; | ||
| 261 | |||
| 262 | case 'r': | ||
| 263 | return '\r'; | ||
| 264 | |||
| 265 | case 'f': | ||
| 266 | return '\f'; | ||
| 267 | |||
| 268 | case '\'': | ||
| 269 | case '"': | ||
| 270 | case '\\': | ||
| 271 | default: | ||
| 272 | return escaped; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * Reads a null, boolean, numeric or unquoted string literal value. Numeric | ||
| 278 | * values will be returned as an Integer, Long, or Double, in that order of | ||
| 279 | * preference. | ||
| 280 | */ | ||
| 281 | private Object readLiteral() throws JSONException { | ||
| 282 | String literal = nextToInternal("{}[]/\\:,=;# \t\f"); | ||
| 283 | |||
| 284 | if (literal.length() == 0) { | ||
| 285 | throw syntaxError("Expected literal value"); | ||
| 286 | } else if ("null".equalsIgnoreCase(literal)) { | ||
| 287 | return JSONObject.NULL; | ||
| 288 | } else if ("true".equalsIgnoreCase(literal)) { | ||
| 289 | return Boolean.TRUE; | ||
| 290 | } else if ("false".equalsIgnoreCase(literal)) { | ||
| 291 | return Boolean.FALSE; | ||
| 292 | } | ||
| 293 | |||
| 294 | /* try to parse as an integral type... */ | ||
| 295 | if (literal.indexOf('.') == -1) { | ||
| 296 | int base = 10; | ||
| 297 | String number = literal; | ||
| 298 | if (number.startsWith("0x") || number.startsWith("0X")) { | ||
| 299 | number = number.substring(2); | ||
| 300 | base = 16; | ||
| 301 | } else if (number.startsWith("0") && number.length() > 1) { | ||
| 302 | number = number.substring(1); | ||
| 303 | base = 8; | ||
| 304 | } | ||
| 305 | try { | ||
| 306 | long longValue = Long.parseLong(number, base); | ||
| 307 | if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { | ||
| 308 | return (int) longValue; | ||
| 309 | } else { | ||
| 310 | return longValue; | ||
| 311 | } | ||
| 312 | } catch (NumberFormatException e) { | ||
| 313 | /* | ||
| 314 | * This only happens for integral numbers greater than | ||
| 315 | * Long.MAX_VALUE, numbers in exponential form (5e-10) and | ||
| 316 | * unquoted strings. Fall through to try floating point. | ||
| 317 | */ | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | /* ...next try to parse as a floating point... */ | ||
| 322 | try { | ||
| 323 | return Double.valueOf(literal); | ||
| 324 | } catch (NumberFormatException ignored) { | ||
| 325 | } | ||
| 326 | |||
| 327 | /* ... finally give up. We have an unquoted string */ | ||
| 328 | return new String(literal); // a new string avoids leaking memory | ||
| 329 | } | ||
| 330 | |||
| 331 | /** | ||
| 332 | * Returns the string up to but not including any of the given characters or | ||
| 333 | * a newline character. This does not consume the excluded character. | ||
| 334 | */ | ||
| 335 | private String nextToInternal(String excluded) { | ||
| 336 | int start = pos; | ||
| 337 | for (; pos < in.length(); pos++) { | ||
| 338 | char c = in.charAt(pos); | ||
| 339 | if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) { | ||
| 340 | return in.substring(start, pos); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | return in.substring(start); | ||
| 344 | } | ||
| 345 | |||
| 346 | /** | ||
| 347 | * Reads a sequence of key/value pairs and the trailing closing brace '}' of | ||
| 348 | * an object. The opening brace '{' should have already been read. | ||
| 349 | */ | ||
| 350 | private JSONObject readObject() throws JSONException { | ||
| 351 | JSONObject result = new JSONObject(); | ||
| 352 | |||
| 353 | /* Peek to see if this is the empty object. */ | ||
| 354 | int first = nextCleanInternal(); | ||
| 355 | if (first == '}') { | ||
| 356 | return result; | ||
| 357 | } else if (first != -1) { | ||
| 358 | pos--; | ||
| 359 | } | ||
| 360 | |||
| 361 | while (true) { | ||
| 362 | Object name = nextValue(); | ||
| 363 | if (!(name instanceof String)) { | ||
| 364 | if (name == null) { | ||
| 365 | throw syntaxError("Names cannot be null"); | ||
| 366 | } else { | ||
| 367 | throw syntaxError("Names must be strings, but " + name | ||
| 368 | + " is of type " + name.getClass().getName()); | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | /* | ||
| 373 | * Expect the name/value separator to be either a colon ':', an | ||
| 374 | * equals sign '=', or an arrow "=>". The last two are bogus but we | ||
| 375 | * include them because that's what the original implementation did. | ||
| 376 | */ | ||
| 377 | int separator = nextCleanInternal(); | ||
| 378 | if (separator != ':' && separator != '=') { | ||
| 379 | throw syntaxError("Expected ':' after " + name); | ||
| 380 | } | ||
| 381 | if (pos < in.length() && in.charAt(pos) == '>') { | ||
| 382 | pos++; | ||
| 383 | } | ||
| 384 | |||
| 385 | result.put((String) name, nextValue()); | ||
| 386 | |||
| 387 | switch (nextCleanInternal()) { | ||
| 388 | case '}': | ||
| 389 | return result; | ||
| 390 | case ';': | ||
| 391 | case ',': | ||
| 392 | continue; | ||
| 393 | default: | ||
| 394 | throw syntaxError("Unterminated object"); | ||
| 395 | } | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | /** | ||
| 400 | * Reads a sequence of values and the trailing closing brace ']' of an | ||
| 401 | * array. The opening brace '[' should have already been read. Note that | ||
| 402 | * "[]" yields an empty array, but "[,]" returns a two-element array | ||
| 403 | * equivalent to "[null,null]". | ||
| 404 | */ | ||
| 405 | private JSONArray readArray() throws JSONException { | ||
| 406 | JSONArray result = new JSONArray(); | ||
| 407 | |||
| 408 | /* to cover input that ends with ",]". */ | ||
| 409 | boolean hasTrailingSeparator = false; | ||
| 410 | |||
| 411 | while (true) { | ||
| 412 | switch (nextCleanInternal()) { | ||
| 413 | case -1: | ||
| 414 | throw syntaxError("Unterminated array"); | ||
| 415 | case ']': | ||
| 416 | if (hasTrailingSeparator) { | ||
| 417 | result.put(null); | ||
| 418 | } | ||
| 419 | return result; | ||
| 420 | case ',': | ||
| 421 | case ';': | ||
| 422 | /* A separator without a value first means "null". */ | ||
| 423 | result.put(null); | ||
| 424 | hasTrailingSeparator = true; | ||
| 425 | continue; | ||
| 426 | default: | ||
| 427 | pos--; | ||
| 428 | } | ||
| 429 | |||
| 430 | result.put(nextValue()); | ||
| 431 | |||
| 432 | switch (nextCleanInternal()) { | ||
| 433 | case ']': | ||
| 434 | return result; | ||
| 435 | case ',': | ||
| 436 | case ';': | ||
| 437 | hasTrailingSeparator = true; | ||
| 438 | continue; | ||
| 439 | default: | ||
| 440 | throw syntaxError("Unterminated array"); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | /** | ||
| 446 | * Returns an exception containing the given message plus the current | ||
| 447 | * position and the entire input string. | ||
| 448 | */ | ||
| 449 | public JSONException syntaxError(String message) { | ||
| 450 | return new JSONException(message + this); | ||
| 451 | } | ||
| 452 | |||
| 453 | /** | ||
| 454 | * Returns the current position and the entire input string. | ||
| 455 | */ | ||
| 456 | @Override public String toString() { | ||
| 457 | // consistent with the original implementation | ||
| 458 | return " at character " + pos + " of " + in; | ||
| 459 | } | ||
| 460 | |||
| 461 | /* | ||
| 462 | * Legacy APIs. | ||
| 463 | * | ||
| 464 | * None of the methods below are on the critical path of parsing JSON | ||
| 465 | * documents. They exist only because they were exposed by the original | ||
| 466 | * implementation and may be used by some clients. | ||
| 467 | */ | ||
| 468 | |||
| 469 | /** | ||
| 470 | * Returns true until the input has been exhausted. | ||
| 471 | */ | ||
| 472 | public boolean more() { | ||
| 473 | return pos < in.length(); | ||
| 474 | } | ||
| 475 | |||
| 476 | /** | ||
| 477 | * Returns the next available character, or the null character '\0' if all | ||
| 478 | * input has been exhausted. The return value of this method is ambiguous | ||
| 479 | * for JSON strings that contain the character '\0'. | ||
| 480 | */ | ||
| 481 | public char next() { | ||
| 482 | return pos < in.length() ? in.charAt(pos++) : '\0'; | ||
| 483 | } | ||
| 484 | |||
| 485 | /** | ||
| 486 | * Returns the next available character if it equals {@code c}. Otherwise an | ||
| 487 | * exception is thrown. | ||
| 488 | */ | ||
| 489 | public char next(char c) throws JSONException { | ||
| 490 | char result = next(); | ||
| 491 | if (result != c) { | ||
| 492 | throw syntaxError("Expected " + c + " but was " + result); | ||
| 493 | } | ||
| 494 | return result; | ||
| 495 | } | ||
| 496 | |||
| 497 | /** | ||
| 498 | * Returns the next character that is not whitespace and does not belong to | ||
| 499 | * a comment. If the input is exhausted before such a character can be | ||
| 500 | * found, the null character '\0' is returned. The return value of this | ||
| 501 | * method is ambiguous for JSON strings that contain the character '\0'. | ||
| 502 | */ | ||
| 503 | public char nextClean() throws JSONException { | ||
| 504 | int nextCleanInt = nextCleanInternal(); | ||
| 505 | return nextCleanInt == -1 ? '\0' : (char) nextCleanInt; | ||
| 506 | } | ||
| 507 | |||
| 508 | /** | ||
| 509 | * Returns the next {@code length} characters of the input. | ||
| 510 | * | ||
| 511 | * <p>The returned string shares its backing character array with this | ||
| 512 | * tokener's input string. If a reference to the returned string may be held | ||
| 513 | * indefinitely, you should use {@code new String(result)} to copy it first | ||
| 514 | * to avoid memory leaks. | ||
| 515 | * | ||
| 516 | * @throws JSONException if the remaining input is not long enough to | ||
| 517 | * satisfy this request. | ||
| 518 | */ | ||
| 519 | public String next(int length) throws JSONException { | ||
| 520 | if (pos + length > in.length()) { | ||
| 521 | throw syntaxError(length + " is out of bounds"); | ||
| 522 | } | ||
| 523 | String result = in.substring(pos, pos + length); | ||
| 524 | pos += length; | ||
| 525 | return result; | ||
| 526 | } | ||
| 527 | |||
| 528 | /** | ||
| 529 | * Returns the {@link String#trim trimmed} string holding the characters up | ||
| 530 | * to but not including the first of: | ||
| 531 | * <ul> | ||
| 532 | * <li>any character in {@code excluded} | ||
| 533 | * <li>a newline character '\n' | ||
| 534 | * <li>a carriage return '\r' | ||
| 535 | * </ul> | ||
| 536 | * | ||
| 537 | * <p>The returned string shares its backing character array with this | ||
| 538 | * tokener's input string. If a reference to the returned string may be held | ||
| 539 | * indefinitely, you should use {@code new String(result)} to copy it first | ||
| 540 | * to avoid memory leaks. | ||
| 541 | * | ||
| 542 | * @return a possibly-empty string | ||
| 543 | */ | ||
| 544 | public String nextTo(String excluded) { | ||
| 545 | if (excluded == null) { | ||
| 546 | throw new NullPointerException(); | ||
| 547 | } | ||
| 548 | return nextToInternal(excluded).trim(); | ||
| 549 | } | ||
| 550 | |||
| 551 | /** | ||
| 552 | * Equivalent to {@code nextTo(String.valueOf(excluded))}. | ||
| 553 | */ | ||
| 554 | public String nextTo(char excluded) { | ||
| 555 | return nextToInternal(String.valueOf(excluded)).trim(); | ||
| 556 | } | ||
| 557 | |||
| 558 | /** | ||
| 559 | * Advances past all input up to and including the next occurrence of | ||
| 560 | * {@code thru}. If the remaining input doesn't contain {@code thru}, the | ||
| 561 | * input is exhausted. | ||
| 562 | */ | ||
| 563 | public void skipPast(String thru) { | ||
| 564 | int thruStart = in.indexOf(thru, pos); | ||
| 565 | pos = thruStart == -1 ? in.length() : (thruStart + thru.length()); | ||
| 566 | } | ||
| 567 | |||
| 568 | /** | ||
| 569 | * Advances past all input up to but not including the next occurrence of | ||
| 570 | * {@code to}. If the remaining input doesn't contain {@code to}, the input | ||
| 571 | * is unchanged. | ||
| 572 | */ | ||
| 573 | public char skipTo(char to) { | ||
| 574 | int index = in.indexOf(to, pos); | ||
| 575 | if (index != -1) { | ||
| 576 | pos = index; | ||
| 577 | return to; | ||
| 578 | } else { | ||
| 579 | return '\0'; | ||
| 580 | } | ||
| 581 | } | ||
| 582 | |||
| 583 | /** | ||
| 584 | * Unreads the most recent character of input. If no input characters have | ||
| 585 | * been read, the input is unchanged. | ||
| 586 | */ | ||
| 587 | public void back() { | ||
| 588 | if (--pos == -1) { | ||
| 589 | pos = 0; | ||
| 590 | } | ||
| 591 | } | ||
| 592 | |||
| 593 | /** | ||
| 594 | * Returns the integer [0..15] value for the given hex character, or -1 | ||
| 595 | * for non-hex input. | ||
| 596 | * | ||
| 597 | * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other | ||
| 598 | * character will yield a -1 result. | ||
| 599 | */ | ||
| 600 | public static int dehexchar(char hex) { | ||
| 601 | if (hex >= '0' && hex <= '9') { | ||
| 602 | return hex - '0'; | ||
| 603 | } else if (hex >= 'A' && hex <= 'F') { | ||
| 604 | return hex - 'A' + 10; | ||
| 605 | } else if (hex >= 'a' && hex <= 'f') { | ||
| 606 | return hex - 'a' + 10; | ||
| 607 | } else { | ||
| 608 | return -1; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | 1 | /* |
TraceSDK/src/com/mobithink/tracesdk/rest/client/AbstractClient.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.net.URI; | ||
| 4 | import java.text.SimpleDateFormat; | ||
| 5 | import java.util.Date; | ||
| 6 | |||
| 7 | import org.apache.http.cookie.Cookie; | ||
| 8 | |||
| 9 | /** | ||
| 10 | * Common implementation of IClient. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | public abstract class AbstractClient implements IClient { | ||
| 14 | |||
| 15 | UriBuilder uriBuilder; | ||
| 16 | |||
| 17 | MultivaluedMap<String, String> headers = new MetadataMap<String, String>(); | ||
| 18 | |||
| 19 | protected AbstractClient(URI baseUri) { | ||
| 20 | this.uriBuilder = new UriBuilder(baseUri); | ||
| 21 | } | ||
| 22 | |||
| 23 | @Override | ||
| 24 | public IClient type(MediaType ct) { | ||
| 25 | return type(ct.getTypeName()); | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override | ||
| 29 | public IClient type(String type) { | ||
| 30 | headers.putSingle(HttpHeaders.CONTENT_TYPE, type); | ||
| 31 | return this; | ||
| 32 | } | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public IClient accept(MediaType... types) { | ||
| 36 | for (MediaType type : types) { | ||
| 37 | headers.addNoDuplicateValue(HttpHeaders.ACCEPT, type.getTypeName()); | ||
| 38 | } | ||
| 39 | return this; | ||
| 40 | } | ||
| 41 | |||
| 42 | @Override | ||
| 43 | public IClient accept(String... types) { | ||
| 44 | for (String type : types) { | ||
| 45 | headers.addNoDuplicateValue(HttpHeaders.ACCEPT, type); | ||
| 46 | } | ||
| 47 | return this; | ||
| 48 | } | ||
| 49 | |||
| 50 | @Override | ||
| 51 | public IClient language(String language) { | ||
| 52 | headers.putSingle(HttpHeaders.CONTENT_LANGUAGE, language); | ||
| 53 | return this; | ||
| 54 | } | ||
| 55 | |||
| 56 | @Override | ||
| 57 | public IClient acceptLanguage(String... languages) { | ||
| 58 | for (String s : languages) { | ||
| 59 | headers.addNoDuplicateValue(HttpHeaders.ACCEPT_LANGUAGE, s); | ||
| 60 | } | ||
| 61 | return this; | ||
| 62 | } | ||
| 63 | |||
| 64 | @Override | ||
| 65 | public IClient encoding(String encoding) { | ||
| 66 | headers.putSingle(HttpHeaders.CONTENT_ENCODING, encoding); | ||
| 67 | return this; | ||
| 68 | } | ||
| 69 | |||
| 70 | @Override | ||
| 71 | public IClient acceptEncoding(String... encodings) { | ||
| 72 | for (String s : encodings) { | ||
| 73 | headers.addNoDuplicateValue(HttpHeaders.ACCEPT_ENCODING, s); | ||
| 74 | } | ||
| 75 | return this; | ||
| 76 | } | ||
| 77 | |||
| 78 | @Override | ||
| 79 | public IClient match(String tag, boolean ifNot) { | ||
| 80 | String hName = ifNot ? HttpHeaders.IF_NONE_MATCH : HttpHeaders.IF_MATCH; | ||
| 81 | headers.putSingle(hName, tag); | ||
| 82 | return this; | ||
| 83 | } | ||
| 84 | |||
| 85 | @Override | ||
| 86 | public IClient modified(Date date, boolean ifNot) { | ||
| 87 | SimpleDateFormat dateFormat = Utils.getHttpDateFormat(); | ||
| 88 | String hName = ifNot ? HttpHeaders.IF_UNMODIFIED_SINCE : HttpHeaders.IF_MODIFIED_SINCE; | ||
| 89 | headers.putSingle(hName, dateFormat.format(date)); | ||
| 90 | return this; | ||
| 91 | } | ||
| 92 | |||
| 93 | @Override | ||
| 94 | public IClient cookie(Cookie cookie) { | ||
| 95 | headers.addNoDuplicateValue(HttpHeaders.COOKIE, cookie.toString()); | ||
| 96 | return this; | ||
| 97 | } | ||
| 98 | |||
| 99 | @Override | ||
| 100 | public IClient header(String name, Object... values) { | ||
| 101 | if (values == null) { | ||
| 102 | throw new IllegalArgumentException(); | ||
| 103 | } | ||
| 104 | for (Object o : values) { | ||
| 105 | headers.addNoDuplicateValue(name, o.toString()); | ||
| 106 | } | ||
| 107 | return this; | ||
| 108 | } | ||
| 109 | |||
| 110 | @Override | ||
| 111 | public IClient headers(MultivaluedMap<String, String> map) { | ||
| 112 | headers.putAll(map); | ||
| 113 | return this; | ||
| 114 | } | ||
| 115 | |||
| 116 | @Override | ||
| 117 | public IClient reset() { | ||
| 118 | headers.clear(); | ||
| 119 | return this; | ||
| 120 | } | ||
| 121 | |||
| 122 | @Override | ||
| 123 | public MultivaluedMap<String, String> getHeaders() { | ||
| 124 | return headers; | ||
| 125 | } | ||
| 126 | |||
| 127 | @Override | ||
| 128 | public URI getBaseURI() { | ||
| 129 | return uriBuilder.getBaseUri(); | ||
| 130 | } | ||
| 131 | |||
| 132 | @Override | ||
| 133 | public URI getCurrentURI() { | ||
| 134 | return uriBuilder.build(); | ||
| 135 | } | ||
| 136 | |||
| 137 | @Override | ||
| 138 | public abstract Response getResponse(); | ||
| 139 | |||
| 140 | } | ||
| 141 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/DefaultRESTClient.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import com.mobithink.tracesdk.Conf; | ||
| 4 | |||
| 5 | public class DefaultRESTClient extends RESTClient { | ||
| 6 | |||
| 7 | // private static final String BASE_URI = "http://mtafftracking.com/"; | ||
| 8 | |||
| 9 | protected DefaultRESTClient(String baseUri) { | ||
| 10 | super(baseUri); | ||
| 11 | } | ||
| 12 | |||
| 13 | public static DefaultRESTClient create() { | ||
| 14 | return DefaultRESTClient.create(Conf.App.API_SERVER); | ||
| 15 | } | ||
| 16 | |||
| 17 | public static DefaultRESTClient create(String baseUri) { | ||
| 18 | DefaultRESTClient client = new DefaultRESTClient(baseUri); | ||
| 19 | DefaultRESTClient.DEBUG = true; | ||
| 20 | client.setRequestEntity(new RequestEntityImplString()); | ||
| 21 | client.setEntityReader(new EntityReaderImplString()); | ||
| 22 | client.type(MediaType.APPLICATION_FORM_URLENCODED); | ||
| 23 | client.accept(MediaType.TEXT_JSON); | ||
| 24 | client.acceptEncoding(EntityReader.ENCODING_GZIP); | ||
| 25 | return client; | ||
| 26 | } | ||
| 27 | |||
| 28 | } | ||
| 29 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/EntityReader.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.io.IOException; | ||
| 4 | import java.io.InputStream; | ||
| 5 | import java.util.zip.GZIPInputStream; | ||
| 6 | |||
| 7 | import org.apache.http.HttpEntity; | ||
| 8 | import org.apache.http.entity.HttpEntityWrapper; | ||
| 9 | |||
| 10 | /** | ||
| 11 | * Read entity content to the target type. | ||
| 12 | */ | ||
| 13 | public abstract class EntityReader<T> { | ||
| 14 | |||
| 15 | public static final String ENCODING_GZIP = "gzip"; | ||
| 16 | |||
| 17 | public abstract T read(HttpEntity entity); | ||
| 18 | |||
| 19 | protected String debug; | ||
| 20 | |||
| 21 | public String getDebug() { | ||
| 22 | return this.debug; | ||
| 23 | } | ||
| 24 | |||
| 25 | public static class GzipDecompressingEntity extends HttpEntityWrapper { | ||
| 26 | |||
| 27 | public GzipDecompressingEntity(final HttpEntity entity) { | ||
| 28 | super(entity); | ||
| 29 | } | ||
| 30 | |||
| 31 | @Override | ||
| 32 | public InputStream getContent() throws IOException, IllegalStateException { | ||
| 33 | // the wrapped entity's getContent() decides about repeatability | ||
| 34 | InputStream wrappedin = wrappedEntity.getContent(); | ||
| 35 | return new GZIPInputStream(wrappedin); | ||
| 36 | } | ||
| 37 | |||
| 38 | @Override | ||
| 39 | public long getContentLength() { | ||
| 40 | // length of ungzipped content is not known | ||
| 41 | return -1; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/EntityReaderImplJSON.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.io.IOException; | ||
| 4 | |||
| 5 | import org.apache.http.Header; | ||
| 6 | import org.apache.http.HttpEntity; | ||
| 7 | import org.apache.http.ParseException; | ||
| 8 | import org.apache.http.protocol.HTTP; | ||
| 9 | import org.apache.http.util.EntityUtils; | ||
| 10 | |||
| 11 | import com.mobithink.tracesdk.json.JSONException; | ||
| 12 | import com.mobithink.tracesdk.json.JSONObject; | ||
| 13 | |||
| 14 | public class EntityReaderImplJSON extends EntityReader<JSONObject> { | ||
| 15 | |||
| 16 | @Override | ||
| 17 | public JSONObject read(HttpEntity entity) { | ||
| 18 | Header encodingHead = entity.getContentEncoding(); | ||
| 19 | if (encodingHead != null && encodingHead.getValue() != null && encodingHead.getValue().contains(ENCODING_GZIP)) { | ||
| 20 | entity = new GzipDecompressingEntity(entity); | ||
| 21 | } | ||
| 22 | try { | ||
| 23 | String result = EntityUtils.toString(entity, HTTP.UTF_8); | ||
| 24 | if (RESTClient.DEBUG) { | ||
| 25 | this.debug = result; | ||
| 26 | } | ||
| 27 | if (result != null && result.length() >= 3) { | ||
| 28 | return new JSONObject(result); | ||
| 29 | } else { | ||
| 30 | return null; | ||
| 31 | } | ||
| 32 | } catch (ParseException e) { | ||
| 33 | e.printStackTrace(); | ||
| 34 | } catch (JSONException e) { | ||
| 35 | e.printStackTrace(); | ||
| 36 | } catch (IOException e) { | ||
| 37 | e.printStackTrace(); | ||
| 38 | } | ||
| 39 | |||
| 40 | return null; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/EntityReaderImplString.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.io.IOException; | ||
| 4 | |||
| 5 | import org.apache.http.Header; | ||
| 6 | import org.apache.http.HttpEntity; | ||
| 7 | import org.apache.http.ParseException; | ||
| 8 | import org.apache.http.protocol.HTTP; | ||
| 9 | import org.apache.http.util.EntityUtils; | ||
| 10 | |||
| 11 | public class EntityReaderImplString extends EntityReader<String> { | ||
| 12 | |||
| 13 | @Override | ||
| 14 | public String read(HttpEntity entity) { | ||
| 15 | Header encodingHead = entity.getContentEncoding(); | ||
| 16 | if (encodingHead != null && encodingHead.getValue() != null && encodingHead.getValue().contains(ENCODING_GZIP)) { | ||
| 17 | entity = new GzipDecompressingEntity(entity); | ||
| 18 | } | ||
| 19 | try { | ||
| 20 | String result = EntityUtils.toString(entity, HTTP.UTF_8); | ||
| 21 | if (RESTClient.DEBUG) { | ||
| 22 | this.debug = result; | ||
| 23 | } | ||
| 24 | return result; | ||
| 25 | } catch (ParseException e) { | ||
| 26 | e.printStackTrace(); | ||
| 27 | } catch (IOException e) { | ||
| 28 | e.printStackTrace(); | ||
| 29 | } | ||
| 30 | |||
| 31 | return null; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/HttpExecutor.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.io.IOException; | ||
| 4 | import java.util.List; | ||
| 5 | import java.util.Map; | ||
| 6 | |||
| 7 | import org.apache.http.Header; | ||
| 8 | import org.apache.http.HttpEntity; | ||
| 9 | import org.apache.http.HttpResponse; | ||
| 10 | import org.apache.http.client.ClientProtocolException; | ||
| 11 | import org.apache.http.client.methods.HttpDelete; | ||
| 12 | import org.apache.http.client.methods.HttpGet; | ||
| 13 | import org.apache.http.client.methods.HttpOptions; | ||
| 14 | import org.apache.http.client.methods.HttpPost; | ||
| 15 | import org.apache.http.client.methods.HttpPut; | ||
| 16 | import org.apache.http.client.methods.HttpUriRequest; | ||
| 17 | import org.apache.http.conn.ClientConnectionManager; | ||
| 18 | import org.apache.http.impl.client.DefaultHttpClient; | ||
| 19 | import org.apache.http.params.BasicHttpParams; | ||
| 20 | import org.apache.http.params.HttpConnectionParams; | ||
| 21 | import org.apache.http.params.HttpParams; | ||
| 22 | |||
| 23 | import android.util.Log; | ||
| 24 | |||
| 25 | public class HttpExecutor { | ||
| 26 | |||
| 27 | public static enum HTTP_METHOD { | ||
| 28 | GET, POST, PUT, DELETE, OPTIONS | ||
| 29 | }; | ||
| 30 | |||
| 31 | public static final int TIMEOUT_CONNECTION = 15000; | ||
| 32 | public static final int TIMEOUT_SOCKET = 10000; | ||
| 33 | |||
| 34 | private DefaultHttpClient client; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Do send the http request. | ||
| 38 | * | ||
| 39 | * @param uriBuilder | ||
| 40 | * The UriBuilder | ||
| 41 | * @param method | ||
| 42 | * HTTP method | ||
| 43 | * @param headers | ||
| 44 | * Multiple values map | ||
| 45 | * @param requestEntity | ||
| 46 | * Use on POST or PUT request | ||
| 47 | * @param entityReader | ||
| 48 | * Read the entity return | ||
| 49 | * @return The Response instance | ||
| 50 | */ | ||
| 51 | public Response execute(UriBuilder uriBuilder, HTTP_METHOD method, MultivaluedMap<String, String> headers, RequestEntity requestEntity, EntityReader<?> entityReader) { | ||
| 52 | client = getHttpClient(); | ||
| 53 | HttpUriRequest request = getHttpRequest(uriBuilder, method, headers, requestEntity); | ||
| 54 | ResponseImpl response = new ResponseImpl(); | ||
| 55 | try { | ||
| 56 | HttpResponse httpResponse = client.execute(request); | ||
| 57 | for (Header header : httpResponse.getAllHeaders()) { | ||
| 58 | response.setHeader(header.getName(), header.getValue()); | ||
| 59 | } | ||
| 60 | HttpEntity entity = httpResponse.getEntity(); | ||
| 61 | if (entity != null) { | ||
| 62 | response.setEntity(entityReader.read(entity)); | ||
| 63 | response.setDebug(entityReader.getDebug()); | ||
| 64 | } | ||
| 65 | int httpStatus = httpResponse.getStatusLine().getStatusCode(); | ||
| 66 | response.setHttpStatus(httpStatus); | ||
| 67 | |||
| 68 | } catch (ClientProtocolException e) { | ||
| 69 | e.printStackTrace(); | ||
| 70 | response.setErrorCode(Response.ERROR_CLIENT_NETWORK); | ||
| 71 | } catch (IOException e) { | ||
| 72 | e.printStackTrace(); | ||
| 73 | response.setErrorCode(Response.ERROR_CLIENT_IO); | ||
| 74 | } catch (Exception e) { | ||
| 75 | e.printStackTrace(); | ||
| 76 | response.setErrorCode(Response.ERROR_CLIENT_UNKNOWN); | ||
| 77 | } finally { | ||
| 78 | try { | ||
| 79 | client.getConnectionManager().shutdown(); | ||
| 80 | } catch (Exception e) { | ||
| 81 | e.printStackTrace(); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | return response; | ||
| 85 | } | ||
| 86 | |||
| 87 | public DefaultHttpClient getHttpClient() { | ||
| 88 | HttpParams httpParams = new BasicHttpParams(); | ||
| 89 | HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT_CONNECTION); | ||
| 90 | HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT_SOCKET); | ||
| 91 | return new DefaultHttpClient(httpParams); | ||
| 92 | } | ||
| 93 | |||
| 94 | public HttpUriRequest getHttpRequest(UriBuilder uriBuilder, HTTP_METHOD method, MultivaluedMap<String, String> headers, RequestEntity entityGenerator) { | ||
| 95 | switch (method) { | ||
| 96 | case GET: | ||
| 97 | return getRequest_GET(uriBuilder, headers); | ||
| 98 | case POST: | ||
| 99 | return getRequest_POST(uriBuilder, headers, entityGenerator); | ||
| 100 | case PUT: | ||
| 101 | return getRequest_PUT(uriBuilder, headers, entityGenerator); | ||
| 102 | case DELETE: | ||
| 103 | return getRequest_DELETE(uriBuilder, headers); | ||
| 104 | case OPTIONS: | ||
| 105 | return getRequest_OPTIONS(uriBuilder, headers); | ||
| 106 | } | ||
| 107 | return null; | ||
| 108 | } | ||
| 109 | |||
| 110 | public HttpUriRequest getRequest_GET(UriBuilder uriBuilder, MultivaluedMap<String, String> headers) { | ||
| 111 | HttpGet get = new HttpGet(uriBuilder.buildIncludeParams()); | ||
| 112 | addToHeader(get, headers); | ||
| 113 | return get; | ||
| 114 | } | ||
| 115 | |||
| 116 | public HttpUriRequest getRequest_POST(UriBuilder uriBuilder, MultivaluedMap<String, String> headers, RequestEntity requestEntity) { | ||
| 117 | HttpPost post = new HttpPost(uriBuilder.build()); | ||
| 118 | addToHeader(post, headers); | ||
| 119 | if (requestEntity != null) { | ||
| 120 | HttpEntity entity = requestEntity.get(uriBuilder, headers); | ||
| 121 | if (entity != null) { | ||
| 122 | post.setEntity(entity); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | return post; | ||
| 126 | } | ||
| 127 | |||
| 128 | public HttpUriRequest getRequest_PUT(UriBuilder uriBuilder, MultivaluedMap<String, String> headers, RequestEntity entityGenerator) { | ||
| 129 | HttpPut put = new HttpPut(uriBuilder.build()); | ||
| 130 | addToHeader(put, headers); | ||
| 131 | if (entityGenerator != null) { | ||
| 132 | HttpEntity entity = entityGenerator.get(uriBuilder, headers); | ||
| 133 | if (entity != null) { | ||
| 134 | put.setEntity(entity); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | return put; | ||
| 138 | } | ||
| 139 | |||
| 140 | public HttpUriRequest getRequest_DELETE(UriBuilder uriBuilder, MultivaluedMap<String, String> headers) { | ||
| 141 | HttpDelete delete = new HttpDelete(uriBuilder.buildIncludeParams()); | ||
| 142 | addToHeader(delete, headers); | ||
| 143 | return delete; | ||
| 144 | } | ||
| 145 | |||
| 146 | public HttpUriRequest getRequest_OPTIONS(UriBuilder uriBuilder, MultivaluedMap<String, String> headers) { | ||
| 147 | HttpOptions opt = new HttpOptions(uriBuilder.buildIncludeParams()); | ||
| 148 | addToHeader(opt, headers); | ||
| 149 | return opt; | ||
| 150 | } | ||
| 151 | |||
| 152 | private void addToHeader(HttpUriRequest request, MultivaluedMap<String, String> headers) { | ||
| 153 | if (headers != null && headers.size() > 0) { | ||
| 154 | for (Map.Entry<String, List<String>> entry : headers.entrySet()) { | ||
| 155 | String k = entry.getKey(); | ||
| 156 | for (String v : entry.getValue()) { | ||
| 157 | request.addHeader(k, v); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | public void close() { | ||
| 164 | if (client != null) { | ||
| 165 | try { | ||
| 166 | ClientConnectionManager manager = client.getConnectionManager(); | ||
| 167 | if (manager != null) { | ||
| 168 | manager.shutdown(); | ||
| 169 | } | ||
| 170 | } catch (Exception e) { | ||
| 171 | e.printStackTrace(); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/HttpHeaders.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.util.List; | ||
| 4 | import java.util.Locale; | ||
| 5 | import java.util.Map; | ||
| 6 | |||
| 7 | import org.apache.http.cookie.Cookie; | ||
| 8 | |||
| 9 | public abstract interface HttpHeaders { | ||
| 10 | public static final String ACCEPT = "Accept"; | ||
| 11 | public static final String ACCEPT_CHARSET = "Accept-Charset"; | ||
| 12 | public static final String ACCEPT_ENCODING = "Accept-Encoding"; | ||
| 13 | public static final String ACCEPT_LANGUAGE = "Accept-Language"; | ||
| 14 | public static final String AUTHORIZATION = "Authorization"; | ||
| 15 | public static final String CACHE_CONTROL = "Cache-Control"; | ||
| 16 | public static final String CONTENT_ENCODING = "Content-Encoding"; | ||
| 17 | public static final String CONTENT_LANGUAGE = "Content-Language"; | ||
| 18 | public static final String CONTENT_LENGTH = "Content-Length"; | ||
| 19 | public static final String CONTENT_LOCATION = "Content-Location"; | ||
| 20 | public static final String CONTENT_TYPE = "Content-Type"; | ||
| 21 | public static final String DATE = "Date"; | ||
| 22 | public static final String ETAG = "ETag"; | ||
| 23 | public static final String EXPIRES = "Expires"; | ||
| 24 | public static final String HOST = "Host"; | ||
| 25 | public static final String IF_MATCH = "If-Match"; | ||
| 26 | public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; | ||
| 27 | public static final String IF_NONE_MATCH = "If-None-Match"; | ||
| 28 | public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; | ||
| 29 | public static final String LAST_MODIFIED = "Last-Modified"; | ||
| 30 | public static final String LOCATION = "Location"; | ||
| 31 | public static final String USER_AGENT = "User-Agent"; | ||
| 32 | public static final String VARY = "Vary"; | ||
| 33 | public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; | ||
| 34 | public static final String COOKIE = "Cookie"; | ||
| 35 | public static final String SET_COOKIE = "Set-Cookie"; | ||
| 36 | |||
| 37 | public abstract List<String> getRequestHeader(String paramString); | ||
| 38 | |||
| 39 | public abstract Map<String, String> getRequestHeaders(); | ||
| 40 | |||
| 41 | public abstract List<MediaType> getAcceptableMediaTypes(); | ||
| 42 | |||
| 43 | public abstract List<Locale> getAcceptableLanguages(); | ||
| 44 | |||
| 45 | public abstract MediaType getMediaType(); | ||
| 46 | |||
| 47 | public abstract Locale getLanguage(); | ||
| 48 | |||
| 49 | public abstract Map<String, Cookie> getCookies(); | ||
| 50 | } |
TraceSDK/src/com/mobithink/tracesdk/rest/client/IClient.java
| 1 | /** | File was deleted | |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one | ||
| 3 | * or more contributor license agreements. See the NOTICE file | ||
| 4 | * distributed with this work for additional information | ||
| 5 | * regarding copyright ownership. The ASF licenses this file | ||
| 6 | * to you under the Apache License, Version 2.0 (the | ||
| 7 | * "License"); you may not use this file except in compliance | ||
| 8 | * with the License. You may obtain a copy of the License at | ||
| 9 | * | ||
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 11 | * | ||
| 12 | * Unless required by applicable law or agreed to in writing, | ||
| 13 | * software distributed under the License is distributed on an | ||
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| 15 | * KIND, either express or implied. See the License for the | ||
| 16 | * specific language governing permissions and limitations | ||
| 17 | * under the License. | ||
| 18 | */ | ||
| 19 | package com.mobithink.tracesdk.rest.client; | ||
| 20 | |||
| 21 | import java.net.URI; | ||
| 22 | import java.util.Date; | ||
| 23 | |||
| 24 | import org.apache.http.cookie.Cookie; | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Represents common proxy and http-centric client capabilities | ||
| 28 | * | ||
| 29 | */ | ||
| 30 | public interface IClient { | ||
| 31 | |||
| 32 | /** | ||
| 33 | * sets HTTP Content-Type header | ||
| 34 | * @param MediaType representing Content-Type value | ||
| 35 | * @return the updated Client | ||
| 36 | */ | ||
| 37 | IClient type(MediaType ct); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * sets HTTP Content-Type header | ||
| 41 | * @param type Content-Type value | ||
| 42 | * @return the updated Client | ||
| 43 | */ | ||
| 44 | IClient type(String type); | ||
| 45 | |||
| 46 | /** | ||
| 47 | * sets HTTP Accept header | ||
| 48 | * @param types list of MediaTypes representing Accept header values | ||
| 49 | * @return the updated Client | ||
| 50 | */ | ||
| 51 | IClient accept(MediaType... types); | ||
| 52 | |||
| 53 | /** | ||
| 54 | * sets HTTP Accept header | ||
| 55 | * @param types list of Accept header values | ||
| 56 | * @return the updated Client | ||
| 57 | */ | ||
| 58 | IClient accept(String... types); | ||
| 59 | |||
| 60 | /** | ||
| 61 | * sets HTTP Content-Language header | ||
| 62 | * @param language Content-Language header value | ||
| 63 | * @return the updated Client | ||
| 64 | */ | ||
| 65 | IClient language(String language); | ||
| 66 | |||
| 67 | /** | ||
| 68 | * sets HTTP Accept-Language header | ||
| 69 | * @param languages list of Accept-Language header values | ||
| 70 | * @return the updated Client | ||
| 71 | */ | ||
| 72 | IClient acceptLanguage(String ...languages); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * sets HTTP Content-Encoding header | ||
| 76 | * @param encoding Content-Encoding header value | ||
| 77 | * @return the updated Client | ||
| 78 | */ | ||
| 79 | IClient encoding(String encoding); | ||
| 80 | |||
| 81 | /** | ||
| 82 | * sets HTTP Accept-Encoding header | ||
| 83 | * @param encodings list of Accept-Encoding header value | ||
| 84 | * @return the updated Client | ||
| 85 | */ | ||
| 86 | IClient acceptEncoding(String ...encodings); | ||
| 87 | |||
| 88 | /** | ||
| 89 | * sets HTTP If-Match or If-None-Match header | ||
| 90 | * @param tag ETag value | ||
| 91 | * @param ifNot if true then If-None-Match is set, If-Match otherwise | ||
| 92 | * @return the updated Client | ||
| 93 | */ | ||
| 94 | IClient match(String tag, boolean ifNot); | ||
| 95 | |||
| 96 | /** | ||
| 97 | * sets HTTP If-Modified-Since or If-Unmodified-Since header | ||
| 98 | * @param date Date value, will be formated as "EEE, dd MMM yyyy HH:mm:ss zzz" | ||
| 99 | * @param ifNot if true then If-Unmodified-Since is set, If-Modified-Since otherwise | ||
| 100 | * @return the updated Client | ||
| 101 | */ | ||
| 102 | IClient modified(Date date, boolean ifNot); | ||
| 103 | |||
| 104 | /** | ||
| 105 | * sets HTTP Cookie header | ||
| 106 | * @param cookie Cookie value | ||
| 107 | * @return the updated Client | ||
| 108 | */ | ||
| 109 | IClient cookie(Cookie cookie); | ||
| 110 | |||
| 111 | /** | ||
| 112 | * Sets arbitrary HTTP Header | ||
| 113 | * @param name header name | ||
| 114 | * @param values list of header values | ||
| 115 | * @return the updated Client | ||
| 116 | */ | ||
| 117 | IClient header(String name, Object... values); | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Sets HTTP Headers | ||
| 121 | * @param map headers | ||
| 122 | * @return the updated Client | ||
| 123 | */ | ||
| 124 | IClient headers(MultivaluedMap<String, String> map); | ||
| 125 | |||
| 126 | /** | ||
| 127 | * Resets the headers and response state if any | ||
| 128 | * @return the updated Client | ||
| 129 | */ | ||
| 130 | IClient reset(); | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Gets the copy of request headers | ||
| 134 | * @return request headers | ||
| 135 | */ | ||
| 136 | MultivaluedMap<String, String> getHeaders(); | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Gets the base URI this Client has been intialized with | ||
| 140 | * @return base URI | ||
| 141 | */ | ||
| 142 | URI getBaseURI(); | ||
| 143 | |||
| 144 | /** | ||
| 145 | * Gets the current URI this Client is working with | ||
| 146 | * @return current URI | ||
| 147 | */ | ||
| 148 | URI getCurrentURI(); | ||
| 149 | |||
| 150 | /** | ||
| 151 | * Gets the response state if any | ||
| 152 | * @return Response response | ||
| 153 | */ | ||
| 154 | Response getResponse(); | ||
| 155 | } | ||
| 156 | 1 | /** |
TraceSDK/src/com/mobithink/tracesdk/rest/client/MediaType.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | public class MediaType { | ||
| 4 | |||
| 5 | public static final MediaType TEXT_JSON = new MediaType("text/json"); | ||
| 6 | public static final MediaType TEXT_XML = new MediaType("text/xml"); | ||
| 7 | public static final MediaType TEXT_HTML = new MediaType("text/html"); | ||
| 8 | public static final MediaType APPLICATION_FORM_URLENCODED = new MediaType("application/x-www-form-urlencoded"); | ||
| 9 | public static final MediaType APPLICATION_PROTOBUF = new MediaType("application/protobuf"); | ||
| 10 | |||
| 11 | private String type; | ||
| 12 | |||
| 13 | protected MediaType(String type) { | ||
| 14 | this.type = type; | ||
| 15 | } | ||
| 16 | |||
| 17 | public String getTypeName() { | ||
| 18 | return this.type; | ||
| 19 | } | ||
| 20 | |||
| 21 | public String toString() { | ||
| 22 | return this.type; | ||
| 23 | } | ||
| 24 | |||
| 25 | public boolean equals(String typeName) { | ||
| 26 | return this.type.equalsIgnoreCase(typeName); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/MetadataMap.java
| 1 | /** | File was deleted | |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one | ||
| 3 | * or more contributor license agreements. See the NOTICE file | ||
| 4 | * distributed with this work for additional information | ||
| 5 | * regarding copyright ownership. The ASF licenses this file | ||
| 6 | * to you under the Apache License, Version 2.0 (the | ||
| 7 | * "License"); you may not use this file except in compliance | ||
| 8 | * with the License. You may obtain a copy of the License at | ||
| 9 | * | ||
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 11 | * | ||
| 12 | * Unless required by applicable law or agreed to in writing, | ||
| 13 | * software distributed under the License is distributed on an | ||
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| 15 | * KIND, either express or implied. See the License for the | ||
| 16 | * specific language governing permissions and limitations | ||
| 17 | * under the License. | ||
| 18 | */ | ||
| 19 | |||
| 20 | package com.mobithink.tracesdk.rest.client; | ||
| 21 | |||
| 22 | import java.util.ArrayList; | ||
| 23 | import java.util.Arrays; | ||
| 24 | import java.util.Collection; | ||
| 25 | import java.util.Collections; | ||
| 26 | import java.util.Comparator; | ||
| 27 | import java.util.LinkedHashMap; | ||
| 28 | import java.util.List; | ||
| 29 | import java.util.Map; | ||
| 30 | import java.util.Set; | ||
| 31 | import java.util.TreeSet; | ||
| 32 | |||
| 33 | public class MetadataMap<K, V> implements MultivaluedMap<K, V> { | ||
| 34 | |||
| 35 | private boolean caseInsensitive; | ||
| 36 | private Map<K, List<V>> m; | ||
| 37 | |||
| 38 | public MetadataMap() { | ||
| 39 | this.m = new LinkedHashMap<K, List<V>>(); | ||
| 40 | } | ||
| 41 | |||
| 42 | public MetadataMap(int size) { | ||
| 43 | this.m = new LinkedHashMap<K, List<V>>(size); | ||
| 44 | } | ||
| 45 | |||
| 46 | public MetadataMap(Map<K, List<V>> store) { | ||
| 47 | this(store, false, false); | ||
| 48 | } | ||
| 49 | |||
| 50 | public MetadataMap(boolean readOnly, boolean caseInsensitive) { | ||
| 51 | this(null, readOnly, caseInsensitive); | ||
| 52 | } | ||
| 53 | |||
| 54 | public MetadataMap(Map<K, List<V>> store, boolean readOnly, boolean caseInsensitive) { | ||
| 55 | |||
| 56 | this(store, true, readOnly, caseInsensitive); | ||
| 57 | |||
| 58 | } | ||
| 59 | |||
| 60 | // TODO: Review the use of this constructor, | ||
| 61 | // refactor the code, copyStore and readOnly are duplicates | ||
| 62 | public MetadataMap(Map<K, List<V>> store, boolean copyStore, boolean readOnly, boolean caseInsensitive) { | ||
| 63 | |||
| 64 | if (copyStore) { | ||
| 65 | this.m = new LinkedHashMap<K, List<V>>(); | ||
| 66 | if (store != null) { | ||
| 67 | for (Map.Entry<K, List<V>> entry : store.entrySet()) { | ||
| 68 | List<V> values = new ArrayList<V>(entry.getValue()); | ||
| 69 | m.put(entry.getKey(), readOnly ? Collections.unmodifiableList(values) : values); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | if (readOnly) { | ||
| 73 | this.m = Collections.unmodifiableMap(m); | ||
| 74 | } | ||
| 75 | } else { | ||
| 76 | this.m = store; | ||
| 77 | } | ||
| 78 | this.caseInsensitive = caseInsensitive; | ||
| 79 | |||
| 80 | } | ||
| 81 | |||
| 82 | public void add(K key, V value) { | ||
| 83 | addValue(key, value, true); | ||
| 84 | } | ||
| 85 | |||
| 86 | private void addValue(K key, V value, boolean last) { | ||
| 87 | List<V> data = getList(key); | ||
| 88 | if (last) { | ||
| 89 | data.add(value); | ||
| 90 | } else { | ||
| 91 | data.add(0, value); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | private List<V> getList(K key) { | ||
| 96 | List<V> data = this.get(key); | ||
| 97 | if (data == null) { | ||
| 98 | data = new ArrayList<V>(); | ||
| 99 | m.put(key, data); | ||
| 100 | } | ||
| 101 | return data; | ||
| 102 | } | ||
| 103 | |||
| 104 | public V getFirst(K key) { | ||
| 105 | List<V> data = this.get(key); | ||
| 106 | return data == null ? null : data.get(0); | ||
| 107 | } | ||
| 108 | |||
| 109 | public void putSingle(K key, V value) { | ||
| 110 | List<V> data = new ArrayList<V>(); | ||
| 111 | data.add(value); | ||
| 112 | this.put(key, data); | ||
| 113 | } | ||
| 114 | |||
| 115 | public void clear() { | ||
| 116 | m.clear(); | ||
| 117 | } | ||
| 118 | |||
| 119 | public boolean containsKey(Object key) { | ||
| 120 | if (!caseInsensitive) { | ||
| 121 | return m.containsKey(key); | ||
| 122 | } | ||
| 123 | return getMatchingKey(key) != null; | ||
| 124 | } | ||
| 125 | |||
| 126 | public boolean containsValue(Object value) { | ||
| 127 | return m.containsValue(value); | ||
| 128 | } | ||
| 129 | |||
| 130 | public Set<Entry<K, List<V>>> entrySet() { | ||
| 131 | return m.entrySet(); | ||
| 132 | } | ||
| 133 | |||
| 134 | public List<V> get(Object key) { | ||
| 135 | if (!caseInsensitive) { | ||
| 136 | return m.get(key); | ||
| 137 | } | ||
| 138 | K realKey = getMatchingKey(key); | ||
| 139 | return realKey == null ? null : m.get(realKey); | ||
| 140 | } | ||
| 141 | |||
| 142 | private K getMatchingKey(Object key) { | ||
| 143 | for (K entry : m.keySet()) { | ||
| 144 | if (entry.toString().equalsIgnoreCase(key.toString())) { | ||
| 145 | return entry; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | return null; | ||
| 149 | } | ||
| 150 | |||
| 151 | public boolean isEmpty() { | ||
| 152 | return m.isEmpty(); | ||
| 153 | } | ||
| 154 | |||
| 155 | public Set<K> keySet() { | ||
| 156 | if (!caseInsensitive) { | ||
| 157 | return m.keySet(); | ||
| 158 | } else { | ||
| 159 | Set<K> set = new TreeSet<K>(new KeyComparator<K>()); | ||
| 160 | set.addAll(m.keySet()); | ||
| 161 | return set; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | public List<V> put(K key, List<V> value) { | ||
| 166 | K realKey = !caseInsensitive ? key : getMatchingKey(key); | ||
| 167 | return m.put(realKey == null ? key : realKey, value); | ||
| 168 | } | ||
| 169 | |||
| 170 | public void putAll(Map<? extends K, ? extends List<V>> map) { | ||
| 171 | if (!caseInsensitive) { | ||
| 172 | m.putAll(map); | ||
| 173 | } else { | ||
| 174 | for (Map.Entry<? extends K, ? extends List<V>> entry : map.entrySet()) { | ||
| 175 | this.put(entry.getKey(), entry.getValue()); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | public List<V> remove(Object key) { | ||
| 181 | if (caseInsensitive) { | ||
| 182 | K realKey = getMatchingKey(key); | ||
| 183 | return m.remove(realKey == null ? key : realKey); | ||
| 184 | } else { | ||
| 185 | return m.remove(key); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | public int size() { | ||
| 190 | return m.size(); | ||
| 191 | } | ||
| 192 | |||
| 193 | public Collection<List<V>> values() { | ||
| 194 | return m.values(); | ||
| 195 | } | ||
| 196 | |||
| 197 | @Override | ||
| 198 | public int hashCode() { | ||
| 199 | return m.hashCode(); | ||
| 200 | } | ||
| 201 | |||
| 202 | @Override | ||
| 203 | public boolean equals(Object o) { | ||
| 204 | return m.equals(o); | ||
| 205 | } | ||
| 206 | |||
| 207 | public String toString() { | ||
| 208 | return m.toString(); | ||
| 209 | } | ||
| 210 | |||
| 211 | private static class KeyComparator<K> implements Comparator<K> { | ||
| 212 | |||
| 213 | public int compare(K k1, K k2) { | ||
| 214 | String s1 = k1.toString(); | ||
| 215 | String s2 = k2.toString(); | ||
| 216 | return s1.compareToIgnoreCase(s2); | ||
| 217 | } | ||
| 218 | |||
| 219 | } | ||
| 220 | |||
| 221 | public void addAll(K key, V... newValues) { | ||
| 222 | this.addAllValues(key, Arrays.asList(newValues)); | ||
| 223 | } | ||
| 224 | |||
| 225 | public void addAll(K key, List<V> newValues) { | ||
| 226 | this.addAllValues(key, newValues); | ||
| 227 | } | ||
| 228 | |||
| 229 | private void addAllValues(K key, List<V> newValues) { | ||
| 230 | if (newValues == null) { | ||
| 231 | throw new NullPointerException("List is empty"); | ||
| 232 | } | ||
| 233 | if (newValues.isEmpty()) { | ||
| 234 | return; | ||
| 235 | } | ||
| 236 | getList(key).addAll(newValues); | ||
| 237 | } | ||
| 238 | |||
| 239 | public void addFirst(K key, V value) { | ||
| 240 | addValue(key, value, false); | ||
| 241 | } | ||
| 242 | |||
| 243 | public boolean equalsIgnoreValueOrder(MultivaluedMap<K, V> map) { | ||
| 244 | Set<K> mapKeys = map.keySet(); | ||
| 245 | if (mapKeys.size() != m.keySet().size()) { | ||
| 246 | return false; | ||
| 247 | } | ||
| 248 | |||
| 249 | for (K key : mapKeys) { | ||
| 250 | List<V> localValues = this.get(key); | ||
| 251 | List<V> mapValues = map.get(key); | ||
| 252 | if (localValues == null || localValues.size() != mapValues.size() || !localValues.containsAll(mapValues)) { | ||
| 253 | return false; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | return true; | ||
| 257 | } | ||
| 258 | |||
| 259 | @Override | ||
| 260 | public void addNoDuplicateValue(K key, V value) { | ||
| 261 | if (!isDuplicate(key, value)) { | ||
| 262 | add(key, value); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | private boolean isDuplicate(K key, V value) { | ||
| 267 | List<V> values = get(key); | ||
| 268 | return values != null && values.contains(value) ? true : false; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | 1 | /** |
TraceSDK/src/com/mobithink/tracesdk/rest/client/MultivaluedMap.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.util.List; | ||
| 4 | import java.util.Map; | ||
| 5 | |||
| 6 | public abstract interface MultivaluedMap<K, V> extends Map<K, List<V>> { | ||
| 7 | |||
| 8 | public abstract void putSingle(K paramK, V paramV); | ||
| 9 | |||
| 10 | public abstract void add(K paramK, V paramV); | ||
| 11 | |||
| 12 | public abstract void addNoDuplicateValue(K paramK, V paramV); | ||
| 13 | |||
| 14 | public abstract V getFirst(K paramK); | ||
| 15 | } |
TraceSDK/src/com/mobithink/tracesdk/rest/client/RESTClient.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.net.URI; | ||
| 4 | import java.util.Date; | ||
| 5 | |||
| 6 | import org.apache.http.cookie.Cookie; | ||
| 7 | |||
| 8 | import com.mobithink.tracesdk.rest.client.HttpExecutor.HTTP_METHOD; | ||
| 9 | |||
| 10 | public class RESTClient extends AbstractClient { | ||
| 11 | |||
| 12 | public static boolean DEBUG = false; | ||
| 13 | |||
| 14 | RequestEntity requestEntity = new RequestEntityImplString(); | ||
| 15 | |||
| 16 | EntityReader<?> entityReader = new EntityReaderImplJSON(); | ||
| 17 | |||
| 18 | HttpExecutor httpExecutor; | ||
| 19 | |||
| 20 | Response response; | ||
| 21 | |||
| 22 | public static RESTClient create(String baseUri) { | ||
| 23 | return new RESTClient(baseUri); | ||
| 24 | } | ||
| 25 | |||
| 26 | public static RESTClient create(URI baseUri) { | ||
| 27 | return new RESTClient(baseUri); | ||
| 28 | } | ||
| 29 | |||
| 30 | protected RESTClient(String baseUri) { | ||
| 31 | super(URI.create(baseUri)); | ||
| 32 | } | ||
| 33 | |||
| 34 | protected RESTClient(URI baseUri) { | ||
| 35 | super(baseUri); | ||
| 36 | } | ||
| 37 | |||
| 38 | public RESTClient path(String path) { | ||
| 39 | uriBuilder.addPath(path); | ||
| 40 | return this; | ||
| 41 | } | ||
| 42 | |||
| 43 | public RESTClient query(String key, Object value) { | ||
| 44 | uriBuilder.addQuery(key, value); | ||
| 45 | return this; | ||
| 46 | } | ||
| 47 | |||
| 48 | public Response get() { | ||
| 49 | handle(HTTP_METHOD.GET); | ||
| 50 | return getResponse(); | ||
| 51 | } | ||
| 52 | |||
| 53 | public Response post() { | ||
| 54 | handle(HTTP_METHOD.POST); | ||
| 55 | return getResponse(); | ||
| 56 | } | ||
| 57 | |||
| 58 | public Response put() { | ||
| 59 | handle(HTTP_METHOD.PUT); | ||
| 60 | return getResponse(); | ||
| 61 | } | ||
| 62 | |||
| 63 | public Response delete() { | ||
| 64 | handle(HTTP_METHOD.DELETE); | ||
| 65 | return getResponse(); | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Do handle request | ||
| 70 | * | ||
| 71 | * @param method | ||
| 72 | */ | ||
| 73 | private void handle(HTTP_METHOD method) { | ||
| 74 | httpExecutor = new HttpExecutor(); | ||
| 75 | this.response = httpExecutor.execute(uriBuilder, method, headers, requestEntity, entityReader); | ||
| 76 | } | ||
| 77 | |||
| 78 | @Override | ||
| 79 | public Response getResponse() { | ||
| 80 | return this.response; | ||
| 81 | } | ||
| 82 | |||
| 83 | @Override | ||
| 84 | public RESTClient type(MediaType ct) { | ||
| 85 | return (RESTClient) super.type(ct); | ||
| 86 | } | ||
| 87 | |||
| 88 | @Override | ||
| 89 | public RESTClient type(String type) { | ||
| 90 | return (RESTClient) super.type(type); | ||
| 91 | } | ||
| 92 | |||
| 93 | @Override | ||
| 94 | public RESTClient accept(MediaType... types) { | ||
| 95 | return (RESTClient) super.accept(types); | ||
| 96 | } | ||
| 97 | |||
| 98 | @Override | ||
| 99 | public RESTClient accept(String... types) { | ||
| 100 | return (RESTClient) super.accept(types); | ||
| 101 | } | ||
| 102 | |||
| 103 | @Override | ||
| 104 | public RESTClient language(String language) { | ||
| 105 | return (RESTClient) super.language(language); | ||
| 106 | } | ||
| 107 | |||
| 108 | @Override | ||
| 109 | public RESTClient acceptLanguage(String... languages) { | ||
| 110 | return (RESTClient) super.acceptLanguage(languages); | ||
| 111 | } | ||
| 112 | |||
| 113 | @Override | ||
| 114 | public RESTClient encoding(String encoding) { | ||
| 115 | return (RESTClient) super.encoding(encoding); | ||
| 116 | } | ||
| 117 | |||
| 118 | @Override | ||
| 119 | public RESTClient acceptEncoding(String... encodings) { | ||
| 120 | return (RESTClient) super.acceptEncoding(encodings); | ||
| 121 | } | ||
| 122 | |||
| 123 | @Override | ||
| 124 | public RESTClient match(String tag, boolean ifNot) { | ||
| 125 | return (RESTClient) super.match(tag, ifNot); | ||
| 126 | } | ||
| 127 | |||
| 128 | @Override | ||
| 129 | public RESTClient modified(Date date, boolean ifNot) { | ||
| 130 | return (RESTClient) super.modified(date, ifNot); | ||
| 131 | } | ||
| 132 | |||
| 133 | @Override | ||
| 134 | public RESTClient cookie(Cookie cookie) { | ||
| 135 | return (RESTClient) super.cookie(cookie); | ||
| 136 | } | ||
| 137 | |||
| 138 | @Override | ||
| 139 | public RESTClient header(String name, Object... values) { | ||
| 140 | return (RESTClient) super.header(name, values); | ||
| 141 | } | ||
| 142 | |||
| 143 | @Override | ||
| 144 | public RESTClient headers(MultivaluedMap<String, String> map) { | ||
| 145 | return (RESTClient) super.headers(map); | ||
| 146 | } | ||
| 147 | |||
| 148 | @Override | ||
| 149 | public RESTClient reset() { | ||
| 150 | return (RESTClient) super.reset(); | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * set a RequestEntity that the request will format params. | ||
| 155 | * | ||
| 156 | * @param requestEntity | ||
| 157 | * @return | ||
| 158 | */ | ||
| 159 | public RESTClient setRequestEntity(RequestEntity requestEntity) { | ||
| 160 | this.requestEntity = requestEntity; | ||
| 161 | return this; | ||
| 162 | } | ||
| 163 | |||
| 164 | /** | ||
| 165 | * Set an EntityReader which to read the response entity and parse it to the target format. | ||
| 166 | * | ||
| 167 | * @param reader | ||
| 168 | * @return | ||
| 169 | */ | ||
| 170 | public RESTClient setEntityReader(EntityReader<?> reader) { | ||
| 171 | this.entityReader = reader; | ||
| 172 | return this; | ||
| 173 | } | ||
| 174 | |||
| 175 | public void close() { | ||
| 176 | if (httpExecutor != null) { | ||
| 177 | httpExecutor.close(); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/RequestEntity.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.io.UnsupportedEncodingException; | ||
| 4 | |||
| 5 | import org.apache.http.HttpEntity; | ||
| 6 | import org.apache.http.entity.StringEntity; | ||
| 7 | import org.apache.http.protocol.HTTP; | ||
| 8 | |||
| 9 | public abstract class RequestEntity { | ||
| 10 | |||
| 11 | public abstract HttpEntity get(UriBuilder uriBuilder, MultivaluedMap<String, String> headers); | ||
| 12 | |||
| 13 | protected StringEntity getStringEntity(String params) { | ||
| 14 | try { | ||
| 15 | return new StringEntity(params, HTTP.UTF_8); | ||
| 16 | } catch (UnsupportedEncodingException e) { | ||
| 17 | e.printStackTrace(); | ||
| 18 | } | ||
| 19 | return null; | ||
| 20 | } | ||
| 21 | } | ||
| 22 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/RequestEntityImplJSON.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import org.apache.http.HttpEntity; | ||
| 4 | |||
| 5 | import android.util.Log; | ||
| 6 | |||
| 7 | import com.mobithink.tracesdk.json.JSONObject; | ||
| 8 | |||
| 9 | public class RequestEntityImplJSON extends RequestEntity { | ||
| 10 | |||
| 11 | @Override | ||
| 12 | public HttpEntity get(UriBuilder uriBuilder, MultivaluedMap<String, String> headers) { | ||
| 13 | String entityStr = new JSONObject(uriBuilder.getQuery()).toString(); | ||
| 14 | return getStringEntity(entityStr); | ||
| 15 | } | ||
| 16 | } | ||
| 17 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/RequestEntityImplString.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import org.apache.http.HttpEntity; | ||
| 4 | |||
| 5 | import android.util.Log; | ||
| 6 | |||
| 7 | public class RequestEntityImplString extends RequestEntity { | ||
| 8 | |||
| 9 | @Override | ||
| 10 | public HttpEntity get(UriBuilder uriBuilder, MultivaluedMap<String, String> headers) { | ||
| 11 | String params = uriBuilder.assambleParams(); | ||
| 12 | Log.d("RequestEntityImplString", "params str:"+params); | ||
| 13 | return getStringEntity(params); | ||
| 14 | } | ||
| 15 | |||
| 16 | } | ||
| 17 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/Response.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | public abstract class Response { | ||
| 4 | |||
| 5 | public static final int ERROR_CLIENT_NETWORK = -100; | ||
| 6 | public static final int ERROR_CLIENT_IO = -200; | ||
| 7 | public static final int ERROR_CLIENT_UNKNOWN = -300; | ||
| 8 | |||
| 9 | public abstract Object getEntity(); | ||
| 10 | |||
| 11 | public abstract int getHttpStatus(); | ||
| 12 | |||
| 13 | public abstract int getErrorCode(); | ||
| 14 | |||
| 15 | public abstract MultivaluedMap<String, Object> getHeaderMetadata(); | ||
| 16 | |||
| 17 | // /////////////////////////////////////////////// | ||
| 18 | |||
| 19 | public abstract String getContentType(); | ||
| 20 | |||
| 21 | public abstract String getContentEncoding(); | ||
| 22 | |||
| 23 | public abstract String getContentLanguage(); | ||
| 24 | |||
| 25 | public abstract String getLocation(); | ||
| 26 | |||
| 27 | public abstract String getContentLocation(); | ||
| 28 | |||
| 29 | public abstract String getETag(); | ||
| 30 | |||
| 31 | public abstract String getLastModified(); | ||
| 32 | |||
| 33 | public abstract String getCacheControl(); | ||
| 34 | |||
| 35 | public abstract String getExpires(); | ||
| 36 | |||
| 37 | public abstract long getExpiresTime(); | ||
| 38 | |||
| 39 | public abstract String getCookie(); | ||
| 40 | |||
| 41 | public abstract String getDebug(); | ||
| 42 | |||
| 43 | } | ||
| 44 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/ResponseImpl.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.text.ParseException; | ||
| 4 | import java.text.SimpleDateFormat; | ||
| 5 | import java.util.Date; | ||
| 6 | |||
| 7 | public final class ResponseImpl extends Response { | ||
| 8 | |||
| 9 | private int httpStatus; | ||
| 10 | private int errorCode; | ||
| 11 | private Object entity; | ||
| 12 | private MultivaluedMap<String, Object> metadata = new MetadataMap<String, Object>(); | ||
| 13 | |||
| 14 | private String debug; | ||
| 15 | |||
| 16 | public void setDebug(String debugStr) { | ||
| 17 | this.debug = debugStr; | ||
| 18 | } | ||
| 19 | |||
| 20 | public String getDebug() { | ||
| 21 | return this.debug; | ||
| 22 | } | ||
| 23 | |||
| 24 | @Override | ||
| 25 | public Object getEntity() { | ||
| 26 | return this.entity; | ||
| 27 | } | ||
| 28 | |||
| 29 | @Override | ||
| 30 | public int getHttpStatus() { | ||
| 31 | return this.httpStatus; | ||
| 32 | } | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public MultivaluedMap<String, Object> getHeaderMetadata() { | ||
| 36 | return this.metadata; | ||
| 37 | } | ||
| 38 | |||
| 39 | @Override | ||
| 40 | public int getErrorCode() { | ||
| 41 | return this.errorCode; | ||
| 42 | } | ||
| 43 | |||
| 44 | protected void setHttpStatus(int s) { | ||
| 45 | this.httpStatus = s; | ||
| 46 | } | ||
| 47 | |||
| 48 | public void setErrorCode(int code) { | ||
| 49 | this.errorCode = code; | ||
| 50 | } | ||
| 51 | |||
| 52 | protected void setEntity(Object paramObject) { | ||
| 53 | this.entity = paramObject; | ||
| 54 | } | ||
| 55 | |||
| 56 | @Override | ||
| 57 | public String getContentType() { | ||
| 58 | return getHeaderValue(HttpHeaders.CONTENT_TYPE).toString(); | ||
| 59 | } | ||
| 60 | |||
| 61 | @Override | ||
| 62 | public String getContentEncoding() { | ||
| 63 | return getHeaderValue(HttpHeaders.CONTENT_ENCODING).toString(); | ||
| 64 | } | ||
| 65 | |||
| 66 | @Override | ||
| 67 | public String getContentLanguage() { | ||
| 68 | return getHeaderValue(HttpHeaders.CONTENT_LANGUAGE).toString(); | ||
| 69 | } | ||
| 70 | |||
| 71 | @Override | ||
| 72 | public String getLocation() { | ||
| 73 | return getHeaderValue(HttpHeaders.LOCATION).toString(); | ||
| 74 | } | ||
| 75 | |||
| 76 | @Override | ||
| 77 | public String getContentLocation() { | ||
| 78 | return getHeaderValue(HttpHeaders.CONTENT_LOCATION).toString(); | ||
| 79 | } | ||
| 80 | |||
| 81 | @Override | ||
| 82 | public String getETag() { | ||
| 83 | return getHeaderValue(HttpHeaders.ETAG).toString(); | ||
| 84 | } | ||
| 85 | |||
| 86 | @Override | ||
| 87 | public String getLastModified() { | ||
| 88 | return getHeaderValue(HttpHeaders.LAST_MODIFIED).toString(); | ||
| 89 | } | ||
| 90 | |||
| 91 | @Override | ||
| 92 | public String getCacheControl() { | ||
| 93 | return getHeaderValue(HttpHeaders.CACHE_CONTROL).toString(); | ||
| 94 | } | ||
| 95 | |||
| 96 | @Override | ||
| 97 | public String getExpires() { | ||
| 98 | return getHeaderValue(HttpHeaders.EXPIRES).toString(); | ||
| 99 | } | ||
| 100 | |||
| 101 | @Override | ||
| 102 | public long getExpiresTime() { | ||
| 103 | String ex = getHeaderValue("Cache-Expires").toString(); | ||
| 104 | if (ex == null || ex.length() == 0) { | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | try { | ||
| 108 | return Long.valueOf(ex) * 1000; | ||
| 109 | } catch (Exception e) { | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | @Override | ||
| 115 | public String getCookie() { | ||
| 116 | return getHeaderValue(HttpHeaders.SET_COOKIE).toString(); | ||
| 117 | } | ||
| 118 | |||
| 119 | public void setHeader(String name, String value) { | ||
| 120 | if (value == null) { | ||
| 121 | metadata.remove(name); | ||
| 122 | } else { | ||
| 123 | metadata.putSingle(name, value.toString()); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | private Object getHeaderValue(String name) { | ||
| 128 | Object value = metadata.getFirst(name); | ||
| 129 | if (value == null) { | ||
| 130 | return ""; | ||
| 131 | } | ||
| 132 | return value; | ||
| 133 | } | ||
| 134 | |||
| 135 | public String toHttpDate(Date date) { | ||
| 136 | SimpleDateFormat format = Utils.getHttpDateFormat(); | ||
| 137 | return format.format(date); | ||
| 138 | } | ||
| 139 | |||
| 140 | public Date toDate(String dateOfGMT) { | ||
| 141 | SimpleDateFormat format = Utils.getHttpDateFormat(); | ||
| 142 | try { | ||
| 143 | return format.parse(dateOfGMT); | ||
| 144 | } catch (ParseException e) { | ||
| 145 | e.printStackTrace(); | ||
| 146 | return null; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | } |
TraceSDK/src/com/mobithink/tracesdk/rest/client/UriBuilder.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.io.UnsupportedEncodingException; | ||
| 4 | import java.net.URI; | ||
| 5 | import java.net.URLEncoder; | ||
| 6 | import java.util.ArrayList; | ||
| 7 | import java.util.Iterator; | ||
| 8 | import java.util.LinkedHashMap; | ||
| 9 | import java.util.List; | ||
| 10 | import java.util.Map.Entry; | ||
| 11 | |||
| 12 | import android.util.Log; | ||
| 13 | |||
| 14 | public class UriBuilder { | ||
| 15 | |||
| 16 | private URI baseUri; | ||
| 17 | private List<String> paths = new ArrayList<String>(); | ||
| 18 | private LinkedHashMap<String, Object> query = new LinkedHashMap<String, Object>(); | ||
| 19 | |||
| 20 | public UriBuilder(URI uri) { | ||
| 21 | this.baseUri = uri; | ||
| 22 | } | ||
| 23 | |||
| 24 | public void addPath(String path) { | ||
| 25 | paths.add(path); | ||
| 26 | } | ||
| 27 | |||
| 28 | public void addQuery(String key, Object value) { | ||
| 29 | query.put(key, value); | ||
| 30 | } | ||
| 31 | |||
| 32 | public URI getBaseUri() { | ||
| 33 | return baseUri; | ||
| 34 | } | ||
| 35 | |||
| 36 | public URI build() { | ||
| 37 | return URI.create(baseUri.toString() + assamblePath()); | ||
| 38 | } | ||
| 39 | |||
| 40 | public URI buildIncludeParams() { | ||
| 41 | return URI.create(baseUri.toString() + assamblePathAndParams()); | ||
| 42 | } | ||
| 43 | |||
| 44 | private String assamblePathAndParams() { | ||
| 45 | StringBuilder strBuilder = new StringBuilder(assamblePath()); | ||
| 46 | String params = assambleParams(); | ||
| 47 | if (params != null && params.length() > 0) { | ||
| 48 | strBuilder.append("?").append(params); | ||
| 49 | } | ||
| 50 | return strBuilder.toString(); | ||
| 51 | } | ||
| 52 | |||
| 53 | private String assamblePath() { | ||
| 54 | if (paths != null && paths.size() > 0) { | ||
| 55 | StringBuilder strBuilder = new StringBuilder(); | ||
| 56 | Iterator<String> iter = paths.iterator(); | ||
| 57 | while (iter.hasNext()) { | ||
| 58 | strBuilder.append("/").append(iter.next()); | ||
| 59 | } | ||
| 60 | return strBuilder.toString(); | ||
| 61 | } | ||
| 62 | return ""; | ||
| 63 | } | ||
| 64 | |||
| 65 | public String assambleParams() { | ||
| 66 | if (query != null && query.size() > 0) { | ||
| 67 | StringBuilder strBuilder = new StringBuilder(); | ||
| 68 | int i = 0; | ||
| 69 | for (Entry<String, Object> entry : query.entrySet()) { | ||
| 70 | if (i > 0) { | ||
| 71 | strBuilder.append("&"); | ||
| 72 | } | ||
| 73 | try { | ||
| 74 | Object v = entry.getValue(); | ||
| 75 | strBuilder.append(entry.getKey()).append("=").append(URLEncoder.encode(v == null ? "" : v.toString(), "utf-8")); | ||
| 76 | } catch (UnsupportedEncodingException e) { | ||
| 77 | e.printStackTrace(); | ||
| 78 | } | ||
| 79 | i++; | ||
| 80 | } | ||
| 81 | return strBuilder.toString(); | ||
| 82 | } | ||
| 83 | return ""; | ||
| 84 | } | ||
| 85 | |||
| 86 | public LinkedHashMap<String, Object> getQuery() { | ||
| 87 | return this.query; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/rest/client/Utils.java
| 1 | package com.mobithink.tracesdk.rest.client; | File was deleted | |
| 2 | |||
| 3 | import java.text.ParseException; | ||
| 4 | import java.text.SimpleDateFormat; | ||
| 5 | import java.util.Date; | ||
| 6 | import java.util.Locale; | ||
| 7 | import java.util.TimeZone; | ||
| 8 | |||
| 9 | public class Utils { | ||
| 10 | |||
| 11 | public static SimpleDateFormat getHttpDateFormat() { | ||
| 12 | SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); | ||
| 13 | TimeZone tZone = TimeZone.getTimeZone("GMT"); | ||
| 14 | dateFormat.setTimeZone(tZone); | ||
| 15 | return dateFormat; | ||
| 16 | } | ||
| 17 | |||
| 18 | public static long GMT2LocaleTime(long time_GMT) { | ||
| 19 | try { | ||
| 20 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); | ||
| 21 | String timeStr_GMT = dateFormat.format(new Date(time_GMT)); | ||
| 22 | dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); | ||
| 23 | Date date = dateFormat.parse(timeStr_GMT); | ||
| 24 | |||
| 25 | dateFormat.setTimeZone(TimeZone.getDefault()); | ||
| 26 | String timeStr_locale = dateFormat.format(date); | ||
| 27 | return dateFormat.parse(timeStr_locale).getTime(); | ||
| 28 | } catch (ParseException e) { | ||
| 29 | e.printStackTrace(); | ||
| 30 | } | ||
| 31 | |||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | public static long getTime(String timeStr) { | ||
| 36 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); | ||
| 37 | try { | ||
| 38 | return dateFormat.parse(timeStr).getTime(); | ||
| 39 | } catch (ParseException e) { | ||
| 40 | e.printStackTrace(); | ||
| 41 | } | ||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | 1 | package com.mobithink.tracesdk.rest.client; |
TraceSDK/src/com/mobithink/tracesdk/utils/LogUtil.java
| 1 | package com.mobithink.tracesdk.utils; | File was deleted | |
| 2 | |||
| 3 | import com.mobithink.tracesdk.Conf; | ||
| 4 | |||
| 5 | import android.util.Log; | ||
| 6 | |||
| 7 | public class LogUtil { | ||
| 8 | |||
| 9 | public static void d(String tag, String msg) { | ||
| 10 | if (Conf.Env.LOG_ON) | ||
| 11 | Log.d(tag, msg); | ||
| 12 | } | ||
| 13 | |||
| 14 | public static void i(String tag, String msg) { | ||
| 15 | if (Conf.Env.LOG_ON) | ||
| 16 | Log.i(tag, msg); | ||
| 17 | } | ||
| 18 | |||
| 19 | public static void w(String tag, String msg) { | ||
| 20 | if (Conf.Env.LOG_ON) | ||
| 21 | Log.w(tag, msg); | ||
| 22 | } | ||
| 23 | |||
| 24 | public static void e(String tag, String msg) { | ||
| 25 | if (Conf.Env.LOG_ON) | ||
| 26 | Log.e(tag, msg); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | 1 | package com.mobithink.tracesdk.utils; |
TraceSDK/src/com/mobithink/tracesdk/utils/Util.java
| 1 | package com.mobithink.tracesdk.utils; | File was deleted | |
| 2 | |||
| 3 | import java.security.MessageDigest; | ||
| 4 | import java.security.NoSuchAlgorithmException; | ||
| 5 | import java.util.UUID; | ||
| 6 | |||
| 7 | import android.bluetooth.BluetoothAdapter; | ||
| 8 | import android.content.Context; | ||
| 9 | import android.net.wifi.WifiInfo; | ||
| 10 | import android.net.wifi.WifiManager; | ||
| 11 | import android.provider.Settings; | ||
| 12 | import android.provider.Settings.Secure; | ||
| 13 | import android.telephony.TelephonyManager; | ||
| 14 | import android.text.TextUtils; | ||
| 15 | |||
| 16 | public class Util { | ||
| 17 | |||
| 18 | public static String getIMEI(Context context) { | ||
| 19 | TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); | ||
| 20 | String imei = tm.getDeviceId(); | ||
| 21 | return imei; | ||
| 22 | } | ||
| 23 | |||
| 24 | public static String getMacAddr(Context context) { | ||
| 25 | WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); | ||
| 26 | if (wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED) | ||
| 27 | return wm.getConnectionInfo().getMacAddress(); | ||
| 28 | else | ||
| 29 | return ""; | ||
| 30 | } | ||
| 31 | |||
| 32 | public static String getAndroidId(Context context) { | ||
| 33 | // fetch androidId | ||
| 34 | String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID); | ||
| 35 | return androidId; | ||
| 36 | } | ||
| 37 | |||
| 38 | public static String getUniqueId(Context context) { | ||
| 39 | String did = Settings.System.getString(context.getContentResolver(), "deviceId"); | ||
| 40 | if (did == null || did.length() == 0) { | ||
| 41 | try { | ||
| 42 | // fetch imei | ||
| 43 | TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); | ||
| 44 | String imei = tm.getDeviceId(); | ||
| 45 | String simSN = tm.getSimSerialNumber(); | ||
| 46 | // fetch bluetooth mac addr | ||
| 47 | BluetoothAdapter m_BluetoothAdapter = null; // Local Bluetooth | ||
| 48 | // adapter | ||
| 49 | m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); | ||
| 50 | String BTMAC = m_BluetoothAdapter.getAddress(); | ||
| 51 | // fetch wifi mac | ||
| 52 | WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); | ||
| 53 | WifiInfo wifiInf = wifiMan.getConnectionInfo(); | ||
| 54 | |||
| 55 | String macAddr = wifiInf.getMacAddress(); | ||
| 56 | if (macAddr != null) { | ||
| 57 | macAddr = macAddr.replace(":", ""); | ||
| 58 | } | ||
| 59 | // fetch androidId | ||
| 60 | String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID); | ||
| 61 | |||
| 62 | String figureStr = imei + simSN + BTMAC + macAddr + androidId; | ||
| 63 | if (!TextUtils.isEmpty(figureStr)) | ||
| 64 | did = md5(figureStr); | ||
| 65 | else | ||
| 66 | did = UUID.randomUUID().toString(); | ||
| 67 | Settings.System.putString(context.getContentResolver(), "deviceId", did); | ||
| 68 | } catch (Exception ex) { | ||
| 69 | ex.printStackTrace(); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | return did; | ||
| 73 | } | ||
| 74 | |||
| 75 | public static String md5(String input) { | ||
| 76 | MessageDigest m = null; | ||
| 77 | try { | ||
| 78 | m = MessageDigest.getInstance("MD5"); | ||
| 79 | } catch (NoSuchAlgorithmException e) { | ||
| 80 | e.printStackTrace(); | ||
| 81 | } | ||
| 82 | m.update(input.getBytes(), 0, input.length()); | ||
| 83 | byte p_md5Data[] = m.digest(); | ||
| 84 | |||
| 85 | String mOutput = new String(); | ||
| 86 | for (int i = 0; i < p_md5Data.length; i++) { | ||
| 87 | int b = (0xFF & p_md5Data[i]); | ||
| 88 | // if it is a single digit, make sure it have 0 in front (proper | ||
| 89 | // padding) | ||
| 90 | if (b <= 0xF) | ||
| 91 | mOutput += "0"; | ||
| 92 | // add number to string | ||
| 93 | mOutput += Integer.toHexString(b); | ||
| 94 | } | ||
| 95 | // hex string to uppercase | ||
| 96 | return mOutput.toUpperCase(); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | 1 | package com.mobithink.tracesdk.utils; |