1. opensymphony
  2. propertyset

Commits

skanjo  committed 35debf6

Split main source tree into api and core modules. Moved the jdbc provider under provider source tree as jdbc. Renamed hibernate and ejb branches to include major version.

git-svn-id: http://svn.opensymphony.com/svn/propertyset/branches/ivy_build@196bf3cbcdd-1c1a-0410-9a68-d6f521e3fa7b

  • Participants
  • Parent commits 0f41b88
  • Branches master

Comments (0)

Files changed (112)

File api/src/main/java/com/opensymphony/module/propertyset/AbstractPropertySet.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+import com.opensymphony.util.Data;
+
+import org.w3c.dom.Document;
+
+import java.util.*;
+
+
+/**
+ * Base implementation of PropertySet.
+ *
+ * <p>Performs necessary casting for get???/set??? methods which wrap around the
+ * following 2 methods which are declared <code>protected abstract</code> and need
+ * to be implemented by subclasses:</p>
+ *
+ * <ul>
+ * <li> {@link #get(int,java.lang.String)} </li>
+ * <li> {@link #setImpl(int,java.lang.String,java.lang.Object)} </li>
+ * </ul>
+ *
+ * <p>The following methods are declared <code>public abstract</code> and are the
+ * remainder of the methods that need to be implemented at the very least:</p>
+ *
+ * <ul>
+ * <li> {@link #exists(java.lang.String)} </li>
+ * <li> {@link #remove(java.lang.String)} </li>
+ * <li> {@link #getType(java.lang.String)} </li>
+ * <li> {@link #getKeys(java.lang.String,int)} </li>
+ * </ul>
+ *
+ * <p>The <code>supports???</code> methods are implemented and all return true by default.
+ * Override if necessary.</p>
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @author <a href="mailto:hani@fate.demon.co.uk">Hani Suleiman</a>
+ * @version $Revision$
+ */
+public abstract class AbstractPropertySet implements PropertySet {
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    protected PropertySetSchema schema;
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    public void setAsActualType(String key, Object value) throws PropertyException {
+        int type;
+
+        if (value instanceof Boolean) {
+            type = BOOLEAN;
+        } else if (value instanceof Integer) {
+            type = INT;
+        } else if (value instanceof Long) {
+            type = LONG;
+        } else if (value instanceof Double) {
+            type = DOUBLE;
+        } else if (value instanceof String) {
+            if (value.toString().length() > 255) {
+                type = TEXT;
+            } else {
+                type = STRING;
+            }
+        } else if (value instanceof Date) {
+            type = DATE;
+        } else if (value instanceof Document) {
+            type = XML;
+        } else if (value instanceof byte[]) {
+            type = DATA;
+        } else if (value instanceof Properties) {
+            type = PROPERTIES;
+        } else {
+            type = OBJECT;
+        }
+
+        set(type, key, value);
+    }
+
+    public Object getAsActualType(String key) throws PropertyException {
+        int type = getType(key);
+        Object value = null;
+
+        switch (type) {
+        case BOOLEAN:
+            value = new Boolean(getBoolean(key));
+
+            break;
+
+        case INT:
+            value = new Integer(getInt(key));
+
+            break;
+
+        case LONG:
+            value = new Long(getLong(key));
+
+            break;
+
+        case DOUBLE:
+            value = new Double(getDouble(key));
+
+            break;
+
+        case STRING:
+            value = getString(key);
+
+            break;
+
+        case TEXT:
+            value = getText(key);
+
+            break;
+
+        case DATE:
+            value = getDate(key);
+
+            break;
+
+        case XML:
+            value = getXML(key);
+
+            break;
+
+        case DATA:
+            value = getData(key);
+
+            break;
+
+        case PROPERTIES:
+            value = getProperties(key);
+
+            break;
+
+        case OBJECT:
+            value = getObject(key);
+
+            break;
+        }
+
+        return value;
+    }
+
+    public void setBoolean(String key, boolean value) {
+        set(BOOLEAN, key, value ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    public boolean getBoolean(String key) {
+        try {
+            return ((Boolean) get(BOOLEAN, key)).booleanValue();
+        } catch (NullPointerException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Constructs {@link com.opensymphony.util.Data} wrapper around bytes.
+     */
+    public void setData(String key, byte[] value) {
+        set(DATA, key, new Data(value));
+    }
+
+    /**
+     * Casts to {@link com.opensymphony.util.Data} and returns bytes.
+     */
+    public byte[] getData(String key) {
+        try {
+            Object data = get(DATA, key);
+
+            if (data instanceof Data) {
+                return ((Data) data).getBytes();
+            } else if (data instanceof byte[]) {
+                return (byte[]) data;
+            }
+        } catch (NullPointerException e) {
+            return null;
+        }
+
+        return null;
+    }
+
+    public void setDate(String key, Date value) {
+        set(DATE, key, value);
+    }
+
+    public Date getDate(String key) {
+        try {
+            return (Date) get(DATE, key);
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    public void setDouble(String key, double value) {
+        set(DOUBLE, key, new Double(value));
+    }
+
+    public double getDouble(String key) {
+        try {
+            return ((Double) get(DOUBLE, key)).doubleValue();
+        } catch (NullPointerException e) {
+            return 0.0;
+        }
+    }
+
+    public void setInt(String key, int value) {
+        set(INT, key, new Integer(value));
+    }
+
+    public int getInt(String key) {
+        try {
+            return ((Integer) get(INT, key)).intValue();
+        } catch (NullPointerException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * Calls <code>getKeys(null,0)</code>
+     */
+    public Collection getKeys() throws PropertyException {
+        return getKeys(null, 0);
+    }
+
+    /**
+     * Calls <code>getKeys(null,type)</code>
+     */
+    public Collection getKeys(int type) throws PropertyException {
+        return getKeys(null, type);
+    }
+
+    /**
+     * Calls <code>getKeys(prefix,0)</code>
+     */
+    public Collection getKeys(String prefix) throws PropertyException {
+        return getKeys(prefix, 0);
+    }
+
+    public void setLong(String key, long value) {
+        set(LONG, key, new Long(value));
+    }
+
+    public long getLong(String key) {
+        try {
+            return ((Long) get(LONG, key)).longValue();
+        } catch (NullPointerException e) {
+            return 0L;
+        }
+    }
+
+    public void setObject(String key, Object value) {
+        set(OBJECT, key, value);
+    }
+
+    public Object getObject(String key) {
+        try {
+            return get(OBJECT, key);
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    public void setProperties(String key, Properties value) {
+        set(PROPERTIES, key, value);
+    }
+
+    public Properties getProperties(String key) {
+        try {
+            return (Properties) get(PROPERTIES, key);
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    public void setSchema(PropertySetSchema schema) {
+        this.schema = schema;
+    }
+
+    public PropertySetSchema getSchema() {
+        return schema;
+    }
+
+    /**
+     * Returns true.
+     */
+    public boolean isSettable(String property) {
+        return true;
+    }
+
+    /**
+     * Throws IllegalPropertyException if value length greater than 255.
+     */
+    public void setString(String key, String value) {
+        if ((value != null) && (value.length() > 255)) {
+            throw new IllegalPropertyException("String exceeds 255 characters.");
+        }
+
+        set(STRING, key, value);
+    }
+
+    public String getString(String key) {
+        try {
+            return (String) get(STRING, key);
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    public void setText(String key, String value) {
+        set(TEXT, key, value);
+    }
+
+    public String getText(String key) {
+        try {
+            return (String) get(TEXT, key);
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    public void setXML(String key, Document value) {
+        set(XML, key, value);
+    }
+
+    public Document getXML(String key) {
+        try {
+            return (Document) get(XML, key);
+        } catch (NullPointerException e) {
+            return null;
+        }
+    }
+
+    public void init(Map config, Map args) {
+        // nothing
+    }
+
+    /**
+     * Returns true.
+     */
+    public boolean supportsType(int type) {
+        return true;
+    }
+
+    /**
+     * Returns true.
+     */
+    public boolean supportsTypes() {
+        return true;
+    }
+
+    /**
+     * Simple human readable representation of contents of PropertySet.
+     */
+    public String toString() {
+        StringBuffer result = new StringBuffer();
+        result.append(getClass().getName());
+        result.append(" {\n");
+
+        try {
+            Iterator keys = getKeys().iterator();
+
+            while (keys.hasNext()) {
+                String key = (String) keys.next();
+                int type = getType(key);
+
+                if (type > 0) {
+                    result.append('\t');
+                    result.append(key);
+                    result.append(" = ");
+                    result.append(get(type, key));
+                    result.append('\n');
+                }
+            }
+        } catch (PropertyException e) {
+            // toString should never throw an exception.
+        }
+
+        result.append("}\n");
+
+        return result.toString();
+    }
+
+    protected abstract void setImpl(int type, String key, Object value) throws PropertyException;
+
+    protected abstract Object get(int type, String key) throws PropertyException;
+
+    protected String type(int type) {
+        switch (type) {
+        case PropertySet.BOOLEAN:
+            return "boolean";
+
+        case PropertySet.INT:
+            return "int";
+
+        case PropertySet.LONG:
+            return "long";
+
+        case PropertySet.DOUBLE:
+            return "double";
+
+        case PropertySet.STRING:
+            return "string";
+
+        case PropertySet.TEXT:
+            return "text";
+
+        case PropertySet.DATE:
+            return "date";
+
+        case PropertySet.OBJECT:
+            return "object";
+
+        case PropertySet.XML:
+            return "xml";
+
+        case PropertySet.DATA:
+            return "data";
+
+        case PropertySet.PROPERTIES:
+            return "properties";
+
+        default:
+            return null;
+        }
+    }
+
+    protected int type(String type) {
+        if (type == null) {
+            return 0;
+        }
+
+        type = type.toLowerCase();
+
+        if (type.equals("boolean")) {
+            return PropertySet.BOOLEAN;
+        }
+
+        if (type.equals("int")) {
+            return PropertySet.INT;
+        }
+
+        if (type.equals("long")) {
+            return PropertySet.LONG;
+        }
+
+        if (type.equals("double")) {
+            return PropertySet.DOUBLE;
+        }
+
+        if (type.equals("string")) {
+            return PropertySet.STRING;
+        }
+
+        if (type.equals("text")) {
+            return PropertySet.TEXT;
+        }
+
+        if (type.equals("date")) {
+            return PropertySet.DATE;
+        }
+
+        if (type.equals("object")) {
+            return PropertySet.OBJECT;
+        }
+
+        if (type.equals("xml")) {
+            return PropertySet.XML;
+        }
+
+        if (type.equals("data")) {
+            return PropertySet.DATA;
+        }
+
+        if (type.equals("properties")) {
+            return PropertySet.PROPERTIES;
+        }
+
+        return 0;
+    }
+
+    private void set(int type, String key, Object value) throws PropertyException {
+        //If we have a schema, validate data against it.
+        if (schema != null) {
+            PropertySchema ps = schema.getPropertySchema(key);
+
+            //Restricted schemas have to explicitly list all permissible values
+            if ((ps == null) && schema.isRestricted()) {
+                throw new IllegalPropertyException("Property " + key + " not explicitly specified in restricted schema.");
+            }
+
+            //Check the property type matches
+            if (supportsTypes() && (ps.getType() != type)) {
+                throw new InvalidPropertyTypeException("Property " + key + " has invalid type " + type + " expected type=" + ps.getType());
+            }
+
+            ps.validate(value);
+        }
+
+        //we're ok this far, so call the actual setter.
+        setImpl(type, key, value);
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/DuplicatePropertyKeyException.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+
+/**
+ * Thrown if a property is set who's key matches a key of an
+ * existing property with different type.
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @version $Revision$
+ */
+public class DuplicatePropertyKeyException extends PropertyException {
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public DuplicatePropertyKeyException() {
+        super();
+    }
+
+    public DuplicatePropertyKeyException(String msg) {
+        super(msg);
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/IllegalPropertyException.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+
+/**
+ * Thrown if a property is set which is not allowed.
+ *
+ * <p><i>e.g.</i> non-serializable Object is passed to SerializablePropertySet,
+ * or field is persisted that cannot be stored in database.</p>
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @version $Revision$
+ */
+public class IllegalPropertyException extends PropertyException {
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public IllegalPropertyException() {
+        super();
+    }
+
+    public IllegalPropertyException(String msg) {
+        super(msg);
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/InvalidPropertyTypeException.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+
+/**
+ * Thrown if a property is attempted to be retrieved that
+ * does exist but is of different type.
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @version $Revision$
+ */
+public class InvalidPropertyTypeException extends PropertyException {
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public InvalidPropertyTypeException() {
+        super();
+    }
+
+    public InvalidPropertyTypeException(String msg) {
+        super(msg);
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/PropertyException.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+
+/**
+ * Parent class of all exceptions thrown by PropertySet.
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @version $Revision$
+ */
+public class PropertyException extends RuntimeException {
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public PropertyException() {
+        super();
+    }
+
+    public PropertyException(String msg) {
+        super(msg);
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/PropertyImplementationException.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+
+/**
+ * Thrown if a specific implementation exception is thrown
+ * (such as EJBException, RemoteException, NamingException, IOException, etc).
+ *
+ * <p>A specific Exception can be wrapped in this Exception, by being
+ * passed to the constructor. It can be retrieved via
+ * {@link #getRootCause()} .</p>
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @version $Revision$
+ */
+public class PropertyImplementationException extends PropertyException {
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    protected Throwable original;
+
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public PropertyImplementationException() {
+        super();
+    }
+
+    public PropertyImplementationException(String msg) {
+        super(msg);
+    }
+
+    public PropertyImplementationException(String msg, Throwable original) {
+        super(msg);
+        this.original = original;
+    }
+
+    public PropertyImplementationException(Throwable original) {
+        this(original.getLocalizedMessage(), original);
+    }
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    /**
+     * Retrieve original Exception.
+     */
+    public Throwable getRootCause() {
+        return original;
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/PropertySchema.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+import com.opensymphony.module.propertyset.verifiers.PropertyVerifier;
+import com.opensymphony.module.propertyset.verifiers.VerifyException;
+
+import java.io.Serializable;
+
+import java.util.*;
+
+
+/**
+ * Describes the meta data for a given property.
+ * The meta data for a property includes its type as well as
+ * any verifiers that constrain it.
+ *
+ * todo: add multiplicity?
+ *
+ * @author <a href="mailto:hani@fate.demon.co.uk">Hani Suleiman</a>
+ * @version $Revision$
+ */
+public class PropertySchema implements Serializable {
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    private Collection verifiers;
+    private String name;
+    private int type;
+
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public PropertySchema() {
+        this(null);
+    }
+
+    public PropertySchema(String name) {
+        super();
+        this.name = name;
+        verifiers = new HashSet();
+    }
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    public void setPropertyName(String s) {
+        name = s;
+    }
+
+    public String getPropertyName() {
+        return name;
+    }
+
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Returns unmodifiable List of verifiers.
+     */
+    public Collection getVerifiers() {
+        return Collections.unmodifiableCollection(verifiers);
+    }
+
+    public boolean addVerifier(PropertyVerifier pv) {
+        return verifiers.add(pv);
+    }
+
+    public boolean removeVerifier(PropertyVerifier pv) {
+        return verifiers.remove(pv);
+    }
+
+    /**
+     * Validate a given value against all verifiers.
+     * Default behaviour is to AND all verifiers.
+     */
+    public void validate(Object value) throws PropertyException {
+        Iterator i = verifiers.iterator();
+
+        while (i.hasNext()) {
+            PropertyVerifier pv = (PropertyVerifier) i.next();
+
+            //Hmm, do we need a try/catch?
+            try {
+                pv.verify(value);
+            } catch (VerifyException ex) {
+                throw new IllegalPropertyException(ex.getMessage());
+            }
+        }
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/PropertySet.aegis.xml

View file
+<mappings>
+  <mapping>
+    <method name="getKeys">
+      <return-type componentType="java.lang.String" />
+    </method>
+    <property name="schema" ignore="true" />
+  </mapping>
+</mappings>

File api/src/main/java/com/opensymphony/module/propertyset/PropertySet.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+import org.w3c.dom.Document;
+
+import java.util.*;
+
+
+/**
+ * A <code>PropertySet</code> is designed to be associated with other entities
+ * in the system for storing key/value property pairs.
+ *
+ * <p>A key can only contain one value and a key is unique across all types. If
+ * a property is set using the same key and an already existing property of the
+ * SAME type, the new value will overwrite the old. However, if a property of
+ * DIFFERENT type attempts to overwrite the existing value, a
+ * {@link com.opensymphony.module.propertyset.DuplicatePropertyKeyException}
+ * should be thrown.</p>
+ *
+ * <p>If a property is set of a type that is not allowed, a
+ * {@link com.opensymphony.module.propertyset.IllegalPropertyException}
+ * should be thrown.</p>
+ *
+ * <p>If a property is retrieved that exists but contains a value of different
+ * type, a
+ * {@link com.opensymphony.module.propertyset.InvalidPropertyTypeException}
+ * should be thrown.</p>
+ *
+ * <p>If a property is retrieved that does not exist, null (or the primitive
+ * equivalent) is returned.</p>
+ *
+ * <p>If an Exception is encountered in the actual implementation of the
+ * PropertySet that needs to be rethrown, it should be wrapped in a
+ * {@link com.opensymphony.module.propertyset.PropertyImplementationException}
+ * .</p>
+ *
+ * <p>Some PropertySet implementations may not store along side the data the original
+ * type it was set as. This means that it could be retrieved using a get method of
+ * a different type without throwing an InvalidPropertyTypeException (so long as the
+ * original type can be converted to the requested type.</p>
+ *
+ * <p><b>Typed PropertySet Example</b></p>
+ *
+ * <p><code>
+ * propertySet.setString("something","99");<br>
+ * x = propertySet.getString("something"); // throws InvalidPropertyTypeException
+ * </code></p>
+ *
+ * <p><b>Untyped PropertySet Example</b></p>
+ *
+ * <p><code>
+ * propertySet.setString("something","99");<br>
+ * x = propertySet.getString("something"); // returns 99.
+ * </code></p>
+ *
+ * <p>Typically (unless otherwise stated), an implementation is typed. This can be
+ * checked by calling the {@link #supportsTypes()} method of the implementation.</p>
+ *
+ * <p>Not all PropertySet implementations need to support setter methods (i.e.
+ * they are read only) and not all have to support storage/retrieval of specific
+ * types. The capabilities of the specific implementation can be determined by
+ * calling {@link #supportsType(int)} and {@link #isSettable(String)} .</p>
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @version $Revision$
+ */
+public interface PropertySet {
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    /** Value-type boolean */
+    int BOOLEAN = 1;
+
+    /** Value-type byte[] */
+    int DATA = 10;
+
+    /** Value-type {@link java.util.Date} */
+    int DATE = 7;
+
+    /** Value-type double */
+    int DOUBLE = 4;
+
+    /** Value-type int */
+    int INT = 2;
+
+    /** Value-type long */
+    int LONG = 3;
+
+    /** Value-type serializable {@link java.lang.Object} */
+    int OBJECT = 8;
+
+    /** Value-type {@link java.util.Properties} */
+    int PROPERTIES = 11;
+
+    /** Value-type {@link java.lang.String} (max length 255) */
+    int STRING = 5;
+
+    /** Value-type text (unlimited length {@link java.lang.String})  */
+    int TEXT = 6;
+
+    /** Value-type XML {@link org.w3c.dom.Document} */
+    int XML = 9;
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    public void setSchema(PropertySetSchema schema) throws PropertyException;
+
+    public PropertySetSchema getSchema() throws PropertyException;
+
+    void setAsActualType(String key, Object value) throws PropertyException;
+
+    Object getAsActualType(String key) throws PropertyException;
+
+    void setBoolean(String key, boolean value) throws PropertyException;
+
+    boolean getBoolean(String key) throws PropertyException;
+
+    void setData(String key, byte[] value) throws PropertyException;
+
+    byte[] getData(String key) throws PropertyException;
+
+    void setDate(String key, Date value) throws PropertyException;
+
+    Date getDate(String key) throws PropertyException;
+
+    void setDouble(String key, double value) throws PropertyException;
+
+    double getDouble(String key) throws PropertyException;
+
+    void setInt(String key, int value) throws PropertyException;
+
+    int getInt(String key) throws PropertyException;
+
+    /**
+    * List all keys.
+    *
+    * @return Unmodifiable {@link java.util.Collection} of
+    *         {@link java.lang.String}s.
+    */
+    Collection getKeys() throws PropertyException;
+
+    /**
+    * List all keys of certain type.
+    *
+    * @param type Type to list. See static class variables. If null, then
+    *        all types shall be returned.
+    * @return Unmodifiable {@link java.util.Collection} of
+    *         {@link java.lang.String}s.
+    */
+    Collection getKeys(int type) throws PropertyException;
+
+    /**
+    * List all keys starting with supplied prefix.
+    *
+    * @param prefix String that keys must start with. If null, than all
+    *        keys shall be returned.
+    * @return Unmodifiable {@link java.util.Collection} of
+    *         {@link java.lang.String}s.
+    */
+    Collection getKeys(String prefix) throws PropertyException;
+
+    /**
+    * List all keys starting with supplied prefix of certain type. See
+    * statics.
+    *
+    * @param prefix String that keys must start with. If null, than all
+    *        keys shall be returned.
+    * @param type Type to list. See static class variables. If null, then
+    *        all types shall be returned.
+    * @return Unmodifiable {@link java.util.Collection} of
+    *         {@link java.lang.String}s.
+    */
+    Collection getKeys(String prefix, int type) throws PropertyException;
+
+    void setLong(String key, long value) throws PropertyException;
+
+    long getLong(String key) throws PropertyException;
+
+    void setObject(String key, Object value) throws PropertyException;
+
+    Object getObject(String key) throws PropertyException;
+
+    void setProperties(String key, Properties value) throws PropertyException;
+
+    Properties getProperties(String key) throws PropertyException;
+
+    /**
+    * Whether this PropertySet implementation allows values to be set
+    * (as opposed to read-only).
+    */
+    boolean isSettable(String property);
+
+    void setString(String key, String value) throws PropertyException;
+
+    /**
+    * {@link java.lang.String} of maximum 255 chars.
+    */
+    String getString(String key) throws PropertyException;
+
+    void setText(String key, String value) throws PropertyException;
+
+    /**
+    * {@link java.lang.String} of unlimited length.
+    */
+    String getText(String key) throws PropertyException;
+
+    /**
+    * Returns type of value.
+    *
+    * @return Type of value. See static class variables.
+    */
+    int getType(String key) throws PropertyException;
+
+    void setXML(String key, Document value) throws PropertyException;
+
+    Document getXML(String key) throws PropertyException;
+
+    /**
+    * Determine if property exists.
+    */
+    boolean exists(String key) throws PropertyException;
+
+    void init(Map config, Map args);
+
+    /**
+    * Removes property.
+    */
+    void remove(String key) throws PropertyException;
+
+    /**
+     * Remove the propertyset and all it associated keys.
+     * @throws PropertyException if there is an error removing the propertyset.
+     */
+    void remove() throws PropertyException;
+
+    /**
+    * Whether this PropertySet implementation allows the type specified
+    * to be stored or retrieved.
+    */
+    boolean supportsType(int type);
+
+    /**
+    * Whether this PropertySet implementation supports types when storing values.
+     * (i.e. the type of data is stored as well as the actual value).
+    */
+    boolean supportsTypes();
+}

File api/src/main/java/com/opensymphony/module/propertyset/PropertySetCloner.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+import java.util.Iterator;
+
+
+/**
+ * The PropertySetCloner is used to copy all the properties from one PropertySet into another.
+ *
+ * <h3>Example</h3>
+ *
+ * <blockquote><code>
+ *   EJBPropertySet source = new EJBPropertySet("ejb/PropertyStore","MyEJB",7);<br>
+ *   XMLPropertySet dest   = new XMLPropertySet();<br>
+ *   <br>
+ *   PropertySetCloner cloner = new PropertySetCloner();<br>
+ *   cloner.setSource( source );<br>
+ *   cloner.setDestination( dest );<br>
+ *   <br>
+ *   cloner.cloneProperties();<br>
+ *   dest.save( new FileWriter("propertyset-MyEJB-7.xml") );<br>
+ * </code></blockquote>
+ *
+ * <p>The above example demonstrates how a PropertySetCloner can be used to export properties
+ * stores in an EJBPropertySet to an XML file.</p>
+ *
+ * <p>If the destination PropertySet contains any properties, they will be cleared before
+ * the source properties are copied across.</p>
+ *
+ * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
+ * @version $Revision$
+ */
+public class PropertySetCloner {
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    private PropertySet destination;
+    private PropertySet source;
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    public void setDestination(PropertySet destination) {
+        this.destination = destination;
+    }
+
+    public PropertySet getDestination() {
+        return destination;
+    }
+
+    public void setSource(PropertySet source) {
+        this.source = source;
+    }
+
+    public PropertySet getSource() {
+        return source;
+    }
+
+    public void cloneProperties() throws PropertyException {
+        clearDestination();
+
+        Iterator keys = source.getKeys().iterator();
+
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            cloneProperty(key);
+        }
+    }
+
+    /**
+     * Clear all properties that already exist in destination PropertySet.
+     */
+    private void clearDestination() throws PropertyException {
+        Iterator keys = destination.getKeys().iterator();
+
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            destination.remove(key);
+        }
+    }
+
+    /**
+     * Copy individual property from source to destination.
+     */
+    private void cloneProperty(String key) throws PropertyException {
+        switch (source.getType(key)) {
+        case PropertySet.BOOLEAN:
+            destination.setBoolean(key, source.getBoolean(key));
+
+            break;
+
+        case PropertySet.INT:
+            destination.setInt(key, source.getInt(key));
+
+            break;
+
+        case PropertySet.LONG:
+            destination.setLong(key, source.getLong(key));
+
+            break;
+
+        case PropertySet.DOUBLE:
+            destination.setDouble(key, source.getDouble(key));
+
+            break;
+
+        case PropertySet.STRING:
+            destination.setString(key, source.getString(key));
+
+            break;
+
+        case PropertySet.TEXT:
+            destination.setText(key, source.getText(key));
+
+            break;
+
+        case PropertySet.DATE:
+            destination.setDate(key, source.getDate(key));
+
+            break;
+
+        case PropertySet.OBJECT:
+            destination.setObject(key, source.getObject(key));
+
+            break;
+
+        case PropertySet.XML:
+            destination.setXML(key, source.getXML(key));
+
+            break;
+
+        case PropertySet.DATA:
+            destination.setData(key, source.getData(key));
+
+            break;
+
+        case PropertySet.PROPERTIES:
+            destination.setProperties(key, source.getProperties(key));
+
+            break;
+        }
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/PropertySetManager.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+import com.opensymphony.module.propertyset.config.PropertySetConfig;
+
+import java.util.Map;
+
+
+/**
+ * The PropertySetManager is a factory for all the different types of
+ * propertysets registered.
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class PropertySetManager {
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    /**
+     * Get a propertyset by name.
+     * @param name The name of the propertyset as registered in propertyset.xml.
+     * For example 'ejb', or 'memory'.
+     * @param args The arguments to pass to the propertyset for initialization.
+     * Consult the javadocs for a particular propertyset to see what arguments
+     * it requires and supports.
+     */
+    public static PropertySet getInstance(String name, Map args) {
+        PropertySet ps = getInstance(name, args, PropertySetManager.class.getClassLoader());
+
+        if (ps == null) {
+            ps = getInstance(name, args, Thread.currentThread().getContextClassLoader());
+        }
+
+        return ps;
+    }
+
+    /**
+     * @see #getInstance(String, java.util.Map)
+     * @param loader The classloader to use for loading the propertyset.
+     */
+    public static PropertySet getInstance(String name, Map args, ClassLoader loader) {
+        PropertySetConfig psc = PropertySetConfig.getConfig();
+        String clazz = psc.getClassName(name);
+        Map config = psc.getArgs(name);
+        Class psClass;
+
+        try {
+            psClass = loader.loadClass(clazz);
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+
+        try {
+            PropertySet ps = (PropertySet) psClass.newInstance();
+            ps.init(config, args);
+
+            return ps;
+        } catch (InstantiationException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    /**
+     * Copy the contents of one propertyset into another.
+     * @param src The propertyset to copy from.
+     * @param dest The propertyset to copy into.
+     */
+    public static void clone(PropertySet src, PropertySet dest) {
+        PropertySetCloner cloner = new PropertySetCloner();
+        cloner.setSource(src);
+        cloner.setDestination(dest);
+        cloner.cloneProperties();
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/PropertySetSchema.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset;
+
+import java.io.Serializable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ *
+ * @author <a href="mailto:hani@fate.demon.co.uk">Hani Suleiman</a>
+ * @version $Revision$
+ */
+public class PropertySetSchema implements Serializable {
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    private Map propertySchemas;
+    private boolean restricted;
+
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public PropertySetSchema() {
+        propertySchemas = new HashMap();
+    }
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    public void setPropertySchema(String key, PropertySchema ps) {
+        if (ps.getPropertyName() == null) {
+            ps.setPropertyName(key);
+        }
+
+        propertySchemas.put(key, ps);
+    }
+
+    public PropertySchema getPropertySchema(String key) {
+        return (PropertySchema) propertySchemas.get(key);
+    }
+
+    public void setRestricted(boolean b) {
+        restricted = b;
+    }
+
+    public boolean isRestricted() {
+        return restricted;
+    }
+
+    public void addPropertySchema(PropertySchema ps) {
+        propertySchemas.put(ps.getPropertyName(), ps);
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/config/PropertySetConfig.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset.config;
+
+import org.w3c.dom.*;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.URL;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.*;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class PropertySetConfig {
+    //~ Static fields/initializers /////////////////////////////////////////////
+
+    private static PropertySetConfig config;
+    private static final Object lock = new Object();
+    private static final String[] CONFIG_LOCATIONS = new String[] {
+        "propertyset.xml", "/propertyset.xml", "META-INF/propertyset.xml",
+        "/META-INF/propertyset.xml", "META-INF/propertyset-default.xml",
+        "/META-INF/propertyset-default.xml"
+    };
+
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    private HashMap propertySetArgs = new HashMap();
+    private HashMap propertySets = new HashMap();
+
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    private PropertySetConfig() {
+        InputStream is = load();
+
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setNamespaceAware(true);
+
+        DocumentBuilder db = null;
+
+        try {
+            db = dbf.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            e.printStackTrace();
+        }
+
+        Document doc = null;
+
+        try {
+            doc = db.parse(is);
+        } catch (SAXException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            //close the input stream
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) { /* ignore */
+                }
+            }
+        }
+
+        // get propertysets
+        Element root = (Element) doc.getElementsByTagName("propertysets").item(0);
+        NodeList propertySets = root.getElementsByTagName("propertyset");
+
+        for (int i = 0; i < propertySets.getLength(); i++) {
+            Element propertySet = (Element) propertySets.item(i);
+            String name = propertySet.getAttribute("name");
+            String clazz = propertySet.getAttribute("class");
+            this.propertySets.put(name, clazz);
+
+            // get args now
+            NodeList args = propertySet.getElementsByTagName("arg");
+            HashMap argsMap = new HashMap();
+
+            for (int j = 0; j < args.getLength(); j++) {
+                Element arg = (Element) args.item(j);
+                String argName = arg.getAttribute("name");
+                String argValue = arg.getAttribute("value");
+                argsMap.put(argName, argValue);
+            }
+
+            this.propertySetArgs.put(name, argsMap);
+        }
+    }
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    public static PropertySetConfig getConfig() {
+        // check one more time, another thread may have finished
+        synchronized (lock) {
+            if (config == null) {
+                config = new PropertySetConfig();
+            }
+
+            return config;
+        }
+    }
+
+    public Map getArgs(String name) {
+        return (Map) propertySetArgs.get(name);
+    }
+
+    public String getClassName(String name) {
+        return (String) propertySets.get(name);
+    }
+
+    /**
+    * Load a given resource.
+    *
+    * This method will try to load the resource using the following methods (in order):
+    * <ul>
+    *  <li>From Thread.currentThread().getContextClassLoader()
+    *  <li>From ClassLoaderUtil.class.getClassLoader()
+    *  <li>callingClass.getClassLoader()
+    * </ul>
+    *
+    * @param resourceName The name of the resource to load
+    * @param callingClass The Class object of the calling object
+    */
+    public static URL getResource(String resourceName, Class callingClass) {
+        URL url = Thread.currentThread().getContextClassLoader().getResource(resourceName);
+
+        if (url == null) {
+            url = PropertySetConfig.class.getClassLoader().getResource(resourceName);
+        }
+
+        if (url == null) {
+            ClassLoader cl = callingClass.getClassLoader();
+
+            if (cl != null) {
+                url = cl.getResource(resourceName);
+            }
+        }
+
+        if ((url == null) && (resourceName != null) && (resourceName.charAt(0) != '/')) {
+            return getResource('/' + resourceName, callingClass);
+        }
+
+        return url;
+    }
+
+    /**
+     * Load the config from locations found in {@link #CONFIG_LOCATIONS}
+     *
+     * @return  An inputstream to load from
+     * @throws IllegalArgumentException     If none of the config files could be found.
+     */
+    private InputStream load() throws IllegalArgumentException {
+        InputStream is = null;
+
+        for (int i = 0; i < CONFIG_LOCATIONS.length; i++) {
+            String location = CONFIG_LOCATIONS[i];
+
+            try {
+                URL resource = getResource(location, this.getClass());
+
+                if (resource != null) {
+                    is = resource.openStream();
+                }
+
+                //if we have found something then stop looking
+                if (is != null) {
+                    return is;
+                }
+            } catch (Exception e) {
+                //do nothing.
+            }
+        }
+
+        if (is == null) {
+            String exceptionMessage = "Could not load propertyset config using '" + CONFIG_LOCATIONS + "'.  Please check your classpath.";
+            throw new IllegalArgumentException(exceptionMessage);
+        }
+
+        return is;
+    }
+}

File api/src/main/java/com/opensymphony/module/propertyset/verifiers/PropertyVerifier.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset.verifiers;
+
+import java.io.Serializable;
+
+
+/**
+ *
+ * @author <a href="mailto:hani@fate.demon.co.uk">Hani Suleiman</a>
+ * @version $Revision$
+ */
+public interface PropertyVerifier extends Serializable {
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    public void verify(Object value) throws VerifyException;
+}

File api/src/main/java/com/opensymphony/module/propertyset/verifiers/VerifyException.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset.verifiers;
+
+
+/**
+ *
+ * @author <a href="mailto:hani@fate.demon.co.uk">Hani Suleiman</a>
+ * @version $Revision$
+ */
+public class VerifyException extends RuntimeException {
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public VerifyException() {
+        super();
+    }
+
+    public VerifyException(String msg) {
+        super(msg);
+    }
+}

File core/src/main/java/com/opensymphony/module/propertyset/aggregate/AggregatePropertySet.java

View file
+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.module.propertyset.aggregate;
+
+import com.opensymphony.module.propertyset.*;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.w3c.dom.Document;
+
+import java.io.Serializable;
+
+import java.util.*;
+
+
+/**
+ * PropertySet composed of a collection of other propertysets.
+ * Tried each of the propertysets to find a value, tries to be
+ * as fault tolerant as possible, in that when any error occurs,
+ * it simply tries the operation on the next set.
+ * <p>
+ *
+ * <b>Optional Args</b>
+ * <ul>
+ *  <li><b>PropertySets</b> - a List of PropertySet</li>
+ * </ul>
+ *
+ * Date: Dec 16, 2001
+ * Time: 11:28:06 PM
+ * @author Hani Suleiman
+ */</