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;
017    
018    import java.util.AbstractMap;
019    import java.util.AbstractSet;
020    import java.util.Collections;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.Map;
024    import java.util.Set;
025    
026    import org.joda.beans.Bean;
027    import org.joda.beans.MetaProperty;
028    import org.joda.beans.Property;
029    import org.joda.beans.PropertyMap;
030    
031    /**
032     * A standard map of properties.
033     * <p>
034     * This is the standard implementation of a map of properties derived from a meta-bean.
035     * 
036     * @author Stephen Colebourne
037     */
038    public final class BasicPropertyMap
039            extends AbstractMap<String, Property<?>> implements PropertyMap {
040    
041        /** The bean. */
042        private final Bean bean;
043    
044        /**
045         * Factory to create a property map avoiding duplicate generics.
046         * 
047         * @param bean  the bean
048         */
049        public static BasicPropertyMap of(Bean bean) {
050            return new BasicPropertyMap(bean);
051        }
052    
053        /**
054         * Creates a property map.
055         * 
056         * @param bean  the bean that the property is bound to, not null
057         */
058        private BasicPropertyMap(Bean bean) {
059            if (bean == null) {
060                throw new NullPointerException("Bean must not be null");
061            }
062            this.bean = bean;
063        }
064    
065        //-----------------------------------------------------------------------
066        @Override
067        public int size() {
068            return bean.metaBean().metaPropertyCount();
069        }
070    
071        @Override
072        public boolean containsKey(Object obj) {
073            return obj instanceof String ? bean.metaBean().metaPropertyExists(obj.toString()) : false;
074        }
075    
076        @Override
077        public Property<?> get(Object obj) {
078            return containsKey(obj) ? bean.metaBean().metaProperty(obj.toString()).createProperty(bean) : null;
079        }
080    
081        @Override
082        public Set<String> keySet() {
083            return bean.metaBean().metaPropertyMap().keySet();
084        }
085    
086        @Override
087        public Set<Entry<String, Property<?>>> entrySet() {
088            return new AbstractSet<Entry<String,Property<?>>>() {
089                // TODO: possibly override contains()
090                @Override
091                public int size() {
092                    return bean.metaBean().metaPropertyCount();
093                }
094                @Override
095                public Iterator<Entry<String, Property<?>>> iterator() {
096                    final Iterator<MetaProperty<?>> it = bean.metaBean().metaPropertyMap().values().iterator();
097                    return new Iterator<Entry<String, Property<?>>>() {
098                        @Override
099                        public boolean hasNext() {
100                            return it.hasNext();
101                        }
102                        @Override
103                        public Entry<String, Property<?>> next() {
104                            MetaProperty<?> meta = it.next();
105                            return new SimpleImmutableEntry<String, Property<?>>(meta.name(), BasicProperty.of(bean, meta));
106                        }
107                        @Override
108                        public void remove() {
109                            throw new UnsupportedOperationException("Unmodifiable");
110                        }
111                    };
112                }
113            };
114        }
115    
116        //-----------------------------------------------------------------------
117        @Override
118        public Map<String, Object> flatten() {
119            // TODO: dedicated map implementation
120            Map<String, MetaProperty<?>> propertyMap = bean.metaBean().metaPropertyMap();
121            Map<String, Object> map = new HashMap<String, Object>(propertyMap.size());
122            for (Entry<String, MetaProperty<?>> entry : propertyMap.entrySet()) {
123                map.put(entry.getKey(), entry.getValue().get(bean));
124            }
125            return Collections.unmodifiableMap(map);
126        }
127    
128    }