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