All Downloads are FREE. Search and download functionalities are using the official Maven repository.

Data.Storage Maven / Gradle / Ivy

package Data;

import DataTools.ConvertObjectToJson;
import DataTools.Utils;
import StorageHelper.Converter;
import StorageHelper.CreatorHelper;
import StorageHelper.PathParser;
import StorageHelper.RetrieveByPath;
import StorageHelper.Update;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import org.dom4j.Element;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.sip.message.Response;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 Copyright 2016 Alianza Inc.

 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.

 */

/**
 * A place to hold data that endpoints will need to interact with the system
 * can handle different formats of data
 */
public class Storage {

    private final HashMap storage;

    /**
     * default constructor
     */
    public Storage() {
        storage = new HashMap<>();
    }

    /**
     * constructor that populates the collections with given data
     * @param json JSONObject of data
     */
    public Storage(JSONObject json) {
        this();
        addJson(json);
    }

    /**
     * constructor that populates the collections with given data
     * @param json JSONArray of data
     */
    public Storage(JSONArray json) {
        this();
        addJson(json);
    }

    /**
     * constructor that populates the collections with given data
     * @param data String of data or json String
     */
    public Storage(String data) {
        storage = CreatorHelper.createDataStorage(data).getMap();
    }

    /**
     * constructor that populates the collections with given sip data response
     * @param sipResponse SIPResponse from a sip request
     */
    public Storage(Response sipResponse) {
        this();
        addSip(sipResponse);
    }

    /**
     * constructor that populates the collections with given data
     * @param model ax model of data
     */
    public  Storage(T model) {
        this();
        addModel(model);
    }

    /**
     * constructor that populates the collections with given data
     * @param dataMap hash map of data
     */
    public Storage(HashMap dataMap) {
        this();
        addMap(dataMap);
    }

    /**
     * constructor that populates the collections with given data
     * @param array of data
     */
    public Storage(ArrayList array) {
        this();
        addArray(array);
    }

    /**
     * adding an item to the collection
     * @param key index item is stored by
     * @param value actual data being stored
     */
    public void put(String key, Object value) {
        storage.put(key, value);
    }

    /**
     * adding an item to the collection, if its string see if it is json string
     * @param key index item is stored by
     * @param value string of the data, can be json string or just a string
     */
    public void put(String key, String value) {
        try {
            if (Utils.isJsonArray(value))
                storage.put(key, new JSONArray(value));
            else if (Utils.isJSONObject(value))
                storage.put(key, new JSONObject(value));
            else if (value.startsWith("<") && value.endsWith(">"))
                addXml(Converter.xmlStringToElement(value));
            else
                storage.put(key, value);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * adding a data Storage to the collection
     * @param key index item is stored by
     * @param value actual data storage data to be stored
     */
    public void put(String key, Storage value) {
        try {
            //find out if it is an array or json
            //if the collection is empty then hashmap
            boolean isArray = true;
            for(String storageKey : value.keys())
                for(char k : storageKey.toCharArray())
                    //if there is just one key not a digit then not array
                    if (!Character.isDigit(k))
                        isArray = false;

            //if the collection is empty then hashmap
            if (value.keys().size() > 0 && isArray){
                HashMap newJson = new HashMap<>();
                newJson.put(key, value.getJsonArray());
                addMap(newJson);
            }
            else {
                JSONObject newJson = new JSONObject();
                newJson.put(key, value.getJson());
                addJson(newJson);
            }

        } catch (JSONException e) {
            Utils.debug("unable to add to Data Storage:\nStorage: " + toString() + "\nAdding: " + value.toString(), "error");
            e.printStackTrace();
        }
    }

    /**
     * adding an item to the collection that is from a path
     * @param keys index path, item is stored by
     * @param value actual data being stored
     */
    public void put(String[] keys, Object value) {
        //only one item then use the normal puts
        if (keys.length == 1) {
            put(keys[0], value);
            return;
        }

        //remove the last key of the path
        String lastKey = keys[keys.length - 1];
        String[] path = Utils.copyArrayExceptLast(keys);

        //find the containing object
        Object item = findElementByPath(path);

        try {
            Update update = new Update(item);
            update.performUpdate(lastKey, value);
        } catch (IllegalAccessException | InvocationTargetException e) {
            Utils.debug("PATH INVALID:\nPATH: " + path + "\nDATA: " + getJson(), "error");
            e.printStackTrace();
        }
    }

    /**
     * remove item from collection
     * @param key key of item to remove
     */
    public void remove(String key) {
        storage.remove(key);
    }

    /**
     * remove item from collection found by path
     * @param keys an array of the path to delete the item
     */
    public void remove(String[] keys) {
        //remove the last key of the path
        String lastKey = keys[keys.length - 1];
        String[] path = Utils.copyArrayExceptLast(keys);

        //find the containing object
        Object item = findElementByPath(path);

        //perform the remove operation, casting to what it is to allow remove to be called
        try { //set
            Update update = new Update(item);
            update.performRemove(lastKey);
        } catch (Exception e) {
            Utils.debug("PATH INVALID:\nPATH: " + path + "\nDATA: " + getJson(), "error");
            e.printStackTrace();
        }
    }

    /**
     * get a single item from collection
     * @param key key to find the stored item
     * @return T the found item cast to expected type
     */
    public  T get(String key) {
        return (T) storage.get(key);
    }

    /**
     * get a single item from collection as an int
     * @param key key to find stored item
     * @return int the item as an int
     */
    public int getInt(String key) {
        //get the int value of doubles
        String intValue = getString(key).split("\\.")[0];
        return Integer.parseInt(intValue);
    }

    /**
     * get a single item from collection as a String
     * @param key key to find the stored item
     * @return String the item as a string
     */
    public String getString(String key) {
        return storage.get(key).toString();
    }

    /**
     * get a single item from collection
     * @param key index to find the stored item
     * @return T the found item cast to expected type
     */
    public  T get(int key) {
        return get(String.valueOf(key));
    }

    /**
     * get an object in collection that might be a sub object
     * enter the path in an array, index of array is parent to child order
     * index 0 is parent index 1 is child
     * if it is an array just put the index as a string "0" will return first item in array
     * example:
     * {'results':[{'item':12}]}
     * {"results", "0", "item"} returns 12
     * @param path string array of the path
     * @return Object the found item from the path
     */
    public  T get(String[] path) {
        return (T) findElementByPath(path);
    }

    /**
     * get object from collection as a Data Storage object
     * give the path as an array like previous get(String[])
     * @param path string array of the path
     * @return DataStorage object populated with found object
     */
    public Storage getAsDataStorage(String[] path) {
        Object found = findElementByPath(path);
        return CreatorHelper.createDataStorage(found);
    }

    /**
     * get object from collection as a Data Storage object
     * @param key string key of object, top level
     * @return DataStorage object populated with found object
     */
    public Storage getAsDataStorage(String key) {
        Object found = get(key);
        return CreatorHelper.createDataStorage(found);
    }

    /**
     * get object from collection as a Data Storage object
     * @param key index of object, top level
     * @return DataStorage object populated with found object
     */
    public Storage getAsDataStorage(int key) {
        Object found = get(key);
        return CreatorHelper.createDataStorage(found);
    }

    /**
     * extract array from collection
     * if the collection is not an array it will be empty
     * @return ArrayList from the collection
     */
    public ArrayList getArray() {
        ArrayList items = new ArrayList();
        for(int i = 0; has(String.valueOf(i)); ++i)
            items.add(get(i));

        return items;
    }

    /**
     * get the size of the collection
     * @return int number of items in top level of collection
     */
    public int size() {
        return storage.size();
    }

    /**
     * see if collection has this key
     * @param key the key we are looking for to exist
     * @return boolean if it found the key in the collection
     */
    public boolean has(String key) {
        return storage.containsKey(key);
    }

    /**
     * See if collection has a key based on a path
     * @param path Path to the key to check
     * @return boolean if it found the key in the collection
     */
    public boolean has(String[] path) {
        String key = path[path.length - 1];

        for(String[] p : findPaths(key)) {
            if (Arrays.equals(p, path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * gets a set of all available keys at highest level
     * @return Set a set of the keys
     */
    public Set keys() {
        return storage.keySet();
    }

    /**
     * add a json object to the collection
     * converts the json and adds to the current collection
     * @param json JSONObject you want to add to the collection
     */
    public void addJson(JSONObject json) {
        //gson setup
        Gson converter = new Gson();
        Type hashmapType = new TypeToken>() {}.getType();

        HashMap converted = converter.fromJson(json.toString(), hashmapType);
        addMap(converted);
    }

    /**
     * add a json object to the collection
     * converts the json and adds to the current collection
     * @param json JSONArray you want to add to the collection
     */
    public void addJson(JSONArray json) {
        for(int i = 0; i < json.length(); ++i)
            try {
                Object nextItem = json.get(i);
                if (nextItem.getClass().getTypeName().contains("JSONObject"))
                    nextItem = new Storage((JSONObject)nextItem).getMap();
                put(String.valueOf(i), nextItem);
            } catch (JSONException e) {
                e.printStackTrace();
            }
    }

    /**
     * add a xml to the collection, in the form of a string
     * converts the xml and adds to the current collection
     * @param xml String that is in xml format
     */
    public void addXml(String xml) {
        addXml(Converter.xmlStringToElement(xml));
    }

    /**
     * add a xml to the collection, as an xml node
     * @param xmlFile org.w3c.dom.Node object, parent node of xml
     */
    public void addXml(Element xmlFile) {
        ArrayList path = new ArrayList<>();
        recurseOverElements(path, xmlFile);
    }

    /**
     * add a model to the collection
     * @param model model to get data from, example com.alianza.az.model.Account
     * @param  the type the model is
     */
    public  void addModel(T model) {
        ConvertObjectToJson converter = new ConvertObjectToJson();
        JSONObject jsonObject = converter.convertToJson(model);

        addJson(jsonObject);
    }

    /**
     * add a HashMap of data to the current collection
     * @param adding hashmap of data
     */
    public void addMap(HashMap adding) {
        storage.putAll(adding);
    }

    /**
     * add an array of data to the current collection
     * @param array ArrayList of data to add
     */
    public void addArray(ArrayList array) {
        for(int i = 0; i < array.size(); ++i) {
            put(String.valueOf(i), array.get(i));
        }
    }

    /**
     * take the response from sip and format to save data
     * @param sipResponse the response from the sip request
     */
    public void addSip(Response sipResponse) {
        HashMap sipData = new HashMap<>();

        String[] allSip = sipResponse.toString().split("\r\n");

        //first line is the status, response code
        sipData.put("statusCode", allSip[0]);

        //get the response data, first line is the status
        for(int i = 1; i < allSip.length; ++i) {
            String[] rowData = allSip[i].split(": ");

            //if : is not splitting them then it must be the body
            //use = to split
            if (rowData.length < 2)
                rowData = allSip[i].split("=");

            //sometimes empty space just skip those
            if (rowData.length >= 2)
                sipData.put(rowData[0], rowData[1]);
        }

        addMap(sipData);
    }

    /**
     * get the full collection in json form
     * @return JSONObject entire collection as json, or null if error
     */
    public JSONObject getJson() {
        cleanupDate();
        Converter convert = new Converter(storage);
        return convert.convertToJson();
    }

    /**
     * get the an array in json array form
     * @return JSONArray the collection as an array, will only contain array items
     */
    public JSONArray getJsonArray() {
        Converter converter = new Converter(storage);
        return converter.convertToJsonArray();
    }

    /**
     * get the full collection in xml form as a string
     * @return String entire collection as xml string
     */
    public String getXml() {
        Converter converter = new Converter(storage);
        return converter.convertToXml();
    }

    /**
     * get the full collection as a hashMap
     * @return HashMap(String, Object) the full collection in hash map form
     */
    public HashMap getMap() {
        return new HashMap<>(storage);
    }

    /**
     * find all paths leading to a specific key in the collection
     * find any strings that match that key name and give a full path to get to them
     * @param searchKey string key looking for in the collection
     * @return ArrayList of String[], each entry in array list is a path to the key searched for
     */
    public ArrayList findPaths(String searchKey) {
        Converter convert = new Converter(storage);
        JSONObject json = convert.convertToJson();

        PathParser pathParser = new PathParser(json);
        return pathParser.findPaths(searchKey);
    }

    @Override
    public String toString() {
        return getJson().toString();
    }

    @Override
    public boolean equals(Object otherStorage) {
        return (otherStorage instanceof Storage) &&
                storage.equals(((Storage)otherStorage).getMap());
    }

    private Object findElementByPath(String[] path) {
        RetrieveByPath pathSearch = new RetrieveByPath(this);
        return pathSearch.findElementByPath(path);
    }

    /**
     * helper for adding xml
     * @param path where the xml will be added
     * @param xmlData the data as an xml Element
     */
    private void addXmlWithPath(ArrayList path, Element xmlData) {
        boolean isXml = xmlData.elements().size() > 0;

        //set the key
        String[] thePath = new String[path.size()];
        path.toArray(thePath);

        //put either the value or an imbeded object
        if (isXml && !has(thePath))
            put(thePath, new Storage());
        else
            put(thePath, xmlData.getStringValue());

        //if it is xml need to see all children
        if (isXml) {
            recurseOverElements(path, xmlData);
        }
    }

    /**
     * helper for adding xml, goes over each element and add it to the storage, recursively
     * @param path current path to save items
     * @param xmlData data being saved as an xml Element
     */
    private void recurseOverElements(ArrayList path, Element xmlData) {
        String[] thePath = new String[path.size()];
        path.toArray(thePath);

        List elements = (List)xmlData.elements();
        //different if an array
        boolean isArray = false;
        if (elements.size() > 1)
            isArray = elements.get(0).getName().equals(elements.get(1).getName());

        //if its an array then it should be saved as an array
        if (isArray && getAsDataStorage(thePath).getArray().size() < 1)
            put(thePath, new JSONArray());
        int i = 0;
        for (Element element :  elements) {
            String key = isArray ? String.valueOf(i++) : element.getName();
            ArrayList tempPath = (ArrayList) path.clone();
            tempPath.add(key);
            addXmlWithPath(tempPath, element);
        }
    }

    /**
     * date objects come out all messed up
     * change them to a string of the date
     */
    private void cleanupDate() {
        ArrayList paths = findPaths("date");
        String dateString;

        for(String[] path : paths) {
            Object dateItem = get(path);
            if (!dateItem.getClass().equals(String.class))
                dateString = dateItem.toString();
            else
                dateString = (String)dateItem;
            put(path, dateString);

        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy