/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.oobd.base.support; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONException; import org.oobd.base.Base64Coder; /** * Onion provides the transport medium of the different data arrays which have * to be carried through the process * * It is made internally as a set of nested hash arrays, but from outside it's * acessed by a key/value pair, where the key is simular to a folder path, where * a folder may contains other folders, means other onions * * @author steffen */ // public class Onion extends Hashtable<String, Object> { public class Onion extends JSONObject { /** * Help class to ease internal data handling, used as function return data * including key and onion, to which this key belongs to */ class OnionData { public Onion onion; public String key; /** * stores Onion and key string to be used as bundled return value from * some internal function * * @param thisOnion * @param thisKey */ OnionData(Onion thisOnion, String thisKey) { onion = thisOnion; key = thisKey; } } /** * Default Constructor */ public Onion() { super(); } /** * Constructor to generate Onion from JSON- String * * @param jsonString * @throws JSONException */ public Onion(String jsonString) throws JSONException { super(jsonString); } /** * takes a fresh Onion from the pool (if available) * * @author steffen * @return a new onion * @todo does a onion- pool needs to be implemented? */ static public Onion generate() { return new Onion(); } /** * declares the oldunion as not longer be used * * @param oldonion * @return null * @todo does a onion- pool needs to be implemented? */ static public Onion push(Onion oldonion) { oldonion = null; return null; } /** * returns the object at the given path * * @param path * /path/to/object * @return object or null * @todo not yet implemented * @throws OnionNoEntryException */ public Object getOnionObject(String path) throws OnionNoEntryException { Onion actOnion = this; String[] parts = path.split("/"); // split the path into the leading // part and the rest int i = 0; while (i < parts.length - 1) { // the last entry in parts is the key for // the last sub onion, so we have to // handle that seperately in the end try { if (!actOnion.has(parts[i]) || !(actOnion.get(parts[i]) instanceof JSONObject)) { // if // that // key // does // not // exist // or // is // not // a // sub // onion throw new OnionNoEntryException(); } else { actOnion = new Onion( ((JSONObject) actOnion.get(parts[i])).toString()); } } catch (JSONException e) { throw new OnionNoEntryException(); } i++; } try { Object actObject = actOnion.get(parts[i]); if (actObject instanceof JSONObject) { return new Onion(((JSONObject) actObject).toString()); } else { return actObject; } } catch (JSONException e) { throw new OnionNoEntryException(); } } /** * returns the string value at the given path * * @param path * /path/to/value * @return string * @todo not yet implemented * @throws OnionWrongTypeException */ public String getOnionString(String path) { try { Object result = getOnionObject(path); if (!(result instanceof String)) { return null; } return (String) result; } catch (OnionNoEntryException e) { return null; } } /** * returns the string value at the given path at index * * @param path * /path/to/value * @return ArrayList<Onion> */ public ArrayList<Onion> getOnionArray(String path, String name) { ArrayList<Onion> res = new ArrayList<Onion>(); try { JSONArray r = JSONArray(path); if (r != null) { for (int i = 0; i < r.length(); i++) { res.add(new Onion(r.get(i).toString())); } return res; } } catch (JSONException e) { return null; } return res; } /** * returns and decodes the base64 encoded string value at the given path * * @param path * /path/to/value * @return string * @todo not yet implemented * @throws OnionWrongTypeException */ public String getOnionBase64String(String path) { String res = getOnionString(path); if (res != null) { return (Base64Coder.decodeString(res)); } else { return null; } } /** * returns the string value at the given path * * @param path * /path/to/value * @return string * @todo not yet implemented * @throws OnionWrongTypeException */ public Onion getOnion(String path) { try { Object result = getOnionObject(path); if (!(result instanceof JSONObject)) { return null; } return new Onion(result.toString()); } catch (OnionNoEntryException e) { return null; } catch (JSONException ex) { return null; } } /** * returns the string value at the given path * * @param path * /path/to/value * @return string * @todo not yet implemented * @throws OnionWrongTypeException */ public JSONArray JSONArray(String path) { try { Object result = getOnionObject(path); if (!(result instanceof JSONArray)) { return null; } return (JSONArray) result; } catch (OnionNoEntryException e) { return null; } } /** * checks, if the onion has the specified type "type" * * @param type * name of requested type * @return boolean */ public boolean isType(String type) { try { return type.matches(this.getString("type")); } catch (JSONException ex) { return false; } } /** * set the String value at the given path. * * path consist of an optional directory and the key name, seperated by /, * like path/to/value, where the last value is used as key for the onion * hash. * * @param path * @param value * @return onion which contains generated key:value */ public Onion setValue(String path, String value) { OnionData od = createPath(path); if (od != null) { try { od.onion.put(od.key, value); } catch (JSONException e) { return null; } return od.onion; } else { return null; } } /** * set the String value at the given path as base64 encoded string. * * path consist of an optional directory and the key name, seperated by /, * like path/to/value, where the last value is used as key for the onion * hash. * * @param path * @param value * @return onion which contains generated key:value */ public Onion setBase64Value(String path, String value) { return setValue(path, Base64Coder.encodeString(value)); } /** * set the int value at the given path. * * path consist of an optional directory and the key name, seperated by /, * like path/to/value, where the last value is used as key for the onion * hash. * * @param path * @param value * @return onion which contains generated key:value */ public Onion setValue(String path, int value) { OnionData od = createPath(path); if (od != null) { try { od.onion.put(od.key, value); } catch (JSONException e) { return null; } return od.onion; } else { return null; } } /** * generates the reqested onion structure * * @param path * @return the onion which points to the given path and the remaining piece * of the part, which should be used as key for the hash * @bug the routine itself supports relative directories and a leading root- * /, but this is not supplied by superclass JSONObject, so it either * needs to be deleted or made functional */ OnionData createPath(String path) { if (!path.contains("/")) { // in case there no path at all, just a key // value, return this return new OnionData(this, path); } Onion actOnion = this; String lastpart = ""; String[] head = path.split("/", 2); // split the path into the leading // part and the rest while (!head[1].matches("") || !head[0].matches("")) {// as long there's // still // something in // the path if (!head[0].matches("")) { // no leading part? That must be a typo // then, let's just jump to the next lastpart = head[0]; try { if (!actOnion.has(lastpart) || !(actOnion.get(lastpart) instanceof Onion)) { // if // that // key // does // not // exist // or // is // just // a // base // type if (!head[1].matches("")) {// do we have to create // another sub onion? Onion newOnion = new Onion(); actOnion.put(lastpart, newOnion); // adds the new // element actOnion = newOnion; } } else { actOnion = (Onion) actOnion.get(lastpart); } } catch (JSONException e) { } } if (head[1].contains("/")) { head = head[1].split("/", 2); } else { head[0] = head[1]; head[1] = ""; // stop condition for surrounding while- loop } } if (!lastpart.matches("")) { return new OnionData(actOnion, lastpart); } else { return null; // there's no actual key value, so path is invalid... } } /** * takes the value of an onion element and releases all subelements, if it * is an onion * * @param value * @bug delete behaviour of JSONObjects unclear, so usage of this routine at * all needs to be made functional */ void DestroyOnionPath(Object value) { if (value != null) { if (value instanceof Onion) { while (((Onion) value).keys().hasNext()) { DestroyOnionPath(((Onion) value).keys().next()); } this.push(((Onion) value)); // ((Onion) value).clear(); } } } public Onion setValue(String path, Onion value) { OnionData od = createPath(path); if (od != null) { try { od.onion.put(od.key, value); } catch (JSONException e) { return null; } return od.onion; } else { return null; } } }