001package jmri.beans;
002
003import java.util.Set;
004
005/**
006 * Generic implementation of {@link jmri.beans.BeanInterface} that supports
007 * arbitrary properties defined at runtime.
008 * <p>
009 * <b>NOTE</b> This class does not implement
010 * {@link java.beans.PropertyChangeSupport}. Subclass {@link jmri.beans.Bean} if
011 * you need to support property change listeners.
012 *
013 * @author Randall Wood
014 */
015public abstract class UnboundArbitraryBean extends UnboundBean {
016
017    protected final ArbitraryPropertySupport arbitraryPropertySupport = new ArbitraryPropertySupport(this);
018
019    /**
020     * Get value of element at <i>index</i> of property array <i>key</i>.
021     * <p>
022     * This implementation calls a read method for the indexed property using
023     * JavaBeans introspection, and assumes, based on JavaBeans coding patterns,
024     * that the read method has the following parameter: <code>index</code>.
025     *
026     * Note that this method returns null instead of throwing
027     * {@link java.lang.ArrayIndexOutOfBoundsException} if the index is invalid
028     * since the Java introspection methods provide no reliable way to get the
029     * size of the indexed property.
030     *
031     * @param key Property array to parse.
032     * @param index Element to retrieve.
033     * @return value of element or null
034     */
035    @Override
036    public Object getIndexedProperty(String key, int index) {
037        return this.arbitraryPropertySupport.getIndexedProperty(key, index);
038    }
039
040    /**
041     * Get the value of property key.
042     * <p>
043     * If <i>null</i> is a valid (or expected) value for <i>key</i>, you might
044     * want to use {@link Bean#hasProperty(java.lang.String)} to test that the
045     * property exists.
046     * <p>
047     * This implementation searches the internal property collection
048     * and uses introspection to get the property.
049     *
050     * @param key Property to retrieve.
051     * @return value of key or null.
052     * @see BeanInterface#getProperty(java.lang.String)
053     */
054    @Override
055    public Object getProperty(String key) {
056        return this.arbitraryPropertySupport.getProperty(key);
057    }
058
059    /**
060     * Return a list of property names.
061     * <p>
062     * This implementation combines the keys in
063     * {@link ArbitraryPropertySupport#getPropertyNames()} with the results of
064     * {@link BeanUtil#getIntrospectedPropertyNames(java.lang.Object)}.
065     *
066     * @return a Set of names
067     * @see BeanInterface#getPropertyNames()
068     */
069    @Override
070    public Set<String> getPropertyNames() {
071        return this.arbitraryPropertySupport.getPropertyNames();
072    }
073
074    /**
075     * Test if a property exists.
076     * <p>
077     * This implementation searches the internal property collection
078     * and uses introspection to get the property.
079     *
080     * @param key Property to inspect.
081     * @return true if property exists
082     * @see BeanInterface#hasProperty(java.lang.String)
083     */
084    @Override
085    public boolean hasProperty(String key) {
086        return this.arbitraryPropertySupport.hasProperty(key);
087    }
088
089    @Override
090    public boolean hasIndexedProperty(String key) {
091        return this.arbitraryPropertySupport.hasIndexedProperty(key);
092    }
093
094    /**
095     * Set element at <i>index</i> of property array <i>key</i> to <i>value</i>.
096     * <p>
097     * This implementation calls a write method for the indexed property using
098     * JavaBeans introspection, and assumes, based on JavaBeans coding patterns,
099     * that the write method has the following two parameters in order:
100     * <code>index</code>, <code>value</code>.
101     *
102     * @param key Property array to use.
103     * @param index Element to write.
104     * @param value Value to set.
105     * @see BeanInterface#setIndexedProperty(java.lang.String, int,
106     *      java.lang.Object)
107     */
108    @Override
109    public void setIndexedProperty(String key, int index, Object value) {
110        this.arbitraryPropertySupport.setIndexedProperty(key, index, value);
111    }
112
113    /**
114     * Set property <i>key</i> to <i>value</i>.
115     * <p>
116     * This implementation checks that a write method is not available for the
117     * property using JavaBeans introspection, and stores the property using
118     * {@link ArbitraryPropertySupport#setProperty(String, Object)} only if a
119     * write method does not exist. This implementation also fires a
120     * PropertyChangeEvent for the property.
121     *
122     * @param key Property to use.
123     * @param value Value to store.
124     * @see BeanInterface#setProperty(java.lang.String, java.lang.Object)
125     */
126    @Override
127    public void setProperty(String key, Object value) {
128        this.arbitraryPropertySupport.setProperty(key, value);
129    }
130}