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

com.servicerocket.confluence.randombits.storage.BasedStorage Maven / Gradle / Ivy

There is a newer version: 2.5.12
Show newest version
/*
 * Copyright (c) 2006, David Peterson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of "randombits.org" nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package com.servicerocket.confluence.randombits.storage;

import java.util.*;

/**
 * Subclasses of this implementation are intended to have a base storage
 * location underlying it.
 *
 * @author David Peterson
 */
public abstract class BasedStorage extends AbstractStorage {

    /**
     * Used to define how boxes are opened and closed.
     */
    public enum BoxType {
        /**
         * Every {@link BasedStorage#openBox(String)} call creates a new
         * {@link Map} to store its values in.
         */
        Real,
        /**
         * Every {@link BasedStorage#openBox(String)} call modifies the path
         * that values are set or retrieved from from the base {@link Map}.
         */
        Virtual
    }

    // The current box. If null, we're at the root.
    private Map box;

    private Stack> boxes;

    private String topBoxName;

    private BoxType boxType;

    /**
     * Constructs a new storage object. {@link BoxType#Virtual} builds the
     * property path as a string with each box separated by a {@link #SEPARATOR},
     * while {@link BoxType#Real} creates a new Map for each box.
     *
     * @param boxType The type.
     */
    public BasedStorage(BoxType boxType) {
        this.boxType = boxType;
    }

    /**
     * Returns the name set for the base object.
     *
     * @return The name set, or null if the set is not available.
     */
    protected abstract Set baseNameSet();

    @Override
    public void openBox(String name) {
        super.openBox(name);

        if (boxType == BoxType.Real) {
            Map newBox = getObject(name, null, Map.class);

            if (newBox == null) {
                newBox = createBox();
            }

            if (box != null) {
                if (boxes == null) {
                    boxes = new Stack<>();
                }
                box.put(name, newBox);
                boxes.push(box);
            }

            box = newBox;
        }

        if (topBoxName == null) {
            topBoxName = name;
        }
    }

    /**
     * Creates a new box when in {@link BoxType#Real} mode. Subclasses should
     * override this if they wish to change the type of Map used for the box.
     *
     * @return The new Map for the box.
     */
    protected Map createBox() {
        return new HashMap<>();
    }

    @Override
    public void closeBox() {
        super.closeBox();

        if (boxType == BoxType.Real) {
            if (boxes != null && boxes.size() != 0) {
                box = boxes.pop();
            } else {
                if (!isReadOnly()) {
                    setBaseObject(topBoxName, box);
                }
                box = null;
                topBoxName = null;
            }
        }
    }

    /**
     * Retrieves a Boolean from the base object.
     *
     * @param string The name of the boolean value.
     * @return the Boolean value for the specified name.
     */
    protected abstract Boolean getBaseBoolean(String string);

    /**
     * Retrieves the named DateTime value from the base object.
     *
     * @param name The name of the value.
     * @return The value.
     * @throws StorageException if there is a problem retrieving the date.
     */
    protected abstract Date getBaseDate(String name);

    /**
     * Retrieves the double value from the base object.
     *
     * @param name The name of the value.
     * @return The value.
     */
    protected abstract Double getBaseDouble(String name);

    /**
     * Returns an integer from the base object.
     *
     * @param name The named value.
     * @return The integer object, or null.
     */
    protected abstract Integer getBaseInteger(String name);

    /**
     * Returns the named value as a Long.
     *
     * @param name The name of the value.
     * @return The value as a long.
     */
    protected abstract Long getBaseLong(String name);

    /**
     * Returns the named value as a Number. Useful if the specific type of
     * number in the field is unknown.
     *
     * @param name The name of the value.
     * @return The value as a Number.
     */
    protected abstract Number getBaseNumber(String name);

    /**
     * Returns an object stored with the specified name.
     *
     * @param name The name of the value to return.
     * @return the stored object.
     */
    protected abstract Object getBaseObject(String name);

    /**
     * Retrieves the object list from the underlying base object.
     *
     * @param name The name of the stored list.
     * @return The list.
     */
    protected abstract List getBaseObjectList(String name);

    /**
     * Returns the named string value from the base object.
     *
     * @param name The name of the string to return.
     * @return the string value, or null.
     */
    protected abstract String getBaseString(String name);

    /**
     * Returns the string array from the underlying base object.
     *
     * @param name The name of the value.
     * @return The string array.
     * @throws StorageException if there is a problem retrieving the value.
     */
    protected abstract String[] getBaseStringArray(String name) throws StorageException;

    protected  T getBoxValue(String name, Class clazz) {
        Object value = box.get(name);
        return toType(value, null, clazz);
    }

    @Override
    public Boolean getBoolean(String name, Boolean def) {
        try {
            Boolean value;
            if (boxType == BoxType.Real) {
                if (box == null) {
                    value = getBaseBoolean(name);
                } else {
                    value = getBoxValue(name, Boolean.class);
                }
            } else {
                value = getBaseBoolean(makePath(name));
            }

            if (value == null) {
                return def;
            }
            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }
    }

    @Override
    public Date getDate(String name, Date def) {
        try {
            Date value;
            if (boxType == BoxType.Real) {
                if (box == null) {
                    value = getBaseDate(name);
                } else {
                    value = getBoxValue(name, Date.class);
                }
            } else {
                value = getBaseDate(makePath(name));
            }

            if (value == null) {
                return def;
            }
            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }
    }

    @Override
    public Double getDouble(String name, Double def) {
        try {
            Double value;

            if (boxType == BoxType.Real) {
                if (box != null) {
                    Number number = getBoxValue(name, Number.class);
                    value = number != null ? number.doubleValue() : null;
                } else {
                    value = getBaseDouble(name);
                }
            } else {
                value = getBaseDouble(makePath(name));
            }

            if (value == null) {
                return def;
            }

            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }

    }

    @Override
    public Integer getInteger(String name, Integer def) {
        try {
            Integer value;

            if (boxType == BoxType.Real) {
                if (box != null) {
                    Number number = getBoxValue(name, Number.class);
                    value = number != null ? number.intValue() : null;
                } else {
                    value = getBaseInteger(name);
                }
            } else {
                value = getBaseInteger(makePath(name));
            }

            if (value == null) {
                return def;
            }

            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }
    }

    @Override
    public Long getLong(String name, Long def) {
        try {
            Long value;

            if (boxType == BoxType.Real) {
                if (box != null) {
                    Number number = getBoxValue(name, Number.class);
                    value = number != null ? number.longValue() : null;
                } else {
                    value = getBaseLong(name);
                }
            } else {
                value = getBaseLong(makePath(name));
            }

            if (value == null) {
                return def;
            }

            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }
    }

    /**
     * Returns the named value as a {@link Number}. What the actual type of
     * Number returned is depends on both the stored value, type of
     * {@link Storage} and the default value. Assume
     * nothing.
     *
     * @param name The name of the value to return.
     * @param def  The value to return if no value is stored.
     * @return The stored value, or the default if nothing is stord with that.
     */
    public Number getNumber(String name, Number def) {
        try {
            Number value;

            if (boxType == BoxType.Real) {
                if (box != null) {
                    value = getBoxValue(name, Number.class);
                } else {
                    value = getBaseNumber(name);
                }
            } else {
                value = getBaseNumber(makePath(name));
            }

            if (value == null) {
                return def;
            }

            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }
    }

    @Override
    public  T getObject(String name, T def, Class type) {
        Object value;
        if (boxType == BoxType.Real) {
            if (box == null) {
                value = getBaseObject(name);
            } else {
                value = box.get(name);
            }
        } else {
            value = getBaseObject(makePath(name));
        }

        return toType(value, def, type);
    }

    protected  T toType(Object value, T def, Class type) {
        if (type.isInstance(value)) {
            return (T) value;
        }
        return def;
    }

    @Override
    public List getObjectList(String name, List def) {
        List value;
        if (boxType == BoxType.Real) {
            if (box == null) {
                value = getBaseObjectList(name);
            } else {
                value = getBoxValue(name, List.class);
            }
        } else {
            value = getBaseObjectList(makePath(name));
        }

        if (value == null) {
            return def;
        }
        return value;
    }

    @Override
    public String getString(String name, String def) {
        try {
            String value;

            if (boxType == BoxType.Real) {
                if (box == null) {
                    value = getBaseString(name);
                } else {
                    value = getBoxValue(name, String.class);
                }
            } else {
                value = getBaseString(makePath(name));
            }

            if (value == null) {
                return def;
            }

            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }
    }

    @Override
    public String[] getStringArray(String name, String[] def) {
        try {
            String[] value;

            if (boxType == BoxType.Real) {
                if (box == null) {
                    value = getBaseStringArray(name);
                } else {
                    value = getBoxValue(name, String[].class);
                }
            } else {
                value = getBaseStringArray(makePath(name));
            }

            if (value == null) {
                return def;
            }

            return value;
        } catch (ClassCastException e) {
            throw new StorageException(makePath(name), e);
        }
    }

    @Override
    public Set nameSet() {
        if (box == null) {
            return baseNameSet();
        } else {
            return box.keySet();
        }
    }

    /**
     * Sets the named boolean value in the base object.
     *
     * @param name  The name of the value.
     * @param value The value being set.
     */
    protected abstract void setBaseBoolean(String name, Boolean value);

    /**
     * Stores the named date value in the base object.
     *
     * @param name  The name of the value.
     * @param value The Date value being set.
     */
    protected abstract void setBaseDate(String name, Date value);

    /**
     * Sets the named double value in the base object.
     *
     * @param name  The name of the value.
     * @param value The value being set.
     */
    protected abstract void setBaseDouble(String name, Double value);

    /**
     * Sets the integer in the base object.
     *
     * @param name  The name of the value.
     * @param value The integer value to set.
     */
    protected abstract void setBaseInteger(String name, Integer value);

    /**
     * Sets the long in the base object.
     *
     * @param name  The name of the value.
     * @param value The long value to set.
     */
    protected abstract void setBaseLong(String name, Long value);

    /**
     * Sets the object in the base object.
     *
     * @param name  The name of the value.
     * @param value The object value to set.
     */
    protected abstract void setBaseObject(String name, Object value);

    /**
     * Stores the list into the base object.
     *
     * @param name  The name to store with.
     * @param value The value to store.
     */
    protected abstract void setBaseObjectList(String name, List value);

    /**
     * Set the string value in the base object.
     *
     * @param name  The name of the value.
     * @param value The value to set.
     */
    protected abstract void setBaseString(String name, String value);

    /**
     * Sets the string array in the underlying base object.
     *
     * @param name  The name to store the value as.
     * @param value The value to store.
     */
    protected abstract void setBaseStringArray(String name, String[] value);

    @Override
    public void setBoolean(String name, Boolean value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseBoolean(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseBoolean(makePath(name), value);
        }
    }

    @Override
    public void setDate(String name, Date value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseDate(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseDate(makePath(name), value);
        }
    }

    @Override
    public void setDouble(String name, Double value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseDouble(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseDouble(makePath(name), value);
        }
    }

    @Override
    public void setInteger(String name, Integer value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseInteger(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseInteger(makePath(name), value);
        }
    }

    @Override
    public void setLong(String name, Long value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseLong(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseLong(makePath(name), value);
        }
    }

    /**
     * Stores the object value with with the specified name.
     *
     * @param name  The name to store against.
     * @param value The value to store.
     */
    @Override
    public void setObject(String name, Object value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseObject(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseObject(makePath(name), value);
        }
    }

    @Override
    public void setObjectList(String name, List value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseObjectList(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseObjectList(makePath(name), value);
        }
    }

    @Override
    public void setString(String name, String value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseString(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseString(makePath(name), value);
        }
    }

    @Override
    public void setStringArray(String name, String[] value) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            if (box == null) {
                setBaseStringArray(name, value);
            } else {
                box.put(name, value);
            }
        } else {
            setBaseStringArray(makePath(name), value);
        }
    }

    public boolean removeBox(String name) {
        checkReadOnly();

        if (boxType == BoxType.Real) {
            Map box = (Map) getBaseObject(name);
            if (box != null) {
                setBaseObject(name, null);
            }
            return true;
        }

        return false;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy