001    /*
002     *  Copyright 2001-2013 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.beans.impl.direct;
017    
018    import java.util.NoSuchElementException;
019    import java.util.Set;
020    
021    import org.joda.beans.Bean;
022    import org.joda.beans.JodaBeanUtils;
023    import org.joda.beans.Property;
024    
025    /**
026     * A bean implementation designed for use by the code generator.
027     * <p>
028     * This implementation uses direct access via {@link #propertyGet(String)} and
029     * {@link #propertySet(String, Object)} to avoid reflection.
030     * <p>
031     * For code generation, the bean must directly extend this class and have a
032     * no-arguments constructor.
033     * 
034     * @author Stephen Colebourne
035     */
036    public abstract class DirectBean implements Bean {
037    
038        @Override
039        public <R> Property<R> property(String propertyName) {
040            return metaBean().<R>metaProperty(propertyName).createProperty(this);
041        }
042    
043        @Override
044        public Set<String> propertyNames() {
045            return metaBean().metaPropertyMap().keySet();
046        }
047    
048        //-------------------------------------------------------------------------
049        /**
050         * Gets the value of the property.
051         * 
052         * @param propertyName  the property name, not null
053         * @param quiet  true to return null if unable to read
054         * @return the value of the property, may be null
055         * @throws NoSuchElementException if the property name is invalid
056         */
057        protected Object propertyGet(String propertyName, boolean quiet) {
058            throw new NoSuchElementException("Unknown property: " + propertyName);
059        }
060    
061        /**
062         * Sets the value of the property.
063         * 
064         * @param propertyName  the property name, not null
065         * @param value  the value of the property, may be null
066         * @param quiet  true to take no action if unable to write
067         * @throws NoSuchElementException if the property name is invalid
068         */
069        protected void propertySet(String propertyName, Object value, boolean quiet) {
070            throw new NoSuchElementException("Unknown property: " + propertyName);
071        }
072    
073        /**
074         * Validates the values of the properties.
075         * 
076         * @throws RuntimeException if a property is invalid
077         */
078        protected void validate() {
079        }
080    
081        //-----------------------------------------------------------------------
082        @Override
083        public boolean equals(Object obj) {
084            if (obj == this) {
085                return true;
086            }
087            if (obj != null && getClass() == obj.getClass()) {
088                DirectBean other = (DirectBean) obj;
089                for (String name : propertyNames()) {
090                    Object value1 = propertyGet(name, true);
091                    Object value2 = other.propertyGet(name, true);
092                    if (JodaBeanUtils.equal(value1, value2) == false) {
093                        return false;
094                    }
095                }
096                return true;
097            }
098            return false;
099        }
100    
101        @Override
102        public int hashCode() {
103            int hash = getClass().hashCode();
104            Set<String> names = propertyNames();
105            for (String name : names) {
106                Object value = propertyGet(name, true);
107                hash += JodaBeanUtils.hashCode(value);
108            }
109            return hash;
110        }
111    
112        @Override
113        public String toString() {
114            Set<String> names = propertyNames();
115            StringBuilder buf = new StringBuilder((names.size()) * 32 + 32);
116            buf.append(getClass().getSimpleName());
117            buf.append('{');
118            if (names.size() > 0) {
119                for (String name : names) {
120                    Object value = propertyGet(name, true);
121                    buf.append(name).append('=').append(value).append(',').append(' ');
122                }
123                buf.setLength(buf.length() - 2);
124            }
125            buf.append('}');
126            return buf.toString();
127        }
128    
129    }