/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2007, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter.wsclient; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Stack; import org.json.JSONArray; import org.json.JSONObject; /** * <p>Title: JsonRequestBuilder</p> * <p>Description: A fluent style builder for JSON formatted requests to the server </p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.wsclient.JsonRequestBuilder</code></p> */ public class JsonRequestBuilder { /** A stack of json objects that are being push into and popped out of focus */ protected final Stack<Object> jsonStack = new Stack<Object>(); /** * Returns a new JsonRequestBuilder initialized with a request id * @return a new JsonRequestBuilder */ public static JsonRequestBuilder newBuilder() { return new JsonRequestBuilder(); } /** * Creates a new JsonRequestBuilder */ protected JsonRequestBuilder() { JsonRequest jr = new JsonRequest(); try { jr.put("t", "req");} catch (Exception ex) { throw new RuntimeException(ex); } jsonStack.push(jr); } /** * Adds a keyed value to the current json node * @param key The entry key * @param value The entry value * @return this builder */ public JsonRequestBuilder put(String key, boolean value) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a keyed value to the current json node * @param key The entry key * @param value The entry value * @return this builder */ public JsonRequestBuilder put(String key, Collection<?> value) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); if(value==null) throw new IllegalArgumentException("The passed value was null", new Throwable()); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a key value pair to a map bound at the map key * @param mapKey The binding name of the map * @param key The pair key * @param value The pair value * @return this builder */ public JsonRequestBuilder putMapPair(String mapKey, String key, Object value) { if(mapKey==null || mapKey.trim().isEmpty()) throw new IllegalArgumentException("The passed mapKey was null or empty", new Throwable()); if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); JSONObject ctx = (JSONObject)jsonStack.peek(); Map<String, Object> map = null; if(!ctx.has(mapKey)) { map = new HashMap<String, Object>(); try { ctx.put(mapKey, map); } catch (Exception ex) {} } else { Object m = null; try { m = ctx.get(mapKey); } catch (Exception ex) {}; map = (Map<String, Object>)m; } map.put(key, value); return this; } /** * Adds a keyed value to the current json node * @param key The entry key * @param value The entry value * @return this builder */ public JsonRequestBuilder put(String key, double value) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a keyed value to the current json node * @param key The entry key * @param value The entry value * @return this builder */ public JsonRequestBuilder put(String key, long value) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a keyed value to the current json node * @param key The entry key * @param value The entry value * @return this builder */ public JsonRequestBuilder put(String key, int value) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a keyed value to the current json node * @param key The entry key * @param value The entry value * @return this builder */ public JsonRequestBuilder put(String key, Object value) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); if(value==null) throw new IllegalArgumentException("The passed value was null", new Throwable()); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a keyed value to the current json node * @param key The entry key * @param value The entry value * @return this builder */ public JsonRequestBuilder put(String key, Map<?,?> value) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); if(value==null) throw new IllegalArgumentException("The passed value was null", new Throwable()); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a new JSONObject to the current content and pushes it onto the context stack * @param key The key of the new JSONObject * @return this builder */ public JsonRequestBuilder putJSONObject(String key) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); typeCheck(JSONObject.class); JSONObject value = new JSONObject(); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } jsonStack.push(value); return this; } /** * Appends the passed value to the JSONArray in current context * @param value The value to append to the array * @return this builder */ public JsonRequestBuilder append(boolean value) { typeCheck(JSONArray.class); try { ((JSONArray)jsonStack.peek()).put(value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Appends the passed value to the JSONArray in current context * @param value The value to append to the array * @return this builder */ public JsonRequestBuilder append(Collection<?> value) { typeCheck(JSONArray.class); if(value==null) throw new IllegalArgumentException("The passed value was null", new Throwable()); try { ((JSONArray)jsonStack.peek()).put(value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Appends the passed value to the JSONArray in current context * @param value The value to append to the array * @return this builder */ public JsonRequestBuilder append(double value) { typeCheck(JSONArray.class); try { ((JSONArray)jsonStack.peek()).put(value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Appends the passed value to the JSONArray in current context * @param value The value to append to the array * @return this builder */ public JsonRequestBuilder append(long value) { typeCheck(JSONArray.class); try { ((JSONArray)jsonStack.peek()).put(value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Appends the passed value to the JSONArray in current context * @param value The value to append to the array * @return this builder */ public JsonRequestBuilder append(int value) { typeCheck(JSONArray.class); try { ((JSONArray)jsonStack.peek()).put(value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Appends the passed value to the JSONArray in current context * @param value The value to append to the array * @return this builder */ public JsonRequestBuilder append(Object value) { typeCheck(JSONArray.class); if(value==null) throw new IllegalArgumentException("The passed value was null", new Throwable()); try { ((JSONArray)jsonStack.peek()).put(value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Appends the passed value to the JSONArray in current context * @param value The value to append to the array * @return this builder */ public JsonRequestBuilder append(Map<?,?> value) { typeCheck(JSONArray.class); if(value==null) throw new IllegalArgumentException("The passed value was null", new Throwable()); try { ((JSONArray)jsonStack.peek()).put(value); } catch (Exception ex) { throw new RuntimeException(ex); } return this; } /** * Adds a new JSONArray to the current content and pushes it onto the context stack * @param key The key of the new JSONArray * @return this builder */ public JsonRequestBuilder putJSONArray(String key) { if(key==null || key.trim().isEmpty()) throw new IllegalArgumentException("The passed key was null or empty", new Throwable()); typeCheck(JSONObject.class); JSONArray value = new JSONArray(); try { ((JSONObject)jsonStack.peek()).put(key, value); } catch (Exception ex) { throw new RuntimeException(ex); } jsonStack.push(value); return this; } /** * Pops the current element off the context stack * @return this builder */ public JsonRequestBuilder pop() { jsonStack.pop(); return this; } /** * Completes the build and returns the root JSONObject * @return the root JSONObject */ public JsonRequest build() { typeCheck(JsonRequest.class); if(jsonStack.size()!=1) throw new RuntimeException("Incomplete pop state. Expected context size of 1 but was " + jsonStack.size(), new Throwable()); return (JsonRequest)jsonStack.pop(); } /** * Executes a type check against the current stack context * @param expectedClass The expected class of the current context */ protected void typeCheck(Class<?> expectedClass) { if(!expectedClass.isInstance(jsonStack.peek())) throw new IllegalStateException("Unassignable Op. Expected context: [" + expectedClass.getSimpleName() + "] Actual Context: [" + jsonStack.peek().getClass().getSimpleName() + "]", new Throwable()); } /* EXAMPLE: ======= JSONObject request = new JSONObject(); int reqId = client.requestSerial.incrementAndGet(); request.put("rid", reqId); request.put("t", "req"); request.put("svc", "sub"); request.put("op", "start"); JSONObject ags = new JSONObject(); ags.put("es", "jmx"); ags.put("esn", "service:jmx:local://DefaultDomain"); ags.put("f", "org.helios.apmrouter.session:service=SharedChannelGroup"); request.put("args", ags); */ }