Skip to content
Browse files

Add JSOM map/reduce jobs, embed JSON code, and copy MapReduceBuilder …

…from Basho's riak-java-client.
  • Loading branch information...
1 parent 667822d commit 569ef193fe6b5c93ee53382b0ada8d3f59c5a97c @krestenkrab committed Jun 24, 2010
View
44 src/com/trifork/riak/BucketProperties.java
@@ -0,0 +1,44 @@
+package com.trifork.riak;
+
+import com.trifork.riak.RPB.RpbBucketProps;
+import com.trifork.riak.RPB.RpbGetBucketResp;
+import com.trifork.riak.RPB.RpbBucketProps.Builder;
+
+public class BucketProperties {
+
+ private Boolean allowMult;
+ private Integer nValue;
+
+ public void init(RpbGetBucketResp resp) {
+ if (resp.hasProps()) {
+
+ RpbBucketProps props = resp.getProps();
+ if (props.hasAllowMult()) {
+ allowMult = Boolean.valueOf(props.getAllowMult());
+ }
+ if (props.hasNVal()) {
+ nValue = new Integer(props.getNVal());
+ }
+ }
+ }
+
+ public Boolean getAllowMult() {
+ return allowMult;
+ }
+
+ public Integer getNValue() {
+ return nValue;
+ }
+
+ RpbBucketProps build() {
+ Builder builder = RpbBucketProps.newBuilder();
+ if (allowMult != null) {
+ builder.setAllowMult(allowMult);
+ }
+ if (nValue != null) {
+ builder.setNVal(nValue);
+ }
+ return builder.build();
+ }
+
+}
View
12 src/com/trifork/riak/RequestMeta.java
@@ -18,11 +18,14 @@
package com.trifork.riak;
+import com.google.protobuf.ByteString;
+
public class RequestMeta {
Boolean returnBody;
Integer writeQuorum;
Integer durableWriteQuorum;
+ String contentType;
public RequestMeta() {
}
@@ -56,4 +59,13 @@ RequestMeta dw(int dw) {
dw = new Integer(dw);
return this;
}
+
+ RequestMeta contentType(String contentType) {
+ this.contentType = contentType;
+ return this;
+ }
+
+ public ByteString getContentType() {
+ return ByteString.copyFromUtf8(contentType);
+ }
}
View
75 src/com/trifork/riak/RiakClient.java
@@ -35,6 +35,8 @@
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
+import org.json.JSONObject;
+
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageLite;
@@ -46,9 +48,13 @@
import com.trifork.riak.RPB.RpbGetServerInfoResp;
import com.trifork.riak.RPB.RpbListBucketsResp;
import com.trifork.riak.RPB.RpbListKeysResp;
+import com.trifork.riak.RPB.RpbMapRedReq;
+import com.trifork.riak.RPB.RpbMapRedResp;
import com.trifork.riak.RPB.RpbPutReq;
import com.trifork.riak.RPB.RpbPutResp;
import com.trifork.riak.RPB.RpbSetClientIdReq;
+import com.trifork.riak.RPB.RpbMapRedReq.Builder;
+import com.trifork.riak.mapreduce.MapReduceResponse;
public class RiakClient {
@@ -81,6 +87,7 @@
private static final int DEFAULT_RIAK_PB_PORT = 8087;
private static final RiakObject[] NO_RIAK_OBJECTS = new RiakObject[0];
private static final ByteString[] NO_BYTE_STRINGS = new ByteString[0];
+ private static final MapReduceResponse[] NO_MAP_REDUCE_RESPONSES = new MapReduceResponse[0];
private Socket sock;
private DataOutputStream dout;
private DataInputStream din;
@@ -117,7 +124,7 @@ public RiakClient(InetAddress addr, int port) throws IOException {
*
* @throws IOException
*/
- private void prepareClientID() throws IOException {
+ public void prepareClientID() throws IOException {
Preferences prefs = Preferences.userNodeForPackage(RiakClient.class);
String clid = prefs.get("client_id", null);
@@ -402,6 +409,33 @@ public void delete(ByteString bucket, ByteString key) throws IOException {
return out;
}
+ public BucketProperties getBucketProperties(ByteString bucket) throws IOException {
+
+ send(MSG_GetBucketReq,
+ RPB.RpbGetBucketReq.newBuilder()
+ .setBucket(bucket).build());
+
+ byte[] data = receive(MSG_GetBucketResp);
+ BucketProperties bp = new BucketProperties();
+ if (data == null) {
+ return bp;
+ }
+
+ bp.init(RPB.RpbGetBucketResp.parseFrom(data));
+ return bp;
+ }
+
+ public void setBucketProperties(ByteString bucket, BucketProperties props) throws IOException {
+
+ RPB.RpbSetBucketReq req = RPB.RpbSetBucketReq.newBuilder()
+ .setBucket(bucket)
+ .setProps( props.build() ).build();
+
+ send(MSG_SetBucketReq, req);
+ receive_code(MSG_SetBucketResp);
+ }
+
+
// /////////////////////
public ByteString[] listKeys(ByteString bucket) throws IOException {
@@ -427,8 +461,45 @@ public void delete(ByteString bucket, ByteString key) throws IOException {
return keys.toArray(new ByteString[keys.size()]);
}
+
+
- // /////////////////////
+ ///////////////////////
+
+ MapReduceResponse[] mapreduce(JSONObject obj) throws IOException {
+ return mapreduce(ByteString.copyFromUtf8(obj.toString()),
+ new RequestMeta().contentType("application/json"));
+ }
+
+ public MapReduceResponse[] mapreduce(ByteString request, RequestMeta meta) throws IOException {
+
+ ByteString contentType = meta.getContentType();
+ if (contentType == null) {
+ throw new IllegalArgumentException("no content type");
+ }
+ RpbMapRedReq req = RPB.RpbMapRedReq.newBuilder()
+ .setRequest(request)
+ .setContentType(meta.getContentType()).build();
+
+ send(MSG_MapRedReq, req);
+ byte[] data = receive(MSG_MapRedResp);
+ if (data == null) {
+ return NO_MAP_REDUCE_RESPONSES;
+ }
+
+ List<MapReduceResponse> out = new ArrayList<MapReduceResponse>();
+ RpbMapRedResp resp;
+ do {
+ resp = RPB.RpbMapRedResp.parseFrom(data);
+ out.add(new MapReduceResponse(resp, contentType));
+
+ } while (!resp.hasDone() || resp.getDone() == false);
+
+ return out.toArray(new MapReduceResponse[out.size()]);
+ }
+
+
+ ///////////////////////
private void send(int code, MessageLite req) throws IOException {
int len = req.getSerializedSize();
View
54 src/com/trifork/riak/mapreduce/ErlangFunction.java
@@ -0,0 +1,54 @@
+/*
+ * This file is provided 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 com.trifork.riak.mapreduce;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Represents an Erlang function used in a map or reduce phase
+ * of a map/reduce job
+ *
+ */
+public class ErlangFunction implements MapReduceFunction {
+
+ private String module;
+ private String function;
+
+ /**
+ * Constructs a new ErlangFunction instance
+ * @param module Erlang module name
+ * @param functionName Erlang function name
+ */
+ public ErlangFunction(String module, String functionName) {
+ this.module = module;
+ this.function = functionName;
+ }
+
+ /**
+ * Converts the function definition to JSON
+ */
+ public JSONObject toJson() {
+ try {
+ JSONObject retval = new JSONObject();
+ retval.put("language", "erlang");
+ retval.put("module", this.module);
+ retval.put("function", this.function);
+ return retval;
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a string");
+ }
+ }
+
+}
View
73 src/com/trifork/riak/mapreduce/JavascriptFunction.java
@@ -0,0 +1,73 @@
+/*
+ * This file is provided 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 com.trifork.riak.mapreduce;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Represents a Javascript function used in a map or reduce phase
+ * of a map/reduce job
+ *
+ */
+public class JavascriptFunction implements MapReduceFunction {
+
+ private String source;
+ private MapReduceFunction.Types type;
+
+ /**
+ * Shortcut for creating a reference to a named
+ * Javascript function
+ * @param functionName Name of Javascript function ("Riak.mapValuesJson")
+ */
+ public static JavascriptFunction named(String functionName) {
+ return new JavascriptFunction(MapReduceFunction.Types.NAMED, functionName);
+ }
+
+ /**
+ * Shortcut for creating a reference to an anonymous
+ * Javascript function
+ * @param functionSource Javascript function source ("function(v) { return [v]; }")
+ */
+ public static JavascriptFunction anon(String functionSource) {
+ return new JavascriptFunction(MapReduceFunction.Types.ANONYMOUS, functionSource);
+ }
+
+ /**
+ * Converts the function definition to JSON
+ */
+ public JSONObject toJson() {
+ try {
+ JSONObject retval = new JSONObject();
+ retval.put("language", "javascript");
+ if (type == MapReduceFunction.Types.NAMED) {
+ retval.put("name", this.source);
+ }
+ else {
+ retval.put("source", this.source);
+ }
+
+ return retval;
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a string");
+ }
+ }
+
+ private JavascriptFunction(MapReduceFunction.Types functionType,
+ String functionSource) {
+ this.type = functionType;
+ this.source = functionSource;
+ }
+
+}
View
48 src/com/trifork/riak/mapreduce/LinkFunction.java
@@ -0,0 +1,48 @@
+/*
+ * This file is provided 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 com.trifork.riak.mapreduce;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class LinkFunction implements MapReduceFunction {
+
+ private String bucket = null;
+ private String tag = null;
+
+ public LinkFunction(String bucket) {
+ this.bucket = bucket;
+ }
+
+ public LinkFunction(String bucket, String tag) {
+ this.bucket = bucket;
+ this.tag = tag;
+ }
+
+ public JSONObject toJson() {
+ try {
+ JSONObject link = new JSONObject();
+ link.put("bucket", this.bucket);
+
+ if (this.tag != null) {
+ link.put("tag", this.tag);
+ }
+
+ return link;
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a string");
+ }
+ }
+
+}
View
431 src/com/trifork/riak/mapreduce/MapReduceBuilder.java
@@ -0,0 +1,431 @@
+/*
+ * This file is provided 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 com.trifork.riak.mapreduce;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.google.protobuf.ByteString;
+import com.trifork.riak.RequestMeta;
+import com.trifork.riak.RiakClient;
+import com.trifork.riak.RiakObject;
+
+/**
+ * Builds a map/reduce job description and submits it Uses the same chained
+ * method metaphor as StringBuilder or StringBuffer
+ */
+public class MapReduceBuilder {
+
+ private static enum Types {
+ MAP, REDUCE, LINK
+ }
+
+ private String bucket = null;
+ private Map<ByteString, Set<ByteString>> objects = new HashMap<ByteString, Set<ByteString>>();
+ private List<MapReducePhase> phases = new LinkedList<MapReducePhase>();
+ private int timeout = -1;
+ private RiakClient riak = null;
+
+ /**
+ * @param riak
+ * RiakClient instance which is pointing to the map/reduce URL
+ */
+ public MapReduceBuilder(RiakClient riak) {
+ this.riak = riak;
+ }
+
+ public MapReduceBuilder() { /* nop */}
+
+ /**
+ * The {@link RiakClient} to which this map reduce job will be submitted to
+ * when {@link MapReduceBuilder#submit()} is called.
+ */
+ public RiakClient getRiakClient() {
+ return riak;
+ }
+
+ public MapReduceBuilder setRiakClient(RiakClient client) {
+ riak = client;
+ return this;
+ }
+
+ /**
+ * Gets the name of the Riak bucket the map/reduce job will process
+ */
+ public String getBucket() {
+ return bucket;
+ }
+
+ /**
+ * Sets the name of the Riak bucket the map/reduce job will process
+ *
+ * @throws IllegalStateException
+ * - If objects have already been added to the job
+ */
+ public MapReduceBuilder setBucket(String newBucket) {
+ if (objects.size() > 0)
+ throw new IllegalStateException("Cannot map/reduce over buckets and objects");
+ bucket = newBucket;
+ return this;
+ }
+
+ /**
+ * Adds a Riak object (bucket name/key pair) to the map/reduce job as inputs
+ *
+ * @throws IllegalStateException
+ * - If a bucket name has already been set on the job
+ */
+ public void addRiakObject(ByteString bucket, ByteString key) {
+ if (this.bucket != null)
+ throw new IllegalStateException("Cannot map/reduce over buckets and objects");
+ Set<ByteString> keys = objects.get(bucket);
+ if (keys == null) {
+ keys = new LinkedHashSet<ByteString>();
+ objects.put(bucket, keys);
+ }
+ keys.add(key);
+ }
+
+ /**
+ * Removes a Riak object (bucket name/key pair) for the job's input list
+ */
+ public void removeRiakObject(String bucket, String key) {
+ Set<ByteString> keys = objects.get(bucket);
+ if (keys != null) {
+ keys.remove(key);
+ if (keys.size() == 0) {
+ objects.remove(bucket);
+ }
+ }
+ }
+
+ /**
+ * Returns a copy of the Riak objects on the input list for a map/reduce job
+ */
+ public Map<ByteString, Set<ByteString>> getRiakObjects() {
+ return new HashMap<ByteString, Set<ByteString>>(objects);
+ }
+
+ /**
+ * Sets a collection of Riak object (bucket name/key pair) as the map/reduce
+ * job as inputs
+ *
+ * @throws IllegalStateException
+ * - If a bucket name has already been set on the job
+ */
+ public MapReduceBuilder setRiakObjects(Map<ByteString, Set<ByteString>> objects) {
+ if (bucket != null)
+ throw new IllegalStateException("Cannot map/reduce over buckets and objects");
+
+ if (objects == null) {
+ clearRiakObjects();
+ } else {
+ this.objects = new HashMap<ByteString, Set<ByteString>>(objects);
+ }
+
+ return this;
+ }
+
+ public MapReduceBuilder setRiakObjects(Collection<RiakObject> objects) {
+ if (bucket != null)
+ throw new IllegalStateException("Cannot map/reduce over buckets and objects");
+
+ clearRiakObjects();
+ if (objects != null) {
+ for (RiakObject o : objects) {
+ addRiakObject(o.getBucket(), o.getKey());
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Remove all Riak objects from the input list
+ */
+ public void clearRiakObjects() {
+ objects.clear();
+ }
+
+ /**
+ * How long the map/reduce job is allowed to execute Time is in milliseconds
+ */
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ /**
+ * Gets the currently assigned timeout
+ */
+ public int getTimeout() {
+ return timeout;
+ }
+
+ /**
+ * Adds a map phase to the job
+ *
+ * @param function
+ * function to run for the phase
+ *
+ * @param keep
+ * should the server keep and return the results
+ * @return current MapReduceBuilder instance. This is done so multiple calls
+ * to map, reduce, and link can be chained together a la
+ * StringBuffer
+ */
+ public MapReduceBuilder map(MapReduceFunction function, boolean keep) {
+ return this.map(function, null, keep);
+ }
+
+
+ /**
+ * Adds a map phase to the job
+ *
+ * @param function
+ * function to run for the phase
+ *
+ * @param arg
+ * Static argument to pass to the function. Should be an
+ * object easily converted to JSON
+ *
+ * @param keep
+ * should the server keep and return the results
+ * @return current MapReduceBuilder instance. This is done so multiple calls
+ * to map, reduce, and link can be chained together a la
+ * StringBuffer
+ */
+ public MapReduceBuilder map(MapReduceFunction function, Object arg, boolean keep) {
+ this.addPhase(MapReduceBuilder.Types.MAP, function, arg, keep);
+ return this;
+ }
+
+ /**
+ * Adds a reduce phase to the job
+ *
+ * @param function
+ * function to run for the phase
+ *
+ * @param keep
+ * should the server keep and return the results
+ * @return current MapReduceBuilder instance. This is done so multiple calls
+ * to map, reduce, and link can be chained together a la
+ * StringBuffer
+ */
+ public MapReduceBuilder reduce(MapReduceFunction function, boolean keep) {
+ return this.reduce(function, null, keep);
+ }
+
+
+ /**
+ * Adds a reduce phase to the job
+ *
+ * @param function
+ * function to run for the phase
+ *
+ * @param arg
+ * Static argument to pass to the function. Should be an
+ * object easily converted to JSON
+ *
+ * @param keep
+ * should the server keep and return the results
+ * @return current MapReduceBuilder instance. This is done so multiple calls
+ * to map, reduce, and link can be chained together a la
+ * StringBuffer
+ */
+ public MapReduceBuilder reduce(MapReduceFunction function, Object arg, boolean keep) {
+ this.addPhase(MapReduceBuilder.Types.REDUCE, function, arg, keep);
+ return this;
+ }
+
+ /**
+ * Adds a link phase to the job
+ *
+ * @param bucket
+ * bucket to link walk
+ * @param keep
+ * should the server keep and return the results
+ * @return current MapReduceBuilder instance. This is done so multiple calls
+ * to map, reduce, and link can be chained together a la
+ * StringBuffer
+ *
+ * Pointing at a bucket without specifying a link tag will follow
+ * all links pointing to objects in the bucket
+ */
+ public MapReduceBuilder link(String bucket, boolean keep) {
+ this.addPhase(MapReduceBuilder.Types.LINK, new LinkFunction(bucket), keep);
+ return this;
+ }
+
+ /**
+ * Adds a link phase to the job
+ *
+ * @param bucket
+ * bucket to link walk
+ * @param tag
+ * link tag to match
+ * @param keep
+ * should the server keep and return the results
+ * @return current MapReduceBuilder instance. This is done so multiple calls
+ * to map, reduce, and link can be chained together a la
+ * StringBuffer
+ */
+ public MapReduceBuilder link(String bucket, String tag, boolean keep) {
+ this.addPhase(MapReduceBuilder.Types.LINK, new LinkFunction(bucket, tag), keep);
+ return this;
+ }
+
+ /**
+ * Submits the job to the Riak server
+ *
+ * @param meta
+ * Extra metadata to attach to the request such as HTTP headers
+ * or query parameters.
+ *
+ * @return {@link MapReduceResponse} containing job results
+ * @throws IOException
+ *
+ * @throws IllegalStateException
+ * If this job has not been associated with a Riak instance by
+ * calling {@link MapReduceBuilder#setRiakClient(RiakClient)}
+ * @throws RiakIORuntimeException
+ * If an error occurs during communication with the Riak server.
+ * @throws RiakResponseRuntimeException
+ * If the Riak server returns a malformed response.
+ */
+ public MapReduceResponse[] submit(RequestMeta meta) throws IOException {
+ if (riak == null)
+ throw new IllegalStateException("Cannot perform map reduce without a RiakClient");
+ return riak.mapreduce(ByteString.copyFromUtf8( toJSON().toString() ), meta);
+ }
+
+ public MapReduceResponse[] submit() throws JSONException, IOException {
+ return submit(null);
+ }
+
+ /**
+ * Builds the JSON representation of a map/reduce job
+ */
+ public JSONObject toJSON() {
+ JSONObject job = new JSONObject();
+ JSONArray query = new JSONArray();
+ for (MapReducePhase phase : phases) {
+ renderPhase(phase, query);
+ }
+ buildInputs(job);
+ try {
+ job.put("query", query);
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a valid JSONArray");
+ }
+ if (timeout > 0) {
+ try {
+ job.put("timeout", timeout);
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to an int");
+ }
+ }
+ return job;
+ }
+
+ private MapReduceBuilder addPhase(Types phaseType, MapReduceFunction function, boolean keep) {
+ return addPhase(phaseType, function, null, keep);
+ }
+
+ private MapReduceBuilder addPhase(Types phaseType, MapReduceFunction function, Object arg, boolean keep) {
+ MapReducePhase phase = new MapReducePhase();
+ phase.type = phaseType;
+ phase.function = function;
+ phase.arg = arg;
+ phase.keep = keep;
+ phases.add(phase);
+ return this;
+ }
+
+ private void buildInputs(JSONObject job) {
+ if (bucket != null) {
+ try {
+ job.put("inputs", bucket);
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a string");
+ }
+ } else {
+ JSONArray inputs = new JSONArray();
+ for (ByteString bucket : objects.keySet()) {
+ Set<ByteString> keys = objects.get(bucket);
+ for (ByteString key : keys) {
+ ByteString[] pair = { bucket, key };
+ inputs.put(pair);
+ }
+ }
+ try {
+ job.put("inputs", inputs);
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a valid JSONArray");
+ }
+ }
+ }
+
+ private void renderPhase(MapReducePhase phase, JSONArray query) {
+ JSONObject phaseJson = new JSONObject();
+ JSONObject functionJson = phase.function.toJson();
+ try {
+ functionJson.put("keep", phase.keep);
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a boolean");
+ }
+ try {
+ if (phase.arg != null) {
+ functionJson.put("arg", phase.arg);
+ }
+ } catch (JSONException e) {
+ throw new RuntimeException("Cannot convert phase arg to JSON");
+ }
+ String type = null;
+ switch (phase.type) {
+ case MAP:
+ type = "map";
+ break;
+ case REDUCE:
+ type = "reduce";
+ break;
+ case LINK:
+ type = "link";
+ break;
+ }
+ try {
+ phaseJson.put(type, functionJson);
+ } catch (JSONException e) {
+ throw new RuntimeException("Can always map a string to a valid JSONObject");
+ }
+ query.put(phaseJson);
+ }
+
+ private class MapReducePhase {
+ Types type;
+ MapReduceFunction function;
+ Object arg;
+ boolean keep;
+ }
+
+}
View
30 src/com/trifork/riak/mapreduce/MapReduceFunction.java
@@ -0,0 +1,30 @@
+/*
+ * This file is provided 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 com.trifork.riak.mapreduce;
+
+import org.json.JSONObject;
+
+/**
+ * Interface for describing functions used in
+ * map/reduce jobs
+ */
+public interface MapReduceFunction {
+
+ public static enum Types {
+ ANONYMOUS,
+ NAMED
+ }
+
+ public JSONObject toJson();
+}
View
56 src/com/trifork/riak/mapreduce/MapReduceResponse.java
@@ -0,0 +1,56 @@
+/**
+ * This file is part of riak-java-pb-client
+ *
+ * Copyright (c) 2010 by Trifork
+ *
+ * Licensed 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 com.trifork.riak.mapreduce;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import com.google.protobuf.ByteString;
+import com.trifork.riak.RPB.RpbMapRedResp;
+
+public class MapReduceResponse {
+
+ static final ByteString APPLICATION_JSON = ByteString.copyFromUtf8("application/json");
+
+ public final Integer phase;
+ public final ByteString response;
+ private ByteString contentType;
+
+ public MapReduceResponse(RpbMapRedResp resp, ByteString contentType2) {
+ if (resp.hasPhase()) {
+ this.phase = new Integer(resp.getPhase());
+ } else {
+ this.phase = null;
+ }
+ if (resp.hasResponse()) {
+ this.response = resp.getResponse();
+ } else {
+ this.response = null;
+ }
+ this.contentType = contentType2;
+ }
+
+ JSONArray getJSON() throws JSONException {
+ if (response == null)
+ return null;
+ if (!APPLICATION_JSON.equals(contentType))
+ throw new IllegalArgumentException("not application/json");
+ return new JSONArray(response.toStringUtf8());
+ }
+}
View
279 src/org/json/CDL.java
@@ -0,0 +1,279 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * This provides static methods to convert comma delimited text into a
+ * JSONArray, and to covert a JSONArray into comma delimited text. Comma
+ * delimited text is a very popular format for data interchange. It is
+ * understood by most database, spreadsheet, and organizer programs.
+ * <p>
+ * Each row of text represents a row in a table or a data record. Each row
+ * ends with a NEWLINE character. Each row contains one or more values.
+ * Values are separated by commas. A value can contain any character except
+ * for comma, unless is is wrapped in single quotes or double quotes.
+ * <p>
+ * The first row usually contains the names of the columns.
+ * <p>
+ * A comma delimited list can be converted into a JSONArray of JSONObjects.
+ * The names for the elements in the JSONObjects can be taken from the names
+ * in the first row.
+ * @author JSON.org
+ * @version 2009-09-11
+ */
+public class CDL {
+
+ /**
+ * Get the next value. The value can be wrapped in quotes. The value can
+ * be empty.
+ * @param x A JSONTokener of the source text.
+ * @return The value string, or null if empty.
+ * @throws JSONException if the quoted string is badly formed.
+ */
+ private static String getValue(JSONTokener x) throws JSONException {
+ char c;
+ char q;
+ StringBuffer sb;
+ do {
+ c = x.next();
+ } while (c == ' ' || c == '\t');
+ switch (c) {
+ case 0:
+ return null;
+ case '"':
+ case '\'':
+ q = c;
+ sb = new StringBuffer();
+ for (;;) {
+ c = x.next();
+ if (c == q) {
+ break;
+ }
+ if (c == 0 || c == '\n' || c == '\r') {
+ throw x.syntaxError("Missing close quote '" + q + "'.");
+ }
+ sb.append(c);
+ }
+ return sb.toString();
+ case ',':
+ x.back();
+ return "";
+ default:
+ x.back();
+ return x.nextTo(',');
+ }
+ }
+
+ /**
+ * Produce a JSONArray of strings from a row of comma delimited values.
+ * @param x A JSONTokener of the source text.
+ * @return A JSONArray of strings.
+ * @throws JSONException
+ */
+ public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
+ JSONArray ja = new JSONArray();
+ for (;;) {
+ String value = getValue(x);
+ char c = x.next();
+ if (value == null ||
+ (ja.length() == 0 && value.length() == 0 && c != ',')) {
+ return null;
+ }
+ ja.put(value);
+ for (;;) {
+ if (c == ',') {
+ break;
+ }
+ if (c != ' ') {
+ if (c == '\n' || c == '\r' || c == 0) {
+ return ja;
+ }
+ throw x.syntaxError("Bad character '" + c + "' (" +
+ (int)c + ").");
+ }
+ c = x.next();
+ }
+ }
+ }
+
+ /**
+ * Produce a JSONObject from a row of comma delimited text, using a
+ * parallel JSONArray of strings to provides the names of the elements.
+ * @param names A JSONArray of names. This is commonly obtained from the
+ * first row of a comma delimited text file using the rowToJSONArray
+ * method.
+ * @param x A JSONTokener of the source text.
+ * @return A JSONObject combining the names and values.
+ * @throws JSONException
+ */
+ public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
+ throws JSONException {
+ JSONArray ja = rowToJSONArray(x);
+ return ja != null ? ja.toJSONObject(names) : null;
+ }
+
+ /**
+ * Produce a JSONArray of JSONObjects from a comma delimited text string,
+ * using the first row as a source of names.
+ * @param string The comma delimited text.
+ * @return A JSONArray of JSONObjects.
+ * @throws JSONException
+ */
+ public static JSONArray toJSONArray(String string) throws JSONException {
+ return toJSONArray(new JSONTokener(string));
+ }
+
+ /**
+ * Produce a JSONArray of JSONObjects from a comma delimited text string,
+ * using the first row as a source of names.
+ * @param x The JSONTokener containing the comma delimited text.
+ * @return A JSONArray of JSONObjects.
+ * @throws JSONException
+ */
+ public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
+ return toJSONArray(rowToJSONArray(x), x);
+ }
+
+ /**
+ * Produce a JSONArray of JSONObjects from a comma delimited text string
+ * using a supplied JSONArray as the source of element names.
+ * @param names A JSONArray of strings.
+ * @param string The comma delimited text.
+ * @return A JSONArray of JSONObjects.
+ * @throws JSONException
+ */
+ public static JSONArray toJSONArray(JSONArray names, String string)
+ throws JSONException {
+ return toJSONArray(names, new JSONTokener(string));
+ }
+
+ /**
+ * Produce a JSONArray of JSONObjects from a comma delimited text string
+ * using a supplied JSONArray as the source of element names.
+ * @param names A JSONArray of strings.
+ * @param x A JSONTokener of the source text.
+ * @return A JSONArray of JSONObjects.
+ * @throws JSONException
+ */
+ public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
+ throws JSONException {
+ if (names == null || names.length() == 0) {
+ return null;
+ }
+ JSONArray ja = new JSONArray();
+ for (;;) {
+ JSONObject jo = rowToJSONObject(names, x);
+ if (jo == null) {
+ break;
+ }
+ ja.put(jo);
+ }
+ if (ja.length() == 0) {
+ return null;
+ }
+ return ja;
+ }
+
+
+ /**
+ * Produce a comma delimited text row from a JSONArray. Values containing
+ * the comma character will be quoted. Troublesome characters may be
+ * removed.
+ * @param ja A JSONArray of strings.
+ * @return A string ending in NEWLINE.
+ */
+ public static String rowToString(JSONArray ja) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < ja.length(); i += 1) {
+ if (i > 0) {
+ sb.append(',');
+ }
+ Object o = ja.opt(i);
+ if (o != null) {
+ String s = o.toString();
+ if (s.length() > 0 && (s.indexOf(',') >= 0 || s.indexOf('\n') >= 0 ||
+ s.indexOf('\r') >= 0 || s.indexOf(0) >= 0 ||
+ s.charAt(0) == '"')) {
+ sb.append('"');
+ int length = s.length();
+ for (int j = 0; j < length; j += 1) {
+ char c = s.charAt(j);
+ if (c >= ' ' && c != '"') {
+ sb.append(c);
+ }
+ }
+ sb.append('"');
+ } else {
+ sb.append(s);
+ }
+ }
+ }
+ sb.append('\n');
+ return sb.toString();
+ }
+
+ /**
+ * Produce a comma delimited text from a JSONArray of JSONObjects. The
+ * first row will be a list of names obtained by inspecting the first
+ * JSONObject.
+ * @param ja A JSONArray of JSONObjects.
+ * @return A comma delimited text.
+ * @throws JSONException
+ */
+ public static String toString(JSONArray ja) throws JSONException {
+ JSONObject jo = ja.optJSONObject(0);
+ if (jo != null) {
+ JSONArray names = jo.names();
+ if (names != null) {
+ return rowToString(names) + toString(names, ja);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Produce a comma delimited text from a JSONArray of JSONObjects using
+ * a provided list of names. The list of names is not included in the
+ * output.
+ * @param names A JSONArray of strings.
+ * @param ja A JSONArray of JSONObjects.
+ * @return A comma delimited text.
+ * @throws JSONException
+ */
+ public static String toString(JSONArray names, JSONArray ja)
+ throws JSONException {
+ if (names == null || names.length() == 0) {
+ return null;
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < ja.length(); i += 1) {
+ JSONObject jo = ja.optJSONObject(i);
+ if (jo != null) {
+ sb.append(rowToString(jo.toJSONArray(names)));
+ }
+ }
+ return sb.toString();
+ }
+}
View
169 src/org/json/Cookie.java
@@ -0,0 +1,169 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * Convert a web browser cookie specification to a JSONObject and back.
+ * JSON and Cookies are both notations for name/value pairs.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class Cookie {
+
+ /**
+ * Produce a copy of a string in which the characters '+', '%', '=', ';'
+ * and control characters are replaced with "%hh". This is a gentle form
+ * of URL encoding, attempting to cause as little distortion to the
+ * string as possible. The characters '=' and ';' are meta characters in
+ * cookies. By convention, they are escaped using the URL-encoding. This is
+ * only a convention, not a standard. Often, cookies are expected to have
+ * encoded values. We encode '=' and ';' because we must. We encode '%' and
+ * '+' because they are meta characters in URL encoding.
+ * @param string The source string.
+ * @return The escaped result.
+ */
+ public static String escape(String string) {
+ char c;
+ String s = string.trim();
+ StringBuffer sb = new StringBuffer();
+ int len = s.length();
+ for (int i = 0; i < len; i += 1) {
+ c = s.charAt(i);
+ if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
+ sb.append('%');
+ sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16));
+ sb.append(Character.forDigit((char)(c & 0x0f), 16));
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Convert a cookie specification string into a JSONObject. The string
+ * will contain a name value pair separated by '='. The name and the value
+ * will be unescaped, possibly converting '+' and '%' sequences. The
+ * cookie properties may follow, separated by ';', also represented as
+ * name=value (except the secure property, which does not have a value).
+ * The name will be stored under the key "name", and the value will be
+ * stored under the key "value". This method does not do checking or
+ * validation of the parameters. It only converts the cookie string into
+ * a JSONObject.
+ * @param string The cookie specification string.
+ * @return A JSONObject containing "name", "value", and possibly other
+ * members.
+ * @throws JSONException
+ */
+ public static JSONObject toJSONObject(String string) throws JSONException {
+ String n;
+ JSONObject o = new JSONObject();
+ Object v;
+ JSONTokener x = new JSONTokener(string);
+ o.put("name", x.nextTo('='));
+ x.next('=');
+ o.put("value", x.nextTo(';'));
+ x.next();
+ while (x.more()) {
+ n = unescape(x.nextTo("=;"));
+ if (x.next() != '=') {
+ if (n.equals("secure")) {
+ v = Boolean.TRUE;
+ } else {
+ throw x.syntaxError("Missing '=' in cookie parameter.");
+ }
+ } else {
+ v = unescape(x.nextTo(';'));
+ x.next();
+ }
+ o.put(n, v);
+ }
+ return o;
+ }
+
+
+ /**
+ * Convert a JSONObject into a cookie specification string. The JSONObject
+ * must contain "name" and "value" members.
+ * If the JSONObject contains "expires", "domain", "path", or "secure"
+ * members, they will be appended to the cookie specification string.
+ * All other members are ignored.
+ * @param o A JSONObject
+ * @return A cookie specification string
+ * @throws JSONException
+ */
+ public static String toString(JSONObject o) throws JSONException {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append(escape(o.getString("name")));
+ sb.append("=");
+ sb.append(escape(o.getString("value")));
+ if (o.has("expires")) {
+ sb.append(";expires=");
+ sb.append(o.getString("expires"));
+ }
+ if (o.has("domain")) {
+ sb.append(";domain=");
+ sb.append(escape(o.getString("domain")));
+ }
+ if (o.has("path")) {
+ sb.append(";path=");
+ sb.append(escape(o.getString("path")));
+ }
+ if (o.optBoolean("secure")) {
+ sb.append(";secure");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convert <code>%</code><i>hh</i> sequences to single characters, and
+ * convert plus to space.
+ * @param s A string that may contain
+ * <code>+</code>&nbsp;<small>(plus)</small> and
+ * <code>%</code><i>hh</i> sequences.
+ * @return The unescaped string.
+ */
+ public static String unescape(String s) {
+ int len = s.length();
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < len; ++i) {
+ char c = s.charAt(i);
+ if (c == '+') {
+ c = ' ';
+ } else if (c == '%' && i + 2 < len) {
+ int d = JSONTokener.dehexchar(s.charAt(i + 1));
+ int e = JSONTokener.dehexchar(s.charAt(i + 2));
+ if (d >= 0 && e >= 0) {
+ c = (char)(d * 16 + e);
+ i += 2;
+ }
+ }
+ b.append(c);
+ }
+ return b.toString();
+ }
+}
View
90 src/org/json/CookieList.java
@@ -0,0 +1,90 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.util.Iterator;
+
+/**
+ * Convert a web browser cookie list string to a JSONObject and back.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class CookieList {
+
+ /**
+ * Convert a cookie list into a JSONObject. A cookie list is a sequence
+ * of name/value pairs. The names are separated from the values by '='.
+ * The pairs are separated by ';'. The names and the values
+ * will be unescaped, possibly converting '+' and '%' sequences.
+ *
+ * To add a cookie to a cooklist,
+ * cookielistJSONObject.put(cookieJSONObject.getString("name"),
+ * cookieJSONObject.getString("value"));
+ * @param string A cookie list string
+ * @return A JSONObject
+ * @throws JSONException
+ */
+ public static JSONObject toJSONObject(String string) throws JSONException {
+ JSONObject o = new JSONObject();
+ JSONTokener x = new JSONTokener(string);
+ while (x.more()) {
+ String name = Cookie.unescape(x.nextTo('='));
+ x.next('=');
+ o.put(name, Cookie.unescape(x.nextTo(';')));
+ x.next();
+ }
+ return o;
+ }
+
+
+ /**
+ * Convert a JSONObject into a cookie list. A cookie list is a sequence
+ * of name/value pairs. The names are separated from the values by '='.
+ * The pairs are separated by ';'. The characters '%', '+', '=', and ';'
+ * in the names and values are replaced by "%hh".
+ * @param o A JSONObject
+ * @return A cookie list string
+ * @throws JSONException
+ */
+ public static String toString(JSONObject o) throws JSONException {
+ boolean b = false;
+ @SuppressWarnings("unchecked") Iterator keys = o.keys();
+ String s;
+ StringBuffer sb = new StringBuffer();
+ while (keys.hasNext()) {
+ s = keys.next().toString();
+ if (!o.isNull(s)) {
+ if (b) {
+ sb.append(';');
+ }
+ sb.append(Cookie.escape(s));
+ sb.append("=");
+ sb.append(Cookie.escape(o.getString(s)));
+ b = true;
+ }
+ }
+ return sb.toString();
+ }
+}
View
163 src/org/json/HTTP.java
@@ -0,0 +1,163 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.util.Iterator;
+
+/**
+ * Convert an HTTP header to a JSONObject and back.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class HTTP {
+
+ /** Carriage return/line feed. */
+ public static final String CRLF = "\r\n";
+
+ /**
+ * Convert an HTTP header string into a JSONObject. It can be a request
+ * header or a response header. A request header will contain
+ * <pre>{
+ * Method: "POST" (for example),
+ * "Request-URI": "/" (for example),
+ * "HTTP-Version": "HTTP/1.1" (for example)
+ * }</pre>
+ * A response header will contain
+ * <pre>{
+ * "HTTP-Version": "HTTP/1.1" (for example),
+ * "Status-Code": "200" (for example),
+ * "Reason-Phrase": "OK" (for example)
+ * }</pre>
+ * In addition, the other parameters in the header will be captured, using
+ * the HTTP field names as JSON names, so that <pre>
+ * Date: Sun, 26 May 2002 18:06:04 GMT
+ * Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
+ * Cache-Control: no-cache</pre>
+ * become
+ * <pre>{...
+ * Date: "Sun, 26 May 2002 18:06:04 GMT",
+ * Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
+ * "Cache-Control": "no-cache",
+ * ...}</pre>
+ * It does no further checking or conversion. It does not parse dates.
+ * It does not do '%' transforms on URLs.
+ * @param string An HTTP header string.
+ * @return A JSONObject containing the elements and attributes
+ * of the XML string.
+ * @throws JSONException
+ */
+ public static JSONObject toJSONObject(String string) throws JSONException {
+ JSONObject o = new JSONObject();
+ HTTPTokener x = new HTTPTokener(string);
+ String t;
+
+ t = x.nextToken();
+ if (t.toUpperCase().startsWith("HTTP")) {
+
+// Response
+
+ o.put("HTTP-Version", t);
+ o.put("Status-Code", x.nextToken());
+ o.put("Reason-Phrase", x.nextTo('\0'));
+ x.next();
+
+ } else {
+
+// Request
+
+ o.put("Method", t);
+ o.put("Request-URI", x.nextToken());
+ o.put("HTTP-Version", x.nextToken());
+ }
+
+// Fields
+
+ while (x.more()) {
+ String name = x.nextTo(':');
+ x.next(':');
+ o.put(name, x.nextTo('\0'));
+ x.next();
+ }
+ return o;
+ }
+
+
+ /**
+ * Convert a JSONObject into an HTTP header. A request header must contain
+ * <pre>{
+ * Method: "POST" (for example),
+ * "Request-URI": "/" (for example),
+ * "HTTP-Version": "HTTP/1.1" (for example)
+ * }</pre>
+ * A response header must contain
+ * <pre>{
+ * "HTTP-Version": "HTTP/1.1" (for example),
+ * "Status-Code": "200" (for example),
+ * "Reason-Phrase": "OK" (for example)
+ * }</pre>
+ * Any other members of the JSONObject will be output as HTTP fields.
+ * The result will end with two CRLF pairs.
+ * @param o A JSONObject
+ * @return An HTTP header string.
+ * @throws JSONException if the object does not contain enough
+ * information.
+ */
+ public static String toString(JSONObject o) throws JSONException {
+ @SuppressWarnings("unchecked") Iterator keys = o.keys();
+ String s;
+ StringBuffer sb = new StringBuffer();
+ if (o.has("Status-Code") && o.has("Reason-Phrase")) {
+ sb.append(o.getString("HTTP-Version"));
+ sb.append(' ');
+ sb.append(o.getString("Status-Code"));
+ sb.append(' ');
+ sb.append(o.getString("Reason-Phrase"));
+ } else if (o.has("Method") && o.has("Request-URI")) {
+ sb.append(o.getString("Method"));
+ sb.append(' ');
+ sb.append('"');
+ sb.append(o.getString("Request-URI"));
+ sb.append('"');
+ sb.append(' ');
+ sb.append(o.getString("HTTP-Version"));
+ } else {
+ throw new JSONException("Not enough material for an HTTP header.");
+ }
+ sb.append(CRLF);
+ while (keys.hasNext()) {
+ s = keys.next().toString();
+ if (!s.equals("HTTP-Version") && !s.equals("Status-Code") &&
+ !s.equals("Reason-Phrase") && !s.equals("Method") &&
+ !s.equals("Request-URI") && !o.isNull(s)) {
+ sb.append(s);
+ sb.append(": ");
+ sb.append(o.getString(s));
+ sb.append(CRLF);
+ }
+ }
+ sb.append(CRLF);
+ return sb.toString();
+ }
+}
View
77 src/org/json/HTTPTokener.java
@@ -0,0 +1,77 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * The HTTPTokener extends the JSONTokener to provide additional methods
+ * for the parsing of HTTP headers.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class HTTPTokener extends JSONTokener {
+
+ /**
+ * Construct an HTTPTokener from a string.
+ * @param s A source string.
+ */
+ public HTTPTokener(String s) {
+ super(s);
+ }
+
+
+ /**
+ * Get the next token or string. This is used in parsing HTTP headers.
+ * @throws JSONException
+ * @return A String.
+ */
+ public String nextToken() throws JSONException {
+ char c;
+ char q;
+ StringBuffer sb = new StringBuffer();
+ do {
+ c = next();
+ } while (Character.isWhitespace(c));
+ if (c == '"' || c == '\'') {
+ q = c;
+ for (;;) {
+ c = next();
+ if (c < ' ') {
+ throw syntaxError("Unterminated string.");
+ }
+ if (c == q) {
+ return sb.toString();
+ }
+ sb.append(c);
+ }
+ }
+ for (;;) {
+ if (c == 0 || Character.isWhitespace(c)) {
+ return sb.toString();
+ }
+ sb.append(c);
+ c = next();
+ }
+ }
+}
View
917 src/org/json/JSONArray.java
@@ -0,0 +1,917 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A JSONArray is an ordered sequence of values. Its external text form is a
+ * string wrapped in square brackets with commas separating the values. The
+ * internal form is an object having <code>get</code> and <code>opt</code>
+ * methods for accessing the values by index, and <code>put</code> methods for
+ * adding or replacing values. The values can be any of these types:
+ * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
+ * <code>Number</code>, <code>String</code>, or the
+ * <code>JSONObject.NULL object</code>.
+ * <p>
+ * The constructor can convert a JSON text into a Java object. The
+ * <code>toString</code> method converts to JSON text.
+ * <p>
+ * A <code>get</code> method returns a value if one can be found, and throws an
+ * exception if one cannot be found. An <code>opt</code> method returns a
+ * default value instead of throwing an exception, and so is useful for
+ * obtaining optional values.
+ * <p>
+ * The generic <code>get()</code> and <code>opt()</code> methods return an
+ * object which you can cast or query for type. There are also typed
+ * <code>get</code> and <code>opt</code> methods that do type checking and type
+ * coercion for you.
+ * <p>
+ * The texts produced by the <code>toString</code> methods strictly conform to
+ * JSON syntax rules. The constructors are more forgiving in the texts they will
+ * accept:
+ * <ul>
+ * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
+ * before the closing bracket.</li>
+ * <li>The <code>null</code> value will be inserted when there
+ * is <code>,</code>&nbsp;<small>(comma)</small> elision.</li>
+ * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
+ * quote)</small>.</li>
+ * <li>Strings do not need to be quoted at all if they do not begin with a quote
+ * or single quote, and if they do not contain leading or trailing spaces,
+ * and if they do not contain any of these characters:
+ * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
+ * and if they are not the reserved words <code>true</code>,
+ * <code>false</code>, or <code>null</code>.</li>
+ * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
+ * well as by <code>,</code> <small>(comma)</small>.</li>
+ * <li>Numbers may have the
+ * <code>0x-</code> <small>(hex)</small> prefix.</li>
+ * </ul>
+
+ * @author JSON.org
+ * @version 2009-04-14
+ */
+@SuppressWarnings("unchecked") public class JSONArray {
+
+
+ /**
+ * The arrayList where the JSONArray's properties are kept.
+ */
+ private ArrayList myArrayList;
+
+
+ /**
+ * Construct an empty JSONArray.
+ */
+ public JSONArray() {
+ this.myArrayList = new ArrayList();
+ }
+
+ /**
+ * Construct a JSONArray from a JSONTokener.
+ * @param x A JSONTokener
+ * @throws JSONException If there is a syntax error.
+ */
+ public JSONArray(JSONTokener x) throws JSONException {
+ this();
+ char c = x.nextClean();
+ char q;
+ if (c == '[') {
+ q = ']';
+ } else if (c == '(') {
+ q = ')';
+ } else {
+ throw x.syntaxError("A JSONArray text must start with '['");
+ }
+ if (x.nextClean() == ']') {
+ return;
+ }
+ x.back();
+ for (;;) {
+ if (x.nextClean() == ',') {
+ x.back();
+ this.myArrayList.add(null);
+ } else {
+ x.back();
+ this.myArrayList.add(x.nextValue());
+ }
+ c = x.nextClean();
+ switch (c) {
+ case ';':
+ case ',':
+ if (x.nextClean() == ']') {
+ return;
+ }
+ x.back();
+ break;
+ case ']':
+ case ')':
+ if (q != c) {
+ throw x.syntaxError("Expected a '" + new Character(q) + "'");
+ }
+ return;
+ default:
+ throw x.syntaxError("Expected a ',' or ']'");
+ }
+ }
+ }
+
+
+ /**
+ * Construct a JSONArray from a source JSON text.
+ * @param source A string that begins with
+ * <code>[</code>&nbsp;<small>(left bracket)</small>
+ * and ends with <code>]</code>&nbsp;<small>(right bracket)</small>.
+ * @throws JSONException If there is a syntax error.
+ */
+ public JSONArray(String source) throws JSONException {
+ this(new JSONTokener(source));
+ }
+
+
+ /**
+ * Construct a JSONArray from a Collection.
+ * @param collection A Collection.
+ */
+ public JSONArray(Collection collection) {
+ this.myArrayList = new ArrayList();
+ if (collection != null) {
+ Iterator iter = collection.iterator();;
+ while (iter.hasNext()) {
+ Object o = iter.next();
+ this.myArrayList.add(JSONObject.wrap(o));
+ }
+ }
+ }
+
+
+ /**
+ * Construct a JSONArray from an array
+ * @throws JSONException If not an array.
+ */
+ public JSONArray(Object array) throws JSONException {
+ this();
+ if (array.getClass().isArray()) {
+ int length = Array.getLength(array);
+ for (int i = 0; i < length; i += 1) {
+ this.put(JSONObject.wrap(Array.get(array, i)));
+ }
+ } else {
+ throw new JSONException("JSONArray initial value should be a string or collection or array.");
+ }
+ }
+
+
+ /**
+ * Get the object value associated with an index.
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return An object value.
+ * @throws JSONException If there is no value for the index.
+ */
+ public Object get(int index) throws JSONException {
+ Object o = opt(index);
+ if (o == null) {
+ throw new JSONException("JSONArray[" + index + "] not found.");
+ }
+ return o;
+ }
+
+
+ /**
+ * Get the boolean value associated with an index.
+ * The string values "true" and "false" are converted to boolean.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The truth.
+ * @throws JSONException If there is no value for the index or if the
+ * value is not convertable to boolean.
+ */
+ public boolean getBoolean(int index) throws JSONException {
+ Object o = get(index);
+ if (o.equals(Boolean.FALSE) ||
+ (o instanceof String &&
+ ((String)o).equalsIgnoreCase("false"))) {
+ return false;
+ } else if (o.equals(Boolean.TRUE) ||
+ (o instanceof String &&
+ ((String)o).equalsIgnoreCase("true"))) {
+ return true;
+ }
+ throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
+ }
+
+
+ /**
+ * Get the double value associated with an index.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException If the key is not found or if the value cannot
+ * be converted to a number.
+ */
+ public double getDouble(int index) throws JSONException {
+ Object o = get(index);
+ try {
+ return o instanceof Number ?
+ ((Number)o).doubleValue() :
+ Double.valueOf((String)o).doubleValue();
+ } catch (Exception e) {
+ throw new JSONException("JSONArray[" + index +
+ "] is not a number.");
+ }
+ }
+
+
+ /**
+ * Get the int value associated with an index.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException If the key is not found or if the value cannot
+ * be converted to a number.
+ * if the value cannot be converted to a number.
+ */
+ public int getInt(int index) throws JSONException {
+ Object o = get(index);
+ return o instanceof Number ?
+ ((Number)o).intValue() : (int)getDouble(index);
+ }
+
+
+ /**
+ * Get the JSONArray associated with an index.
+ * @param index The index must be between 0 and length() - 1.
+ * @return A JSONArray value.
+ * @throws JSONException If there is no value for the index. or if the
+ * value is not a JSONArray
+ */
+ public JSONArray getJSONArray(int index) throws JSONException {
+ Object o = get(index);
+ if (o instanceof JSONArray) {
+ return (JSONArray)o;
+ }
+ throw new JSONException("JSONArray[" + index +
+ "] is not a JSONArray.");
+ }
+
+
+ /**
+ * Get the JSONObject associated with an index.
+ * @param index subscript
+ * @return A JSONObject value.
+ * @throws JSONException If there is no value for the index or if the
+ * value is not a JSONObject
+ */
+ public JSONObject getJSONObject(int index) throws JSONException {
+ Object o = get(index);
+ if (o instanceof JSONObject) {
+ return (JSONObject)o;
+ }
+ throw new JSONException("JSONArray[" + index +
+ "] is not a JSONObject.");
+ }
+
+
+ /**
+ * Get the long value associated with an index.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException If the key is not found or if the value cannot
+ * be converted to a number.
+ */
+ public long getLong(int index) throws JSONException {
+ Object o = get(index);
+ return o instanceof Number ?
+ ((Number)o).longValue() : (long)getDouble(index);
+ }
+
+
+ /**
+ * Get the string associated with an index.
+ * @param index The index must be between 0 and length() - 1.
+ * @return A string value.
+ * @throws JSONException If there is no value for the index.
+ */
+ public String getString(int index) throws JSONException {
+ return get(index).toString();
+ }
+
+
+ /**
+ * Determine if the value is null.
+ * @param index The index must be between 0 and length() - 1.
+ * @return true if the value at the index is null, or if there is no value.
+ */
+ public boolean isNull(int index) {
+ return JSONObject.NULL.equals(opt(index));
+ }
+
+
+ /**
+ * Make a string from the contents of this JSONArray. The
+ * <code>separator</code> string is inserted between each element.
+ * Warning: This method assumes that the data structure is acyclical.
+ * @param separator A string that will be inserted between the elements.
+ * @return a string.
+ * @throws JSONException If the array contains an invalid number.
+ */
+ public String join(String separator) throws JSONException {
+ int len = length();
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < len; i += 1) {
+ if (i > 0) {
+ sb.append(separator);
+ }
+ sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Get the number of elements in the JSONArray, included nulls.
+ *
+ * @return The length (or size).
+ */
+ public int length() {
+ return this.myArrayList.size();
+ }
+
+
+ /**
+ * Get the optional object value associated with an index.
+ * @param index The index must be between 0 and length() - 1.
+ * @return An object value, or null if there is no
+ * object at that index.
+ */
+ public Object opt(int index) {
+ return (index < 0 || index >= length()) ?
+ null : this.myArrayList.get(index);
+ }
+
+
+ /**
+ * Get the optional boolean value associated with an index.
+ * It returns false if there is no value at that index,
+ * or if the value is not Boolean.TRUE or the String "true".
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The truth.
+ */
+ public boolean optBoolean(int index) {
+ return optBoolean(index, false);
+ }
+
+
+ /**
+ * Get the optional boolean value associated with an index.
+ * It returns the defaultValue if there is no value at that index or if
+ * it is not a Boolean or the String "true" or "false" (case insensitive).
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue A boolean default.
+ * @return The truth.
+ */
+ public boolean optBoolean(int index, boolean defaultValue) {
+ try {
+ return getBoolean(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional double value associated with an index.
+ * NaN is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public double optDouble(int index) {
+ return optDouble(index, Double.NaN);
+ }
+
+
+ /**
+ * Get the optional double value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index subscript
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public double optDouble(int index, double defaultValue) {
+ try {
+ return getDouble(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional int value associated with an index.
+ * Zero is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public int optInt(int index) {
+ return optInt(index, 0);
+ }
+
+
+ /**
+ * Get the optional int value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public int optInt(int index, int defaultValue) {
+ try {
+ return getInt(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional JSONArray associated with an index.
+ * @param index subscript
+ * @return A JSONArray value, or null if the index has no value,
+ * or if the value is not a JSONArray.
+ */
+ public JSONArray optJSONArray(int index) {
+ Object o = opt(index);
+ return o instanceof JSONArray ? (JSONArray)o : null;
+ }
+
+
+ /**
+ * Get the optional JSONObject associated with an index.
+ * Null is returned if the key is not found, or null if the index has
+ * no value, or if the value is not a JSONObject.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return A JSONObject value.
+ */
+ public JSONObject optJSONObject(int index) {
+ Object o = opt(index);
+ return o instanceof JSONObject ? (JSONObject)o : null;
+ }
+
+
+ /**
+ * Get the optional long value associated with an index.
+ * Zero is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public long optLong(int index) {
+ return optLong(index, 0);
+ }
+
+
+ /**
+ * Get the optional long value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public long optLong(int index, long defaultValue) {
+ try {
+ return getLong(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get the optional string value associated with an index. It returns an
+ * empty string if there is no value at that index. If the value
+ * is not a string and is not null, then it is coverted to a string.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @return A String value.
+ */
+ public String optString(int index) {
+ return optString(index, "");
+ }
+
+
+ /**
+ * Get the optional string associated with an index.
+ * The defaultValue is returned if the key is not found.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return A String value.
+ */
+ public String optString(int index, String defaultValue) {
+ Object o = opt(index);
+ return o != null ? o.toString() : defaultValue;
+ }
+
+
+ /**
+ * Append a boolean value. This increases the array's length by one.
+ *
+ * @param value A boolean value.
+ * @return this.
+ */
+ public JSONArray put(boolean value) {
+ put(value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+
+ /**
+ * Put a value in the JSONArray, where the value will be a
+ * JSONArray which is produced from a Collection.
+ * @param value A Collection value.
+ * @return this.
+ */
+ public JSONArray put(Collection value) {
+ put(new JSONArray(value));
+ return this;
+ }
+
+
+ /**
+ * Append a double value. This increases the array's length by one.
+ *
+ * @param value A double value.
+ * @throws JSONException if the value is not finite.
+ * @return this.
+ */
+ public JSONArray put(double value) throws JSONException {
+ Double d = new Double(value);
+ JSONObject.testValidity(d);
+ put(d);
+ return this;
+ }
+
+
+ /**
+ * Append an int value. This increases the array's length by one.
+ *
+ * @param value An int value.
+ * @return this.
+ */
+ public JSONArray put(int value) {
+ put(new Integer(value));
+ return this;
+ }
+
+
+ /**
+ * Append an long value. This increases the array's length by one.
+ *
+ * @param value A long value.
+ * @return this.
+ */
+ public JSONArray put(long value) {
+ put(new Long(value));
+ return this;
+ }
+
+
+ /**
+ * Put a value in the JSONArray, where the value will be a
+ * JSONObject which is produced from a Map.
+ * @param value A Map value.
+ * @return this.
+ */
+ public JSONArray put(Map value) {
+ put(new JSONObject(value));
+ return this;
+ }
+
+
+ /**
+ * Append an object value. This increases the array's length by one.
+ * @param value An object value. The value should be a
+ * Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
+ * JSONObject.NULL object.
+ * @return this.
+ */
+ public JSONArray put(Object value) {
+ this.myArrayList.add(value);
+ return this;
+ }
+
+
+ /**
+ * Put or replace a boolean value in the JSONArray. If the index is greater
+ * than the length of the JSONArray, then null elements will be added as
+ * necessary to pad it out.
+ * @param index The subscript.
+ * @param value A boolean value.
+ * @return this.
+ * @throws JSONException If the index is negative.
+ */
+ public JSONArray put(int index, boolean value) throws JSONException {
+ put(index, value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+
+ /**
+ * Put a value in the JSONArray, where the value will be a
+ * JSONArray which is produced from a Collection.
+ * @param index The subscript.
+ * @param value A Collection value.
+ * @return this.
+ * @throws JSONException If the index is negative or if the value is
+ * not finite.
+ */
+ public JSONArray put(int index, Collection value) throws JSONException {
+ put(index, new JSONArray(value));
+ return this;
+ }
+
+
+ /**
+ * Put or replace a double value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad
+ * it out.
+ * @param index The subscript.
+ * @param value A double value.
+ * @return this.
+ * @throws JSONException If the index is negative or if the value is
+ * not finite.
+ */
+ public JSONArray put(int index, double value) throws JSONException {
+ put(index, new Double(value));
+ return this;
+ }
+
+
+ /**
+ * Put or replace an int value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad
+ * it out.