You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by lo...@apache.org on 2013/06/19 20:32:19 UTC
[28/36] [CB-3401] renamed blackberry root folder to bbos
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/041e4481/bbos/framework/ext/src/org/apache/cordova/globalization/Globalization.java
----------------------------------------------------------------------
diff --git a/bbos/framework/ext/src/org/apache/cordova/globalization/Globalization.java b/bbos/framework/ext/src/org/apache/cordova/globalization/Globalization.java
new file mode 100644
index 0000000..e6aaae5
--- /dev/null
+++ b/bbos/framework/ext/src/org/apache/cordova/globalization/Globalization.java
@@ -0,0 +1,558 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.globalization;
+
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONObject;
+
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+
+import net.rim.device.api.i18n.Locale;
+import net.rim.device.api.i18n.SimpleDateFormat;
+import net.rim.device.api.util.TimeZoneUtilities;
+import javax.microedition.global.Formatter;
+
+import java.util.Date;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.lang.Long;
+
+public class Globalization extends Plugin {
+
+ /**
+ * Executes the requested action and returns a PluginResult.
+ *
+ * @param action
+ * The action to execute.
+ * @param data
+ * JSONArry of arguments for the action.
+ * @param callbackId
+ * The callback ID to be invoked upon action completion
+ * @return A PluginResult object with a status and message.
+ */
+ public PluginResult execute(String action, JSONArray data, String callbackId) {
+ JSONObject obj = new JSONObject();
+
+ try {
+ if (action.equals(Resources.GETLOCALENAME)) {
+ obj = getLocaleName();
+ } else if (action.equals(Resources.GETPREFERREDLANGUAGE)) {
+ obj = getPreferredLanguage();
+ } else if (action.equalsIgnoreCase(Resources.DATETOSTRING)) {
+ obj = getDateToString(data);
+ } else if (action.equalsIgnoreCase(Resources.STRINGTODATE)) {
+ obj = getStringToDate(data);
+ } else if (action.equalsIgnoreCase(Resources.GETDATEPATTERN)) {
+ obj = getDatePattern(data);
+ } else if (action.equalsIgnoreCase(Resources.GETDATENAMES)) {
+ obj = getDateNames(data);
+ } else if (action.equalsIgnoreCase(Resources.ISDAYLIGHTSAVINGSTIME)) {
+ obj = getIsDayLightSavingsTime(data);
+ } else if (action.equalsIgnoreCase(Resources.GETFIRSTDAYOFWEEK)) {
+ obj = getFirstDayOfWeek(data);
+ } else if (action.equalsIgnoreCase(Resources.NUMBERTOSTRING)) {
+ obj = getNumberToString(data);
+ } else if (action.equalsIgnoreCase(Resources.STRINGTONUMBER)) {
+ obj = getStringToNumber(data);
+ } else if (action.equalsIgnoreCase(Resources.GETNUMBERPATTERN)) {
+ obj = getNumberPattern(data);
+ } else if (action.equalsIgnoreCase(Resources.GETCURRENCYPATTERN)) {
+ obj = getCurrencyPattern(data);
+ } else {
+ return new PluginResult(PluginResult.Status.INVALID_ACTION);
+ }
+ } catch (GlobalizationError ge) {
+ return new PluginResult(PluginResult.Status.ERROR, ge.toJson());
+ } catch (Exception e) {
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+ }
+
+ return new PluginResult(PluginResult.Status.OK, obj);
+ }
+
+ /**
+ * Returns the string identifier for the client's current locale setting.
+ *
+ * @return JSONObject Object.value {String}: The locale identifier
+ *
+ * @throws GlobalizationError.UNKNOWN_ERROR
+ */
+ private JSONObject getLocaleName() throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ return obj.put("value", Locale.getDefault().toString());
+ } catch (Exception e) {
+ throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+ }
+ }
+
+ /**
+ * Returns the string identifier for the client's current language
+ *
+ * @return JSONObject Object.value {String}: The language identifier
+ *
+ * @throws GlobalizationError.UNKNOWN_ERROR
+ */
+ private JSONObject getPreferredLanguage() throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ return obj.put("value", Locale.getDefault().getDisplayLanguage()
+ .toString());
+ } catch (Exception e) {
+ throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+ }
+ }
+
+ /**
+ * Returns a date formatted as a string according to the client's user
+ * preferences and calendar using the time zone of the client.
+ *
+ * @return JSONObject Object.value {String}: The localized date string
+ *
+ * @throws GlobalizationError.FORMATTING_ERROR
+ */
+ private JSONObject getDateToString(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ Date date = new Date(Long.parseLong(options.getJSONObject(0)
+ .get(Resources.DATE).toString()));
+ // get formatting pattern from BB device
+ SimpleDateFormat fmt = new SimpleDateFormat(
+ Util.getBlackBerryDatePattern(options));
+
+ // return formatted date
+ return obj.put("value", fmt.format(date));
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
+ }
+ }
+
+ /**
+ * Parses a date formatted as a string according to the client's user
+ * preferences and calendar using the time zone of the client and returns
+ * the corresponding date object
+ *
+ * @return JSONObject
+ * Object.year {Number}: The four digit year
+ * Object.month {Number}: The month from (0 - 11)
+ * Object.day {Number}: The day from (1 - 31)
+ * Object.hour {Number}: The hour from (0 - 23)
+ * Object.minute {Number}: The minute from (0 - 59)
+ * Object.second {Number}: The second from (0 - 59)
+ * Object.millisecond {Number}: The milliseconds (from 0 - 999),
+ * not available on all platforms
+ *
+ * @throws GlobalizationError.PARSING_ERROR
+ */
+ private JSONObject getStringToDate(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ // get formatting pattern from BB device
+ SimpleDateFormat fmt = new SimpleDateFormat(
+ Util.getBlackBerryDatePattern(options));
+
+ // Manually parse string based on user preferences or Locale default
+ String userDate = options.getJSONObject(0)
+ .get(Resources.DATESTRING).toString().trim();
+
+ Calendar date = Util.dateParserBB(userDate, fmt.toPattern());
+ if (date == null) { // date was unparsable
+ throw new Exception();
+ }
+
+ // return properties;
+ obj.put("year", date.get(Calendar.YEAR));
+ obj.put("month", date.get(Calendar.MONTH)); // returns 0-11
+ obj.put("day", date.get(Calendar.DAY_OF_MONTH));
+ obj.put("hour", date.get(Calendar.HOUR));
+ obj.put("minute", date.get(Calendar.MINUTE));
+ obj.put("second", date.get(Calendar.SECOND));
+ obj.put("millisecond", date.get(Calendar.MILLISECOND));
+ return obj;
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
+ }
+ }
+
+ /**
+ * Returns a pattern string for formatting and parsing dates according to
+ * the client's user preferences.
+ *
+ * @return JSONObject
+ * Object.pattern {String}: The date and time pattern for
+ * formatting and parsing dates. The patterns follow
+ * Unicode Technical Standard #35
+ * http://unicode.org/reports/tr35/tr35-4.html
+ * Object.timezone {String}: The abbreviated name of the time
+ * zone on the client
+ * Object.utc_offset {Number}: The current difference in seconds
+ * between the client's time zon and coordinated universal
+ * time.
+ * Object.dst_offset {Number}: The current daylight saving time
+ * offset in seconds between the client's non-daylight
+ * saving's time zone and the client's daylight saving's
+ * time zone.
+ *
+ * @throws GlobalizationError.PATTERN_ERROR
+ */
+ private JSONObject getDatePattern(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ // TimeZone from users device
+ TimeZone tz = Calendar.getInstance().getTimeZone();
+
+ // Daylight
+ boolean daylight = tz.useDaylightTime();
+
+ // set dst_offset
+ int dst_offset = 0; // defaulted to zero
+ if (daylight) {
+ Calendar c = Calendar.getInstance();
+ dst_offset = (tz.getOffset(1, c.get(Calendar.YEAR),
+ c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH),
+ c.get(Calendar.DAY_OF_WEEK),
+ c.get(Calendar.MILLISECOND))) / 1000;
+ }
+
+ obj.put("pattern", Util.getBlackBerryDatePattern(options));
+ obj.put("timezone", TimeZoneUtilities.getDisplayName(tz,
+ TimeZoneUtilities.SHORT));
+ obj.put("utc_offset", tz.getRawOffset() / 1000);
+ obj.put("dst_offset", dst_offset);
+ return obj;
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
+ }
+ }
+
+ /**
+ * Returns an array of either the names of the months or days of the week
+ * according to the client's user preferences and calendar
+ *
+ * @return JSONObject
+ * Object.value {Array{String}}: The array of names starting from
+ * either the first month in the year or the first day
+ * of the week.
+ *
+ * @throws GlobalizationError.UNKNOWN_ERROR
+ */
+ private JSONObject getDateNames(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ JSONArray value = new JSONArray();
+ try {
+ int type = 0; // default wide
+ int item = 0; // default months
+
+ // get options if available
+ if (options.getJSONObject(0).length() > 0) {
+ // get type if available
+ if (!((JSONObject) options.getJSONObject(0).get(
+ Resources.OPTIONS)).isNull(Resources.TYPE)) {
+ String t = (String) ((JSONObject) options.getJSONObject(0)
+ .get(Resources.OPTIONS)).get(Resources.TYPE);
+ if (t.equalsIgnoreCase(Resources.NARROW)) {
+ type++;
+ } // DateUtils.LENGTH_MEDIUM
+ }
+ // get item if available
+ if (!((JSONObject) options.getJSONObject(0).get(
+ Resources.OPTIONS)).isNull(Resources.ITEM)) {
+ String t = (String) ((JSONObject) options.getJSONObject(0)
+ .get(Resources.OPTIONS)).get(Resources.ITEM);
+ if (t.equalsIgnoreCase(Resources.DAYS)) {
+ item += 10;
+ } // Days of week start at 1
+ }
+ }
+ // determine return value
+
+ int method = item + type;
+ if (method == 1) {
+ value = Util.getDateNameString(Resources.MONTHS, "MMM");
+ }// months and narrow
+ else if (method == 10) {
+ value = Util.getDateNameString(Resources.DAYS, "EEEE");
+ }// days and wide
+ else if (method == 11) {
+ value = Util.getDateNameString(Resources.DAYS, "EEE");
+ }// days and narrow
+ else {
+ value = Util.getDateNameString(Resources.MONTHS, "MMMM");
+ }// default: months and wide
+
+ if (value == null) {
+ throw new Exception();
+ }
+
+ // return array of names
+ return obj.put("value", value);
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+ }
+ }
+
+ /**
+ * Returns whether daylight savings time is in effect for a given date using
+ * the client's time zone and calendar.
+ *
+ * @return JSONObject
+ * Object.dst {Boolean}: The value "true" indicates that daylight
+ * savings time is in effect for the given date and
+ * "false" indicates that it is not.
+ *
+ * @throws GlobalizationError.UNKNOWN_ERROR
+ *
+ * Note: Functionality to determine if date is within day light
+ * savings time is not available in this API version
+ */
+ private JSONObject getIsDayLightSavingsTime(JSONArray options)
+ throws GlobalizationError {
+ throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+ }
+
+ /**
+ * Returns the first day of the week according to the client's user
+ * preferences and calendar. The days of the week are numbered starting from
+ * 1 where 1 is considered to be Sunday.
+ *
+ * @return JSONObject
+ * Object.value {Number}: The number of the first day of the week.
+ *
+ * @throws GlobalizationError.UNKNOWN_ERROR
+ */
+ private JSONObject getFirstDayOfWeek(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ JSONObject result = Util.getLocaleData(Locale.getDefault()
+ .toString());
+
+ if (result == null || result.length() <= 0) {
+ throw new Exception();
+ }
+ return obj.put("value", Integer.valueOf(result
+ .getString(Resources.JSON_FIRISTDAYOFWEEK)));
+ } catch (Exception e) {
+ throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+ }
+ }
+
+ /**
+ * Returns a number formatted as a string according to the client's user
+ * preferences.
+ *
+ * @return JSONObject
+ * Object.value {String}: The formatted number string.
+ *
+ * @throws GlobalizationError.FORMATTING_ERROR
+ */
+ private JSONObject getNumberToString(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ String value;
+ try {
+ // Initialize formatter
+ Formatter fmt = new Formatter(Locale.getDefault().toString());
+
+ // obtain user supplied number
+ double num = Double.parseDouble(options.getJSONObject(0)
+ .get(Resources.NUMBER).toString());
+ // format based on options if available
+ value = fmt.formatNumber(num);
+ if (options.getJSONObject(0).length() > 1) {
+ // options were included
+ if (!((JSONObject) options.getJSONObject(0).get(
+ Resources.OPTIONS)).isNull(Resources.TYPE)) {
+ String fmtOpt = (String) ((JSONObject) options
+ .getJSONObject(0).get(Resources.OPTIONS))
+ .get(Resources.TYPE);
+ if (fmtOpt.equalsIgnoreCase(Resources.CURRENCY)) {
+ value = fmt.formatCurrency(num);
+ } else if (fmtOpt.equalsIgnoreCase(Resources.PERCENT)) {
+ // convert double to long
+ // used 1 decimal places as a default
+ value = fmt.formatPercentage((float) num, 1);
+ }
+ }
+ }
+ return obj.put("value", value);
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
+ }
+
+ }
+
+ /**
+ * Parses a number formatted as a string according to the client's user
+ * preferences and returns the corresponding number.
+ *
+ * @return JSONObject
+ * Object.value {Number}: The parsed number.
+ *
+ * @throws GlobalizationError.PARSING_ERROR
+ */
+ private JSONObject getStringToNumber(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ double value = 0;
+ try {
+ // format based on options if available
+ String num = options.getJSONObject(0).get(Resources.NUMBERSTRING)
+ .toString().trim();
+ if (options.getJSONObject(0).length() > 1) {
+ // options were included
+ if (!((JSONObject) options.getJSONObject(0).get(
+ Resources.OPTIONS)).isNull(Resources.TYPE)) {
+ String fmtOpt = (String) ((JSONObject) options
+ .getJSONObject(0).get(Resources.OPTIONS))
+ .get(Resources.TYPE);
+ // remove unwanted symbols
+ if (fmtOpt.equalsIgnoreCase(Resources.CURRENCY)) {
+ value = (Double.parseDouble(Util.removeSymbols(num)));
+ } else if (fmtOpt.equalsIgnoreCase(Resources.PERCENT)) {
+ value = (Double.parseDouble(Util.removeSymbols(num)) / 100);
+ }
+ }
+ } else {
+ value = Double.parseDouble(num); // decimal default
+ }
+
+ return obj.put("value", value);
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
+ }
+ }
+
+ /**
+ * Returns a pattern string for formatting and parsing numbers according to
+ * the client's user preferences.
+ *
+ * @return JSONObject
+ * Object.pattern {String}: The number pattern for formatting and
+ * parsing numbers. The patterns follow Unicode
+ * Technical Standard #35.
+ * http://unicode.org/reports/tr35/tr35-4.html
+ * Object.symbol {String}: The symbol to be used when formatting
+ * and parsing e.g., percent or currency symbol.
+ * Object.fraction {Number}: The number of fractional digits to use
+ * when parsing and formatting numbers.
+ * Object.rounding {Number}: The rounding increment to use when
+ * parsing and formatting.
+ * Object.positive {String}: The symbol to use for positive numbers
+ * when parsing and formatting.
+ * Object.negative: {String}: The symbol to use for negative
+ * numbers when parsing and formatting.
+ * Object.decimal: {String}: The decimal symbol to use for parsing
+ * and formatting.
+ * Object.grouping: {String}: The grouping symbol to use for
+ * parsing and formatting.
+ *
+ * @throws GlobalizationError.PATTERN_ERROR
+ */
+ private JSONObject getNumberPattern(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ JSONObject result = Util.getLocaleData(Locale.getDefault()
+ .toString());
+
+ String symbol = Resources.JSON_DECIMALSYMBOL;
+ // get Date value + options (if available)
+ if (options.getJSONObject(0).length() > 0) {
+ // options were included
+ if (!((JSONObject) options.getJSONObject(0).get(
+ Resources.OPTIONS)).isNull(Resources.TYPE)) {
+ String fmtOpt = (String) ((JSONObject) options
+ .getJSONObject(0).get(Resources.OPTIONS))
+ .get(Resources.TYPE);
+ if (fmtOpt.equalsIgnoreCase(Resources.CURRENCY)) {
+ symbol = Resources.JSON_CURRENCYSYMBOL;
+ } else if (fmtOpt.equalsIgnoreCase(Resources.PERCENT)) {
+ symbol = Resources.JSON_PERCENTSYMBOL;
+ }
+ }
+ }
+
+ // return properties
+ obj.put("pattern", result.getString(Resources.JSON_PATTERN));
+ obj.put("symbol", result.getString(symbol));
+ obj.put("fraction",
+ Integer.valueOf(result.getString(Resources.JSON_FRACTION)));
+ obj.put("rounding",
+ Integer.valueOf(result.getString(Resources.JSON_ROUNDING)));
+ obj.put("positive", result.getString(Resources.JSON_POSITIVE));
+ obj.put("negative", result.getString(Resources.JSON_NEGATIVE));
+ obj.put("decimal", result.getString(Resources.JSON_DECIMALSYMBOL));
+ obj.put("grouping", result.getString(Resources.JSON_GROUPING));
+ return obj;
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
+ }
+ }
+
+ /**
+ * Returns a pattern string for formatting and parsing currency values
+ * according to the client's user preferences and ISO 4217 currency code.
+ *
+ * @return JSONObject =
+ * Object.pattern {String}: The currency pattern for formatting and
+ * parsing currency values. The patterns follow
+ * Unicode Technical Standard #35
+ * http://unicode.org/reports/tr35/tr35-4.html
+ * Object.code {String}: The ISO 4217 currency code for the pattern.
+ * Object.fraction {Number}: The number of fractional digits to use
+ * when parsing and formatting currency.
+ * Object.rounding {Number}: The rounding increment to use when
+ * parsing and formatting.
+ * Object.decimal: {String}: The decimal symbol to use for parsing
+ * and formatting.
+ * Object.grouping: {String}: The grouping symbol to use for
+ * parsing and formatting.
+ *
+ * @throws GlobalizationError.FORMATTING_ERROR
+ */
+ private JSONObject getCurrencyPattern(JSONArray options)
+ throws GlobalizationError {
+ JSONObject obj = new JSONObject();
+ try {
+ JSONObject result = Util.getCurrencyData(Locale.getDefault()
+ .toString(),
+ options.getJSONObject(0).getString(Resources.CURRENCYCODE));
+
+ // return properties
+ obj.put("pattern", result.getString(Resources.JSON_CURRENCYPATTERN));
+ obj.put("code", result.getString(Resources.JSON_CURRENCYCODE));
+ obj.put("fraction", Integer.valueOf(result
+ .getString(Resources.JSON_CURRENCYFRACTION)));
+ obj.put("rounding", Integer.valueOf(result
+ .getString(Resources.JSON_CURRENCYROUNDING)));
+ obj.put("decimal", result.getString(Resources.JSON_CURRENCYDECIMAL));
+ obj.put("grouping",
+ result.getString(Resources.JSON_CURRENCYGROUPING));
+ return obj;
+ } catch (Exception ge) {
+ throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/041e4481/bbos/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java
----------------------------------------------------------------------
diff --git a/bbos/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java b/bbos/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java
new file mode 100644
index 0000000..b2a9388
--- /dev/null
+++ b/bbos/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.globalization;
+
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.json4j.JSONObject;
+
+/**
+ * User initiated exception. Exception class representing defined Globalization
+ * error codes.
+ *
+ * Globalization error codes:
+ * GlobalizationError.UNKNOWN_ERROR = 0;
+ * GlobalizationError.FORMATTING_ERROR = 1;
+ * GlobalizationError.PARSING_ERROR = 2;
+ * GlobalizationError.PATTERN_ERROR = 3;
+ */
+public class GlobalizationError extends Exception {
+
+ private static final long serialVersionUID = 1L;
+ public static final String UNKNOWN_ERROR = "UNKNOWN_ERROR";
+ public static final String FORMATTING_ERROR = "FORMATTING_ERROR";
+ public static final String PARSING_ERROR = "PARSING_ERROR";
+ public static final String PATTERN_ERROR = "PATTERN_ERROR";
+
+ int error = 0; // default unknown error thrown
+
+ /**
+ * Default constructor
+ */
+ public GlobalizationError() {
+ }
+
+ /**
+ * Create an exception returning an error code
+ *
+ * @param s
+ */
+ public GlobalizationError(String s) {
+ if (s.equalsIgnoreCase(FORMATTING_ERROR)) {
+ error = 1;
+ } else if (s.equalsIgnoreCase(PARSING_ERROR)) {
+ error = 2;
+ } else if (s.equalsIgnoreCase(PATTERN_ERROR)) {
+ error = 3;
+ }
+ }
+
+ /**
+ * get error string based on error code
+ *
+ * @param String
+ * msg
+ */
+ public String getErrorString() {
+ String msg = "";
+ switch (error) {
+ case 0:
+ msg = UNKNOWN_ERROR;
+ break;
+ case 1:
+ msg = FORMATTING_ERROR;
+ break;
+ case 2:
+ msg = PARSING_ERROR;
+ break;
+ case 3:
+ msg = PATTERN_ERROR;
+ break;
+ }
+ return msg;
+ }
+
+ /**
+ * get error code
+ *
+ * @param String
+ * msg
+ */
+ public int getErrorCode() {
+ return error;
+ }
+
+ /**
+ * get the json version of this object to return to javascript
+ *
+ * @return
+ */
+ public JSONObject toJson() {
+ JSONObject obj = new JSONObject();
+ try {
+ obj.put("code", getErrorCode());
+ obj.put("message", getErrorString());
+ } catch (JSONException e) {
+ // never happens
+ }
+ return obj;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/041e4481/bbos/framework/ext/src/org/apache/cordova/globalization/Resources.java
----------------------------------------------------------------------
diff --git a/bbos/framework/ext/src/org/apache/cordova/globalization/Resources.java b/bbos/framework/ext/src/org/apache/cordova/globalization/Resources.java
new file mode 100644
index 0000000..02cbc8a
--- /dev/null
+++ b/bbos/framework/ext/src/org/apache/cordova/globalization/Resources.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.globalization;
+
+public class Resources {
+ // Globalization Plugin Actions
+ public static final String GETLOCALENAME = "getLocaleName";
+ public static final String DATETOSTRING = "dateToString";
+ public static final String STRINGTODATE = "stringToDate";
+ public static final String GETDATEPATTERN = "getDatePattern";
+ public static final String GETDATENAMES = "getDateNames";
+ public static final String ISDAYLIGHTSAVINGSTIME = "isDayLightSavingsTime";
+ public static final String GETFIRSTDAYOFWEEK = "getFirstDayOfWeek";
+ public static final String NUMBERTOSTRING = "numberToString";
+ public static final String STRINGTONUMBER = "stringToNumber";
+ public static final String GETNUMBERPATTERN = "getNumberPattern";
+ public static final String GETCURRENCYPATTERN = "getCurrencyPattern";
+ public static final String GETPREFERREDLANGUAGE = "getPreferredLanguage";
+
+ // Globalization Option Parameters
+ public static final String OPTIONS = "options";
+ public static final String FORMATLENGTH = "formatLength";
+ public static final String MEDIUM = "medium";
+ public static final String LONG = "long";
+ public static final String FULL = "full";
+ public static final String SELECTOR = "selector";
+ public static final String DATE = "date";
+ public static final String TIME = "time";
+ public static final String DATESTRING = "dateString";
+ public static final String TYPE = "type";
+ public static final String ITEM = "item";
+ public static final String NARROW = "narrow";
+ public static final String WIDE = "wide";
+ public static final String MONTHS = "months";
+ public static final String DAYS = "days";
+ public static final String SPACE = " ";
+ public static final String DATEDELIMITER = "-";
+ public static final String TIMEDELIMITER = ":";
+ public static final String[] AM_PMFORMATS = { "a", "aa" };
+ public static final String NUMBER = "number";
+ public static final String NUMBERSTRING = "numberString";
+ public static final String PERCENT = "percent";
+ public static final String CURRENCY = "currency";
+ public static final String CURRENCYCODE = "currencyCode";
+
+ // JSON File: JSONObject
+ public static final String JSON_CURRENCY = "currency";
+ public static final String JSON_LOCALE = "locale";
+ public static final String JSON_NAME = "name";
+
+ // JSON File: parameters
+ // locale:
+ public static final String JSON_PATTERN = "pattern";
+ public static final String JSON_DECIMAL = "decimal";
+ public static final String JSON_FRACTION = "fraction";
+ public static final String JSON_ROUNDING = "rounding";
+ public static final String JSON_GROUPING = "grouping";
+ public static final String JSON_NEGATIVE = "negative";
+ public static final String JSON_FIRISTDAYOFWEEK = "firstDayOfWeek";
+ public static final String JSON_POSITIVE = "positive";
+ public static final String JSON_PERCENTSYMBOL = "percentSymbol";
+ public static final String JSON_CURRENCYSYMBOL = "currencySymbol";
+ public static final String JSON_DECIMALSYMBOL = "decimalSymbol";
+ public static final String JSON_DISPLAYNAME = "displayName";
+
+ // currency
+ public static final String JSON_CURRENCYCODE = "currencyCode";
+ public static final String JSON_CURRENCYPATTERN = "currencyPattern";
+ public static final String JSON_CURRENCYDECIMAL = "currencyDecimal";
+ public static final String JSON_CURRENCYFRACTION = "currencyFraction";
+ public static final String JSON_CURRENCYGROUPING = "currencyGrouping";
+ public static final String JSON_CURRENCYROUNDING = "currencyRounding";
+
+ // class paths:
+ public static final String LOCALEINFOPATH = "/res/resourceBundles/";
+ public static final String LOCALEINFOPATHEND = ".js.gz";
+
+ // locale resource key identifiers
+ public static final int LOCALENAME = 0;
+
+ // Persistent Store ID:
+ public static final long PERSISTENTSTORE_ID = 0x10001;
+}
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/041e4481/bbos/framework/ext/src/org/apache/cordova/globalization/Util.java
----------------------------------------------------------------------
diff --git a/bbos/framework/ext/src/org/apache/cordova/globalization/Util.java b/bbos/framework/ext/src/org/apache/cordova/globalization/Util.java
new file mode 100644
index 0000000..340876e
--- /dev/null
+++ b/bbos/framework/ext/src/org/apache/cordova/globalization/Util.java
@@ -0,0 +1,721 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.globalization;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.TimeZone;
+
+import net.rim.device.api.i18n.DateFormat;
+import net.rim.device.api.i18n.Locale;
+import net.rim.device.api.i18n.SimpleDateFormat;
+import net.rim.device.api.system.NonPersistableObjectException;
+import net.rim.device.api.system.PersistentObject;
+import net.rim.device.api.system.PersistentStore;
+import net.rim.device.api.util.StringMatch;
+import net.rim.device.api.util.StringUtilities;
+import net.rim.device.api.compress.GZIPInputStream;
+
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONObject;
+import org.apache.cordova.json4j.internal.Parser;
+import org.apache.cordova.util.StringUtils;
+import org.apache.cordova.util.Logger;
+
+public class Util {
+
+ /**
+ * Provides manual date string parsing
+ *
+ * @param d
+ * Date string
+ * @param p
+ * Pattern string
+ * @return Calendar
+ */
+ public static Calendar dateParserBB(String d, String p) {
+ String time = "";
+ String date = d;
+ String delimiter = Resources.DATEDELIMITER; // "-"
+ try {
+ // replace '/' with '-' (to compensate for delimiters '/' and '-' in
+ // string)
+ date = date.replace('/', '-');
+
+ // extract time first
+ if (date.indexOf(':') > 0) {
+ time = date.substring(date.indexOf(':') - 2, date.length())
+ .trim();
+ date = date.substring(0, date.indexOf(':') - 2).trim();
+ }
+
+ // determine string delimiter
+ if (date.indexOf(delimiter) == -1) { // is not in short format
+ delimiter = Resources.SPACE; // " "
+ }
+
+ // split date into sections
+ JSONArray str = Util.split(date, delimiter);
+ if (str == null) {
+ throw new Exception(); // incorrect format
+ }
+
+ // remove day of week and other unwanted characters -- will
+ // automatically be set in calendar object
+ str = Util.removeDayOfWeek(str);
+
+ // convert month string into integer: if applicable
+ str = Util.convertMonthString(str);
+
+ // use pattern to determine order of dd, mm, yyyy. If no pattern
+ // will use Locale Default order
+ Hashtable patternFmt = Util.getDatePattern(p);
+
+ // create calendar object
+ Calendar c = Calendar.getInstance(TimeZone.getDefault());
+
+ // set calendar instance:
+ c.set(Calendar.YEAR, Integer.parseInt(removeSymbols(str
+ .getString(Integer.parseInt(patternFmt.get("year")
+ .toString())))));
+ c.set(Calendar.MONTH, Integer.parseInt(removeSymbols(str
+ .getString(Integer.parseInt(patternFmt.get("month")
+ .toString())))));
+ c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(removeSymbols(str
+ .getString(Integer.parseInt(patternFmt.get("day")
+ .toString())))));
+
+ // set time if applicable
+ if (time.length() > 0) {
+ JSONArray t = Util.split(time, Resources.TIMEDELIMITER);
+ // determine if 12hour or 24hour clock
+ int am_pm = getAmPm(t.getString(t.length() - 1).toString());
+ if (!t.isNull(0)) {
+ c.set(Calendar.HOUR,
+ Integer.parseInt(removeSymbols(t.getString(0))));
+ }
+ if (!t.isNull(1)) {
+ c.set(Calendar.MINUTE,
+ Integer.parseInt(removeSymbols(t.getString(1))));
+ }
+ if (!t.isNull(2)) {
+ c.set(Calendar.SECOND,
+ Integer.parseInt(removeSymbols(t.getString(2))));
+ }
+ if (am_pm != -1) {
+ c.set(Calendar.AM_PM, am_pm);
+ }
+ }
+ return c;
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ /**
+ * Returns a pattern string for formatting and parsing dates according to
+ * the client's user preferences.
+ *
+ * @param options
+ * JSONArray options (user pattern)
+ *
+ * @return String (String}: The date and time pattern for formatting and
+ * parsing dates. The patterns follow Unicode Technical Standard #35
+ * http://unicode.org/reports/tr35/tr35-4.html
+ *
+ * @throws GlobalizationError
+ */
+ public static String getBlackBerryDatePattern(JSONArray options)
+ throws GlobalizationError {
+
+ try {
+ // default user preference for date
+ String fmtDate = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.DATE_SHORT)).toPattern();
+ // default user preference for time
+ String fmtTime = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.TIME_SHORT)).toPattern();
+ // default SHORT date/time format. ex. dd/MM/yyyy h:mma
+ String fmt = fmtDate + Resources.SPACE + fmtTime;
+
+ // get Date value + options (if available)
+ if (options.getJSONObject(0).length() > 1) {
+ // options were included. get formatLength option
+ if (!((JSONObject) options.getJSONObject(0).get(
+ Resources.OPTIONS)).isNull(Resources.FORMATLENGTH)) {
+ String fmtOpt = (String) ((JSONObject) options
+ .getJSONObject(0).get(Resources.OPTIONS))
+ .get(Resources.FORMATLENGTH);
+ // medium
+ if (fmtOpt.equalsIgnoreCase(Resources.MEDIUM)) {
+ // default user preference for date
+ fmtDate = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.DATE_MEDIUM))
+ .toPattern();
+ // default user preference for time
+ fmtTime = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.TIME_MEDIUM))
+ .toPattern();
+ } else if (fmtOpt.equalsIgnoreCase(Resources.LONG)) { // long/full
+ // default user preference for date
+ fmtDate = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.DATE_LONG)).toPattern();
+ // default user preference for time
+ fmtTime = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.TIME_LONG)).toPattern();
+ } else if (fmtOpt.equalsIgnoreCase(Resources.FULL)) { // long/full
+ // default user preference for date
+ fmtDate = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.DATE_FULL)).toPattern();
+ // default user preference for time
+ fmtTime = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.TIME_FULL)).toPattern();
+ }
+ }
+
+ // return pattern type
+ fmt = fmtDate + Resources.SPACE + fmtTime;
+ if (!((JSONObject) options.getJSONObject(0).get(
+ Resources.OPTIONS)).isNull(Resources.SELECTOR)) {
+ String selOpt = (String) ((JSONObject) options
+ .getJSONObject(0).get(Resources.OPTIONS))
+ .get(Resources.SELECTOR);
+ if (selOpt.equalsIgnoreCase(Resources.DATE)) {
+ fmt = fmtDate;
+ } else if (selOpt.equalsIgnoreCase(Resources.TIME)) {
+ fmt = fmtTime;
+ }
+ }
+ }
+ return fmt;
+ } catch (Exception ge) {
+ }
+ return null;
+ }
+
+ /**
+ * Returns a JSONArray of either the names of the months or days of the week
+ * according to the client's user preferences and calendar. Note: Months
+ * will be in order from Jan - Dec, while days of week will begin on random
+ * day due to Locale time differences of defined long date values
+ *
+ * @param item
+ * String item (days of week or months)
+ * @param pattern
+ * String pattern (pattern to parse item)
+ * @return JSONArray The array of names starting from either the first month
+ * in the year or the first day of the week.
+ */
+ public static JSONArray getDateNameString(String item, String pattern) {
+ JSONArray value = new JSONArray();
+
+ // multipliers
+ long day = 1000 * 60 * 60 * 24; // 86,400,000
+ long startDay = day * 3; // starting three days in to avoid locale
+ // differences
+ long month = day * 31; // 2,678,400,000
+
+ SimpleDateFormat fmt = new SimpleDateFormat(pattern,
+ Locale.getDefault());
+ Date d = new Date();
+ try {
+ if (item.equalsIgnoreCase(Resources.MONTHS)) {
+ for (int x = 0; x < 13; x++) {
+ d = new Date(startDay + (month * x));
+ // testing short Month first
+ if (!value.contains(fmt.format(d).toString())
+ && !value.isEmpty()) {
+ // add day into array
+ value.put(fmt.format(d).toString());
+ } else if (value.isEmpty()) {
+ // Initialize array
+ value.put(fmt.format(d).toString());
+ }
+ }
+ } else { // Days
+ for (int x = 3; x < 11; x++) {
+ d = new Date(day * x);
+ // testing short day first
+ if (!value.contains(fmt.format(d).toString())
+ && !value.isEmpty()) {
+ // add day into array
+ value.put(fmt.format(d).toString());
+ } else if (value.isEmpty()) {
+ // Initialize array
+ value.put(fmt.format(d).toString());
+ }
+ }
+ }
+ return value;
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ /**
+ * Parses a String formatted as a percent or currency removing the symbol
+ * returns the corresponding number.
+ *
+ * @return String Corresponding number
+ *
+ * @throws Exception
+ */
+ public static String removeSymbols(String s) throws Exception {
+ StringBuffer sb = new StringBuffer(s.trim());
+ try {
+ // begin removing all characters before string
+ for (int x = 0; x < sb.length(); x++) {
+ if (Character.isDigit(sb.charAt(x))) {
+ x = sb.length() - 1; // end loop
+ } else {
+ sb.deleteCharAt(x);
+ }
+ }
+ // begin removing all characters after string
+ for (int x = sb.length() - 1; x > -1; x--) {
+ if (Character.isDigit(sb.charAt(x))) {
+ x = 0; // end loop
+ } else {
+ sb.deleteCharAt(x);
+ }
+ }
+ return sb.toString().trim();
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ /**
+ * Splits string into a JSONArray Note: Other options are to use
+ * org.apache.cordova.util.StringUtils.split(String strString, String
+ * strDelimiter)
+ *
+ * @param s
+ * String s (String to split)
+ * @param delimiter
+ * String delimiter (String used to split s)
+ * @return JSONArray: String objects
+ */
+ public static JSONArray split(String s, String delimiter) {
+ JSONArray result = new JSONArray();
+ String str = s;
+ try {
+ int p = s.indexOf(delimiter);
+ if (p != -1) {
+ while (p != -1) {
+ result.put(str.substring(0, p).trim());
+ if (p + 1 <= str.length()) {
+ str = str.substring(p + 1);
+ } else {
+ // delimiter is the last character in the string
+ str = "";
+ break;
+ }
+ p = str.indexOf(delimiter);
+ }
+ // add remaining characters if any
+ if (str.length() > 0) {
+ result.put(str);
+ }
+ return result;
+ }
+ return null; // incorrect delimiter
+ } catch (Exception e) {
+ }
+ return null; // error thrown
+ }
+
+ /**
+ * If applicable; removes day of week and other unwanted characters from
+ * JSONArray
+ *
+ * @param s
+ * JSONArray s (List of date properties)
+ *
+ * @return JSONArray:
+ * [key: day], [int: position]
+ * [key: month], [int: position]
+ * [key: year], [int: position]
+ */
+ public static JSONArray removeDayOfWeek(JSONArray s) {
+ JSONArray str = s;
+ JSONArray list;
+ try {
+ // get week names in short format //$NON-NLS-1$
+ list = getDateNameString(Resources.DAYS, "EEE");
+
+ // remove day of week from JSONArray
+ for (int x = 0; x < str.length(); x++) {
+ // do manual checking due to short or long version of week
+ // validate entry is not already an int
+ if (!Character.isDigit(str.getString(x).charAt(0))) {
+ // run though short weeks to get match and remove
+ StringMatch sm;
+ for (int y = 0; y < list.length(); y++) {
+ sm = new StringMatch(list.getString(y));
+ if (sm.indexOf(str.getString(x)) != -1) {// week found
+ str.removeElementAt(x); // remove day of week
+ return str;
+ }
+ // if end of list reached, load long version of names
+ // and rerun loop
+ if (y == list.length() - 1) {
+ y = -1;
+ // get week names in long format//$NON-NLS-1$
+ list = getDateNameString(Resources.DAYS, "EEEE");
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ }// exception caught, return initial JSONArray
+ return s;
+ }
+
+ /**
+ * If applicable; converts Month String into number
+ *
+ * @param s
+ * JSONArray s (List of date properties)
+ *
+ * @return JSONArray:
+ * [key: day], [int: position]
+ * [key: month], [int: position]
+ * [key: year], [int: position]
+ */
+ public static JSONArray convertMonthString(JSONArray s) {
+ JSONArray str = s;
+ JSONArray list;
+ try {
+ // get month names in short format
+ list = getDateNameString(Resources.MONTHS, "MMM");
+
+ // convert month string into integer if applicable
+ for (int x = 0; x < str.length(); x++) {
+ // do manual checking due to short or long version of months
+ // validate entry is not already an int
+ if (!Character.isDigit(str.getString(x).charAt(0))) {
+ // run though short format months to get index number
+ StringMatch sm;
+ for (int y = 0; y < list.length(); y++) {
+ sm = new StringMatch(list.getString(y));
+ if (sm.indexOf(str.getString(x)) != -1) {// month found
+ // replace string with integer
+ str.setElementAt(String.valueOf(y), x);
+ return str;
+ }
+ // if end of list reached load long version of names and
+ // rerun loop
+ if (y == list.length() - 1) {
+ y = -1;
+ // get month names in long format
+ list = getDateNameString(Resources.MONTHS, "MMMM");
+ }
+ }
+ }
+ }
+ return str;
+ } catch (Exception e) {
+ }// exception caught, return initial JSONArray
+ return s;
+ }
+
+ /**
+ * Determine if am_pm present and return value. if not return -1
+ *
+ * @param time
+ * String time (time string of date object)
+ *
+ * @return int
+ * -1 = am_pm not present
+ * 0 = am
+ * 1 = pm
+ */
+ public static int getAmPm(String time) {
+ // multipliers
+ long am_pm = 0; // pm
+ long am_pm_12 = 43200000; // am
+ int value = 1;
+ boolean reloop = true;
+
+ Date d = new Date(am_pm);
+
+ for (int x = 0; x < Resources.AM_PMFORMATS.length; x++) {
+ SimpleDateFormat fmt = new SimpleDateFormat(
+ Resources.AM_PMFORMATS[x], Locale.getDefault());
+
+ StringMatch sm = new StringMatch(fmt.format(d).toString());
+
+ if (sm.indexOf(time) != -1) {
+ return value;
+ }
+
+ if (x == Resources.AM_PMFORMATS.length - 1 && reloop) {
+ d = new Date(am_pm_12);
+ value = 0;
+ x = -1;
+ reloop = false;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns Hashtable indicating position of dd, MM, and yyyy in string.
+ * Position will either be 0, 1, or 2
+ *
+ * @param p
+ * String pattern
+ *
+ * @return Hashtable:
+ * [key: day], [int: position]
+ * [key: month], [int: position]
+ * [key: year], [int: position]
+ *
+ * @throws Exception
+ */
+ public static Hashtable getDatePattern(String p) {
+ Hashtable result = new Hashtable();
+
+ if (p.length() <= 0) {
+ // default device preference for date
+ p = ((SimpleDateFormat) DateFormat
+ .getInstance(DateFormat.DATE_SHORT)).toPattern();
+ }
+
+ // get positions
+ int day = p.indexOf('d'); //$NON-NLS-1$
+ int month = p.indexOf('M'); //$NON-NLS-1$
+ int year = p.indexOf('y'); //$NON-NLS-1$
+ // int weekDay = p.indexOf('E'); //removed in removeDayOfWeek()
+
+ if (year < day && day < month) { // yyyy/dd/mmmm
+ year = 0;
+ day = 1;
+ month = 2;
+ } else if (day < month && month < year) { // dd/mm/yyyy
+ year = 2;
+ day = 0;
+ month = 1;
+ } else if (year < month && month < day) {// yyyy/mm/dd
+ year = 0;
+ day = 2;
+ month = 1;
+ } else if (month < day && day < year) { // mm/dd/yyyy
+ year = 2;
+ day = 1;
+ month = 0;
+ } else if (month < year && year < day) { // mm/yyyy/dd
+ year = 1;
+ day = 2;
+ month = 0;
+ } else if (day < year && year < month) { // dd/yyyy/mm
+ year = 1;
+ day = 0;
+ month = 2;
+ } else {
+ return null; // an error has occurred
+ }
+ result.put("day", String.valueOf(day)); //$NON-NLS-1$
+ result.put("month", String.valueOf(month)); //$NON-NLS-1$
+ result.put("year", String.valueOf(year)); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Returns JSONObject of returnType('currency')
+ *
+ * @param _locale
+ * String _locale (user supplied Locale.toString())
+ * @param code
+ * String code (The ISO 4217 currency code)
+ *
+ * @return JSONObject: 'currency':
+ * [key: currencyCodes], [String]
+ * [key: currencyPattern], [String]
+ * [key: currencyDecimal], [String]
+ * [key: currencyFraction], [String]
+ * [key: currencyGrouping], [String]
+ * [key: currencyRounding], [String]
+ *
+ * @throws: Exception
+ */
+ public static JSONObject getCurrencyData(String _locale, String code) {
+ JSONObject result = null;
+ try {
+ JSONArray jsonArray;
+ result = getPersistentResourceBundle(_locale);
+ if (result == null) {
+ jsonArray = getResourceBundle(_locale).getJSONArray(
+ Resources.JSON_CURRENCY);
+ } else {
+ jsonArray = result.getJSONArray(Resources.JSON_CURRENCY);
+ }
+
+ for (int x = 0; x < jsonArray.length(); x++) {
+ JSONObject temp = jsonArray.getJSONObject(x);
+ if (temp.get(Resources.CURRENCYCODE).toString()
+ .equalsIgnoreCase(code)) {
+ result = temp;
+ }
+ }
+ } catch (Exception e) {
+
+ }
+ return result;
+ }
+
+ /**
+ * Returns JSONObject of returnType('locale')
+ *
+ * @param _locale
+ * String _locale (user supplied Locale.toString())
+ *
+ * @return JSONObject: 'locale':
+ * [key: displayName], [String]
+ * [key: firstDayOfWeek], [String]
+ * [key: pattern], [String]
+ * [key: decimalSymbol], [String]
+ * [key: currencySymbol], [String]
+ * [key: percentSymbol], [String]
+ *
+ * @throws Exception
+ */
+ public static JSONObject getLocaleData(String _locale) {
+ JSONObject result = null;
+ try {
+ result = getPersistentResourceBundle(_locale);
+ if (result == null) {
+ result = getResourceBundle(_locale).getJSONObject(
+ Resources.JSON_LOCALE);
+ } else {
+ result = result.getJSONObject(Resources.JSON_LOCALE);
+ }
+ } catch (Exception e) {
+ }
+ return result;
+ }
+
+ /**
+ * Returns resourceBundle JSONObject cached in PersistentStore
+ *
+ * Note: Recursively searches JSONObject from persistentStore using
+ * Resources.PERSISTENTSTORE_ID for locale by removing sub-parts (separated
+ * by '_')
+ *
+ * @param _locale
+ * String _locale (user supplied Locale.toString())
+ *
+ * @return JSONObject
+ */
+ private static JSONObject getPersistentResourceBundle(String _locale) {
+ JSONObject result = null;
+ try {
+ // load object
+ result = (JSONObject) PersistentStore.getPersistentObject(
+ Resources.PERSISTENTSTORE_ID).getContents();
+ } catch (Exception e) {
+ if (StringUtilities.indexOf(_locale, '_', 0, _locale.length()) > 0) {
+ result = getPersistentResourceBundle(removeSubPart(StringUtils
+ .split(_locale, "_"))); //$NON-NLS-1$
+ } else {
+ result = null;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns resourceBundle File as JSONObject from
+ * /resource/resourceBundles/<Locale.toString()>.js.gz
+ *
+ * Note: Recursively searches for locale by removing sub-parts (separated by
+ * '_')
+ *
+ * @param _locale
+ * String _locale (user supplied Locale.toString())
+ *
+ * @return JSONObject
+ */
+ private static JSONObject getResourceBundle(String _locale) {
+ JSONObject result = null;
+
+ try {
+ if (_locale == null || _locale.length() <= 0) {
+ return null;
+ }
+
+ InputStream is = Util.class.getClass().getResourceAsStream(
+ Resources.LOCALEINFOPATH + _locale
+ + Resources.LOCALEINFOPATHEND);
+ Parser parser = new Parser(new InputStreamReader(
+ new GZIPInputStream(is), "UTF-8"));
+ result = parser.parse();
+
+ // cache resourceBundle as JSONOBJECT
+ // store new object
+ PersistentObject persist = PersistentStore
+ .getPersistentObject(Resources.PERSISTENTSTORE_ID);
+ // Synchronize on the PersistentObject so that no other object can
+ // acquire the lock before we finish our commit operation.
+ synchronized (persist) {
+ persist.setContents((Hashtable) result);
+ persist.commit();
+ }
+ } catch (NonPersistableObjectException npoe) {
+ Logger.log("Globalization: Failed to persist locale: "
+ + npoe.getMessage());
+ } catch (Exception e) {
+ // if resourceBundle not found, recursively search for file by
+ // removing substrings from name
+ if (StringUtilities.indexOf(_locale, '_', 0, _locale.length()) > 0) {
+ result = getResourceBundle(removeSubPart(StringUtils.split(
+ _locale, "_"))); //$NON-NLS-1$
+ } else {
+ result = null;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns substring of resourceBundle with the last section removed. Ex.
+ * cs_CZ_PREEURO -> cs_CZ
+ *
+ * @param s
+ * String[] s (Array of locale split by '_')
+ *
+ * @return JSONObject
+ */
+ private static String removeSubPart(String[] s) {
+ String result = "";
+ for (int x = 0; x < s.length - 1; x++) {
+ result += s[x];
+ if (x != s.length - 2) {// length - 2 to account for starting at
+ // zero
+ result += "_"; //$NON-NLS-1$
+ }
+ }
+ return result;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/041e4481/bbos/framework/ext/src/org/apache/cordova/http/FileTransfer.java
----------------------------------------------------------------------
diff --git a/bbos/framework/ext/src/org/apache/cordova/http/FileTransfer.java b/bbos/framework/ext/src/org/apache/cordova/http/FileTransfer.java
new file mode 100644
index 0000000..b0f089c
--- /dev/null
+++ b/bbos/framework/ext/src/org/apache/cordova/http/FileTransfer.java
@@ -0,0 +1,473 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.microedition.io.Connector;
+import javax.microedition.io.HttpConnection;
+import javax.microedition.io.file.FileConnection;
+
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.file.Entry;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.json4j.JSONObject;
+import org.apache.cordova.util.Logger;
+
+import net.rim.device.api.io.FileNotFoundException;
+import net.rim.device.api.io.http.HttpProtocolConstants;
+
+/**
+ * The FileTransfer plugin can be used to transfer files between the device and
+ * a remote server. The following actions are supported:
+ *
+ * download - Download a file from a server to the device.
+ * upload - Upload a file from the device to a server.
+ */
+public class FileTransfer extends Plugin {
+ private static final String LOG_TAG = "FileTransfer: ";
+
+ /**
+ * Error codes
+ */
+ static int FILE_NOT_FOUND_ERR = 1;
+ static int INVALID_URL_ERR = 2;
+ static int CONNECTION_ERR = 3;
+
+ /**
+ * Possible actions
+ */
+ private static final String ACTION_DOWNLOAD = "download";
+ private static final String ACTION_UPLOAD = "upload";
+
+ private static final char SEPARATOR = '/';
+
+ /**
+ * Executes the requested action and returns a PluginResult.
+ *
+ * @param action
+ * The action to execute.
+ * @param callbackId
+ * The callback ID to be invoked upon action completion.
+ * @param args
+ * JSONArry of arguments for the action.
+ * @return A PluginResult object with a status and message.
+ */
+ public PluginResult execute(String action, JSONArray args, String callbackId) {
+ String source = null;
+ String target = null;
+ PluginResult result = null;
+
+ try {
+ // Retrieve the source and target locations from the argument array.
+ source = args.isNull(0) ? null : args.getString(0).trim();
+ target = args.isNull(1) ? null : args.getString(1).trim();
+
+ if (source == null || source.length() == 0 || target == null
+ || target.length() == 0) {
+ Logger.log(LOG_TAG + "Missing source or target");
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+ "Missing source or target");
+ }
+ } catch (JSONException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+ "Invalid or missing parameter");
+ }
+
+ if (ACTION_UPLOAD.equals(action)) {
+ // Source needs to follow the file URI protocol so add "file:///"
+ // prefix if it doesn't exist.
+ if (!source.startsWith("file:///")) {
+ if (source.indexOf(SEPARATOR) != 0) {
+ source = "file://" + SEPARATOR + source;
+ } else {
+ source = "file://" + source;
+ }
+ }
+
+ FileUploader uploader = null;
+ try {
+ // Setup the options
+ String fileKey = getArgument(args, 2, "file");
+ String fileName = getArgument(args, 3, "image.jpg");
+ String mimeType = getArgument(args, 4, null);
+ JSONObject params = null;
+ JSONObject headers = null;
+
+ if (args.length() > 5 && !args.isNull(5)) {
+ params = args.getJSONObject(5);
+ }
+
+ if(args.length() > 8 && !args.isNull(8)){
+ headers = args.getJSONObject(8);
+ }
+ uploader = new FileUploader();
+ FileUploadResult r = uploader.upload(source, target, fileKey,
+ fileName, mimeType, params, headers);
+
+ int status = r.getResponseCode();
+ if (status < 200 || status > 399) {
+ Logger.log(LOG_TAG + "HTTP Status " + status);
+ JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, new Integer(status));
+ return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+ }
+
+ result = new PluginResult(PluginResult.Status.OK,
+ r.toJSONObject());
+ } catch (FileNotFoundException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR,
+ source, target, uploader);
+ result = new PluginResult(PluginResult.Status.IO_EXCEPTION,
+ error);
+ } catch (IllegalArgumentException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ JSONObject error = createFileTransferError(INVALID_URL_ERR,
+ source, target, uploader);
+ result = new PluginResult(
+ PluginResult.Status.MALFORMED_URL_EXCEPTION, error);
+ } catch (IOException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ JSONObject error = createFileTransferError(CONNECTION_ERR,
+ source, target, uploader);
+ result = new PluginResult(PluginResult.Status.IO_EXCEPTION,
+ error);
+ } catch (JSONException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ result = new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+ "Invalid or missing parameter");
+ }
+ } else if (ACTION_DOWNLOAD.equals(action)) {
+ result = download(source, target);
+ } else {
+ // invalid action
+ result = new PluginResult(PluginResult.Status.INVALID_ACTION,
+ LOG_TAG + "invalid action " + action);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create an error object based on the passed in errorCode
+ *
+ * @param errorCode
+ * the error
+ * @return JSONObject containing the error
+ */
+ private JSONObject createFileTransferError(int errorCode, String source,
+ String target) {
+ return createFileTransferError(errorCode, source, target,
+ (Integer) null);
+ }
+
+ /**
+ * Create an error object based on the passed in errorCode
+ *
+ * @param errorCode
+ * the error
+ * @return JSONObject containing the error
+ */
+ private JSONObject createFileTransferError(int errorCode, String source,
+ String target, FileUploader fileUploader) {
+
+ Integer httpStatus = null;
+
+ if (fileUploader != null) {
+ httpStatus = fileUploader.getResponseCode();
+ }
+ return createFileTransferError(errorCode, source, target, httpStatus);
+ }
+
+ /**
+ * Create an error object based on the passed in errorCode
+ *
+ * @param errorCode
+ * the error
+ * @return JSONObject containing the error
+ */
+ private JSONObject createFileTransferError(int errorCode, String source,
+ String target, HttpConnection connection) {
+
+ Integer httpStatus = null;
+
+ if (connection != null) {
+ try {
+ httpStatus = new Integer(connection.getResponseCode());
+ } catch (IOException e) {
+ Logger.log(LOG_TAG + " exception getting http response code "
+ + e.toString());
+ }
+ }
+
+ return createFileTransferError(errorCode, source, target, httpStatus);
+ }
+
+ /**
+ * Create an error object based on the passed in errorCode
+ *
+ * @param errorCode
+ * the error
+ * @return JSONObject containing the error
+ */
+ private JSONObject createFileTransferError(int errorCode, String source,
+ String target, Integer httpStatus) {
+ JSONObject error = null;
+ try {
+ error = new JSONObject();
+ error.put("code", errorCode);
+ error.put("source", source);
+ error.put("target", target);
+ if (httpStatus != null) {
+ error.put("http_status", httpStatus);
+ }
+ } catch (JSONException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ }
+ return error;
+ }
+
+ /**
+ * Recurse through a specified path and create any directories that do not
+ * already exist.
+ *
+ * @param path
+ * directory path to recurse
+ * @throws IOException
+ */
+ private void createSubDirs(String path) throws IOException {
+ FileConnection outputStream = null;
+
+ try {
+ outputStream = (FileConnection) Connector.open(path,
+ Connector.READ_WRITE);
+ if (!outputStream.exists()) {
+ int dirIndex = path.lastIndexOf(SEPARATOR, path.length() - 2);
+ // This code assumes file protocol is specified so stop
+ // recursion once "file:///" is hit.
+ if (dirIndex != -1 && dirIndex > 7) {
+ createSubDirs(path.substring(0, dirIndex + 1));
+ }
+ outputStream.mkdir();
+ }
+ } finally {
+ try {
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ } catch (IOException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Download a file from a given URL and save it to the specified location.
+ *
+ * @param source
+ * URL of the server to receive the file
+ * @param target
+ * Full path of the file on the file system
+ * @return JSONObject a file entry object in JSON form describing the
+ * downloaded file.
+ */
+ private PluginResult download(String source, String target) {
+ HttpConnection httpConn = null;
+ FileConnection fileConn = null;
+ OutputStream outputStream = null;
+ String filename = null;
+ String path = null;
+
+ Logger.debug(LOG_TAG + "downloading " + source + " to " + target);
+
+ // Target needs to follow the file URI protocol so add "file:///"
+ // prefix if it doesn't exist.
+ if (!target.startsWith("file:///")) {
+ if (target.indexOf(SEPARATOR) != 0) {
+ target = "file://" + SEPARATOR + target;
+ } else {
+ target = "file://" + target;
+ }
+ }
+
+ // Parse the target filename and directory path. If the target does not
+ // specify a file name (only directory), try to get the file name from
+ // the source.
+ int dirIndex = target.lastIndexOf(SEPARATOR);
+ if (dirIndex == (target.length() - 1)) {
+ int srcdirIndex = source.lastIndexOf(SEPARATOR);
+ if (srcdirIndex != (source.length() - 1)) {
+ path = target;
+ filename = source.substring(srcdirIndex + 1);
+ target = path + filename;
+ }
+ } else if (dirIndex != -1) {
+ filename = target.substring(dirIndex + 1);
+ path = target.substring(0, dirIndex + 1);
+ }
+
+ // If no filename or path could be determined for the target, error out.
+ if (filename == null || path == null) {
+ Logger.log(LOG_TAG + "Target filename could not be determined.");
+ JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR,
+ source, target);
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION, error);
+ }
+
+ try {
+ try {
+ // Create any directories in the path that do not already exist.
+ createSubDirs(path);
+
+ // Open connection to the target file.
+ fileConn = (FileConnection) Connector.open(target,
+ Connector.READ_WRITE);
+ } catch (IOException e) {
+ Logger.log(LOG_TAG + "Failed to open target file: " + target);
+ JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source,
+ target, httpConn);
+ return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+ }
+
+ // Create the target file if it doesn't exist, otherwise truncate.
+ if (!fileConn.exists()) {
+ fileConn.create();
+ } else {
+ fileConn.truncate(0);
+ }
+
+ // Open the http connection to the server.
+ try {
+ httpConn = HttpUtils.getHttpConnection(source);
+ } catch (IllegalArgumentException e) {
+ JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, httpConn);
+ return new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION, error);
+ }
+ if (httpConn == null) {
+ Logger.log(LOG_TAG + "Failed to create http connection.");
+ // TODO separate malformed url from actual connection error
+ JSONObject error = createFileTransferError(CONNECTION_ERR,
+ source, target);
+ return new PluginResult(
+ PluginResult.Status.IO_EXCEPTION, error);
+ }
+
+ // Set the request headers
+ httpConn.setRequestMethod(HttpConnection.GET);
+ httpConn.setRequestProperty(
+ HttpProtocolConstants.HEADER_USER_AGENT,
+ System.getProperty("browser.useragent"));
+ httpConn.setRequestProperty(
+ HttpProtocolConstants.HEADER_KEEP_ALIVE, "300");
+ httpConn.setRequestProperty(
+ HttpProtocolConstants.HEADER_CONNECTION, "keep-alive");
+
+ // Set the cookie
+ String cookie = HttpUtils.getCookie(source);
+ if (cookie != null) {
+ httpConn.setRequestProperty(
+ HttpProtocolConstants.HEADER_COOKIE, cookie);
+ }
+
+ InputStream inputStream = httpConn.openInputStream();
+ int status = httpConn.getResponseCode();
+ if (status < 200 || status > 399) {
+ Logger.log(LOG_TAG + "HTTP Status " + status);
+ JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, httpConn);
+ return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+ }
+
+ outputStream = fileConn.openOutputStream();
+
+ // Read from the connection and write bytes to the file.
+ byte[] buffer = new byte[1024];
+ int bytesRead = 0;
+ while ((bytesRead = inputStream.read(buffer)) > 0) {
+ outputStream.write(buffer, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ Logger.log(LOG_TAG + e.getMessage());
+ JSONObject error = createFileTransferError(CONNECTION_ERR, source,
+ target, httpConn);
+ return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+ } catch (ClassCastException e) {
+ // in case something really funky gets passed in
+ Logger.log(LOG_TAG + e.getMessage());
+ JSONObject error = createFileTransferError(INVALID_URL_ERR, source,
+ target, httpConn);
+ return new PluginResult(
+ PluginResult.Status.MALFORMED_URL_EXCEPTION, error);
+ } catch (Throwable t) {
+ Logger.log(LOG_TAG + t.toString());
+ JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, httpConn);
+ return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+ } finally {
+ try {
+ if (httpConn != null) {
+ httpConn.close();
+ }
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ if (fileConn != null) {
+ fileConn.close();
+ }
+ } catch (IOException e) {
+ Logger.log(LOG_TAG + "IOException in finally: "
+ + e.getMessage());
+ }
+ }
+
+ // create a new Entry
+ Entry entry = new Entry();
+ entry.setDirectory(false);
+ entry.setName(filename);
+ entry.setFullPath(target);
+
+ return new PluginResult(PluginResult.Status.OK, entry.toJSONObject());
+ }
+
+ /**
+ * Convenience method to read a parameter from the list of JSON args.
+ *
+ * @param args
+ * the args passed to the Plugin
+ * @param position
+ * the position to retrieve the arg from
+ * @param defaultString
+ * the default to be used if the arg does not exist
+ * @return String with the retrieved value
+ */
+ private String getArgument(JSONArray args, int position,
+ String defaultString) {
+ String arg = defaultString;
+ if (args.length() >= position) {
+ arg = args.optString(position);
+ if (arg == null || "null".equals(arg)) {
+ arg = defaultString;
+ }
+ }
+ return arg;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/041e4481/bbos/framework/ext/src/org/apache/cordova/http/FileUploadResult.java
----------------------------------------------------------------------
diff --git a/bbos/framework/ext/src/org/apache/cordova/http/FileUploadResult.java b/bbos/framework/ext/src/org/apache/cordova/http/FileUploadResult.java
new file mode 100644
index 0000000..4b00159
--- /dev/null
+++ b/bbos/framework/ext/src/org/apache/cordova/http/FileUploadResult.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.http;
+
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.json4j.JSONObject;
+
+/**
+ * Encapsulates the result and/or status of uploading a file to a remote server.
+ */
+public class FileUploadResult {
+
+ private long bytesSent = 0; // bytes sent
+ private int responseCode = -1; // HTTP response code
+ private String response = null; // HTTP response
+
+ public long getBytesSent() {
+ return bytesSent;
+ }
+
+ public void setBytesSent(long bytes) {
+ this.bytesSent = bytes;
+ }
+
+ public int getResponseCode() {
+ return responseCode;
+ }
+
+ public void setResponseCode(int responseCode) {
+ this.responseCode = responseCode;
+ }
+
+ public String getResponse() {
+ return response;
+ }
+
+ public void setResponse(String response) {
+ this.response = response;
+ }
+
+ public JSONObject toJSONObject() throws JSONException {
+ return new JSONObject(
+ "{bytesSent:" + bytesSent +
+ ",responseCode:" + responseCode +
+ ",response:" + JSONObject.quote(response) + "}");
+ }
+}