001/* 002 * flattr4j - A Java library for Flattr 003 * 004 * Copyright (C) 2011 Richard "Shred" Körber 005 * http://flattr4j.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License / GNU Lesser 009 * General Public License as published by the Free Software Foundation, 010 * either version 3 of the License, or (at your option) any later version. 011 * 012 * Licensed under the Apache License, Version 2.0 (the "License"); 013 * you may not use this file except in compliance with the License. 014 * 015 * This program is distributed in the hope that it will be useful, 016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 018 */ 019package org.shredzone.flattr4j.connector; 020 021import java.io.Externalizable; 022import java.io.IOException; 023import java.io.ObjectInput; 024import java.io.ObjectOutput; 025import java.io.Serializable; 026import java.util.ArrayList; 027import java.util.Collection; 028import java.util.Date; 029import java.util.List; 030 031import org.json.JSONArray; 032import org.json.JSONException; 033import org.json.JSONObject; 034import org.json.JSONTokener; 035import org.shredzone.flattr4j.exception.MarshalException; 036 037/** 038 * Represents the raw Flattr data. 039 * <p> 040 * Basically, this is a wrapper around {@link JSONObject}, which takes care for the 041 * {@link JSONException} and also for serialization of JSON structures. 042 * 043 * @author Richard "Shred" Körber 044 */ 045public class FlattrObject implements Serializable, Externalizable { 046 private static final long serialVersionUID = -6640392574244365803L; 047 048 private transient JSONObject data; 049 050 /** 051 * Creates a new, empty {@link FlattrObject}. 052 */ 053 public FlattrObject() { 054 data = new JSONObject(); 055 } 056 057 /** 058 * Creates a {@link FlattrObject} from the given {@link JSONObject}. 059 * 060 * @param data 061 * {@link JSONObject} to use. It is not cloned. It's contents may be 062 * changed by this {@link FlattrObject}. 063 */ 064 public FlattrObject(JSONObject data) { 065 this.data = data; 066 } 067 068 /** 069 * Creates a {@link FlattrObject} from the given JSON string. 070 * 071 * @param json 072 * JSON string to initialize the {@link FlattrObject} with 073 */ 074 public FlattrObject(String json) { 075 try { 076 this.data = (JSONObject) new JSONTokener(json).nextValue(); 077 } catch (JSONException ex) { 078 throw new MarshalException(ex); 079 } 080 } 081 082 /** 083 * Checks if there is a key. 084 * 085 * @param key 086 * Key to check for 087 * @return {@code true} if there is such a key (value may still be {@code null}). 088 */ 089 public boolean has(String key) { 090 return data.has(key); 091 } 092 093 /** 094 * Gets an Object from the given key. 095 * 096 * @param key 097 * Key to read from 098 * @return Object that was read 099 * @throws MarshalException 100 * if there was no such key 101 */ 102 public Object getObject(String key) { 103 try { 104 return data.get(key); 105 } catch (JSONException ex) { 106 throw new MarshalException(key, ex); 107 } 108 } 109 110 /** 111 * Gets a String from the given key. 112 * 113 * @param key 114 * Key to read from 115 * @return String that was read 116 * @throws MarshalException 117 * if there was no such key 118 */ 119 public String get(String key) { 120 try { 121 return data.getString(key); 122 } catch (JSONException ex) { 123 throw new MarshalException(key, ex); 124 } 125 } 126 127 /** 128 * Gets a String from the given subKey which is a property of the given key. 129 * 130 * @param key 131 * Key of the parent object 132 * @param subKey 133 * Key to read from 134 * @return String that was read 135 * @throws MarshalException 136 * if there was no such key or subKey 137 */ 138 public String getSubString(String key, String subKey) { 139 try { 140 JSONObject obj = data.getJSONObject(key); 141 return obj.getString(subKey); 142 } catch (JSONException ex) { 143 throw new MarshalException(key, ex); 144 } 145 } 146 147 /** 148 * Gets a {@link FlattrObject} from the given key. 149 * 150 * @param key 151 * Key to read from 152 * @return {@link FlattrObject} that was read 153 * @throws MarshalException 154 * if there was no such key 155 */ 156 public FlattrObject getFlattrObject(String key) { 157 try { 158 return new FlattrObject(data.getJSONObject(key)); 159 } catch (JSONException ex) { 160 throw new MarshalException(key, ex); 161 } 162 } 163 164 /** 165 * Gets an integer from the given key. 166 * 167 * @param key 168 * Key to read from 169 * @return integer that was read 170 * @throws MarshalException 171 * if there was no such key, or if it did not contain the expected type 172 */ 173 public int getInt(String key) { 174 try { 175 return data.getInt(key); 176 } catch (JSONException ex) { 177 throw new MarshalException(key, ex); 178 } 179 } 180 181 /** 182 * Gets a long from the given key. 183 * 184 * @param key 185 * Key to read from 186 * @return long that was read 187 * @throws MarshalException 188 * if there was no such key, or if it did not contain the expected type 189 * @since 2.5 190 */ 191 public long getLong(String key) { 192 try { 193 return data.getLong(key); 194 } catch (JSONException ex) { 195 throw new MarshalException(key, ex); 196 } 197 } 198 199 /** 200 * Gets a boolean from the given key. 201 * 202 * @param key 203 * Key to read from 204 * @return boolean that was read 205 * @throws MarshalException 206 * if there was no such key, or if it did not contain the expected type 207 */ 208 public boolean getBoolean(String key) { 209 try { 210 return data.getBoolean(key); 211 } catch (JSONException ex) { 212 throw new MarshalException(key, ex); 213 } 214 } 215 216 /** 217 * Gets a {@link Date} from the given key. 218 * 219 * @param key 220 * Key to read from 221 * @return {@link Date} that was read, or {@code null} if no date was set 222 * @throws MarshalException 223 * if there was no such key, or if it did not contain the expected type 224 */ 225 public Date getDate(String key) { 226 try { 227 if (data.isNull(key)) { 228 return null; 229 } 230 231 long ts = data.getLong(key); 232 return (ts != 0 ? new Date(ts * 1000L) : null); 233 } catch (JSONException ex) { 234 throw new MarshalException(key, ex); 235 } 236 } 237 238 /** 239 * Gets a collection of String from the given key. 240 * 241 * @param key 242 * Key to read from 243 * @return Collection of Strings 244 * @throws MarshalException 245 * if there was no such key, or if it did not contain the expected type 246 */ 247 public List<String> getStrings(String key) { 248 try { 249 JSONArray array = data.getJSONArray(key); 250 List<String> result = new ArrayList<String>(array.length()); 251 for (int ix = 0; ix < array.length(); ix++) { 252 result.add(array.getString(ix)); 253 } 254 return result; 255 } catch (JSONException ex) { 256 throw new MarshalException(key, ex); 257 } 258 } 259 260 /** 261 * Gets a collection of {@link FlattrObject} from the given key. 262 * 263 * @param key 264 * Key to read from 265 * @return Collection of {@link FlattrObject} 266 * @throws MarshalException 267 * if there was no such key, or if it did not contain the expected type 268 */ 269 public List<FlattrObject> getObjects(String key) { 270 try { 271 JSONArray array = data.getJSONArray(key); 272 List<FlattrObject> result = new ArrayList<FlattrObject>(array.length()); 273 for (int ix = 0; ix < array.length(); ix++) { 274 result.add(new FlattrObject(array.getJSONObject(ix))); 275 } 276 return result; 277 } catch (JSONException ex) { 278 throw new MarshalException(key, ex); 279 } 280 } 281 282 /** 283 * Changes the key and sets it to the given value. 284 * 285 * @param key 286 * Key to write to 287 * @param value 288 * Value to be written 289 * @throws MarshalException 290 * if the key could not be changed 291 */ 292 public void put(String key, Object value) { 293 try { 294 data.put(key, value); 295 } catch (JSONException ex) { 296 throw new MarshalException(key, ex); 297 } 298 } 299 300 /** 301 * Puts a collection of strings as array object to the given key. 302 * 303 * @param key 304 * Key to write to 305 * @param value 306 * Collection of Strings to write 307 * @throws MarshalException 308 * if the key could not be changed 309 */ 310 public void putStrings(String key, Collection<String> value) { 311 try { 312 JSONArray array = new JSONArray(); 313 if (value != null) { 314 for (String tag : value) { 315 array.put(tag); 316 } 317 } 318 data.put(key, array); 319 } catch (JSONException ex) { 320 throw new MarshalException(key, ex); 321 } 322 } 323 324 /** 325 * Returns the current state of the {@link FlattrObject} as JSON string. 326 * 327 * @return JSON representation of the current state 328 */ 329 @Override 330 public String toString() { 331 return data.toString(); 332 } 333 334 /** 335 * Returns the {@link JSONObject} that represents this {@link FlattrObject}. Note that 336 * changes to this {@link JSONObject} will affect the {@link FlattrObject} as well. 337 * 338 * @return {@link JSONObject} 339 */ 340 public JSONObject getJSONObject() { 341 return data; 342 } 343 344 @Override 345 public void writeExternal(ObjectOutput out) throws IOException { 346 out.writeUTF(data.toString()); 347 } 348 349 @Override 350 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 351 try { 352 data = new JSONObject(in.readUTF()); 353 } catch (JSONException ex) { 354 throw new IOException("JSON deserialization failed", ex); 355 } 356 } 357 358}