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.AbstractCollection;
019 import java.util.AbstractMap;
020 import java.util.AbstractSet;
021 import java.util.Arrays;
022 import java.util.Collection;
023 import java.util.Iterator;
024 import java.util.Map;
025 import java.util.Set;
026
027 import org.joda.beans.MetaProperty;
028
029 /**
030 * A map of name to meta-property designed for use by {@code DirectBean}.
031 * <p>
032 * This meta-property map implementation is designed primarily for code-generation.
033 * It stores a reference to the meta-bean and the meta-properties.
034 * The meta-properties are accessed using {@link DirectMetaBean#metaPropertyGet(String)}.
035 * <p>
036 * This class is immutable and thread-safe.
037 *
038 * @author Stephen Colebourne
039 */
040 @SuppressWarnings("rawtypes")
041 public final class DirectMetaPropertyMap implements Map<String, MetaProperty<?>> {
042
043 /** The meta-bean. */
044 private final DirectMetaBean metaBean;
045 /** The property names. */
046 private final Set<String> keys;
047 /** The meta-properties. */
048 private final Collection<MetaProperty<?>> values;
049 /** The map entries. */
050 private final Set<Entry<String, MetaProperty<?>>> entries;
051
052 /**
053 * Constructor.
054 *
055 * @param metaBean the meta-bean, not null
056 * @param parent the superclass parent, may be null
057 * @param propertyNames the property names, not null
058 */
059 @SuppressWarnings("unchecked")
060 public DirectMetaPropertyMap(final DirectMetaBean metaBean, DirectMetaPropertyMap parent, String... propertyNames) {
061 if (metaBean == null) {
062 throw new NullPointerException("MetaBean must not be null");
063 }
064 this.metaBean = metaBean;
065 int parentSize = 0;
066 final Entry<String, MetaProperty<?>>[] metaProperties;
067 if (parent != null) {
068 parentSize = parent.size();
069 metaProperties = Arrays.copyOf(((Entries) parent.entries).metaProperties, parentSize + propertyNames.length);
070 } else {
071 metaProperties = new Entry[propertyNames.length];
072 }
073 for (int i = 0 ; i < propertyNames.length; i++) {
074 metaProperties[i + parentSize] = new AbstractMap.SimpleImmutableEntry(propertyNames[i], metaBean.metaPropertyGet(propertyNames[i]));
075 }
076 keys = new Keys(metaProperties);
077 values = new Values(metaProperties);
078 entries = new Entries(metaProperties);
079 }
080
081 //-----------------------------------------------------------------------
082 @Override
083 public int size() {
084 return keys.size();
085 }
086
087 @Override
088 public boolean isEmpty() {
089 return size() == 0;
090 }
091
092 @SuppressWarnings("unchecked")
093 @Override
094 public MetaProperty<Object> get(Object propertyName) {
095 if (propertyName instanceof String) {
096 return (MetaProperty<Object>) metaBean.metaPropertyGet((String) propertyName);
097 }
098 return null;
099 }
100
101 @Override
102 public boolean containsKey(Object propertyName) {
103 return propertyName instanceof String &&
104 metaBean.metaPropertyGet(propertyName.toString()) != null;
105 }
106
107 @Override
108 public boolean containsValue(Object value) {
109 return value instanceof MetaProperty &&
110 metaBean.metaPropertyGet(((MetaProperty<?>) value).name()) != null;
111 }
112
113 //-----------------------------------------------------------------------
114 @Override
115 public MetaProperty<?> put(String key, MetaProperty<?> value) {
116 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified");
117 }
118
119 @Override
120 public MetaProperty<?> remove(Object key) {
121 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified");
122 }
123
124 @Override
125 public void putAll(Map<? extends String, ? extends MetaProperty<?>> m) {
126 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified");
127 }
128
129 @Override
130 public void clear() {
131 throw new UnsupportedOperationException("DirectBean meta-property map cannot be modified");
132 }
133
134 //-----------------------------------------------------------------------
135 @Override
136 public Set<String> keySet() {
137 return keys;
138 }
139
140 @Override
141 public Collection<MetaProperty<?>> values() {
142 return values;
143 }
144
145 @Override
146 public Set<Entry<String, MetaProperty<?>>> entrySet() {
147 return entries;
148 }
149
150 //-----------------------------------------------------------------------
151 /**
152 * Collection implementation for the keys.
153 */
154 private static final class Keys extends AbstractSet<String> {
155 private final Entry<String, MetaProperty<?>>[] metaProperties;
156
157 private Keys(Entry<String, MetaProperty<?>>[] metaProperties) {
158 this.metaProperties = metaProperties;
159 }
160
161 @Override
162 public Iterator<String> iterator() {
163 return new Iterator<String>() {
164 int index;
165 @Override
166 public boolean hasNext() {
167 return index < metaProperties.length;
168 }
169 @Override
170 public String next() {
171 return metaProperties[index++].getKey();
172 }
173 @Override
174 public void remove() {
175 throw new UnsupportedOperationException();
176 }
177 };
178 }
179
180 @Override
181 public int size() {
182 return metaProperties.length;
183 }
184 }
185
186 /**
187 * Collection implementation for the values.
188 */
189 private static final class Values extends AbstractCollection<MetaProperty<?>> {
190 private final Entry<String, MetaProperty<?>>[] metaProperties;
191
192 private Values(Entry<String, MetaProperty<?>>[] metaProperties) {
193 this.metaProperties = metaProperties;
194 }
195
196 @Override
197 public Iterator<MetaProperty<?>> iterator() {
198 return new Iterator<MetaProperty<?>>() {
199 int index;
200 @Override
201 public boolean hasNext() {
202 return index < metaProperties.length;
203 }
204 @Override
205 public MetaProperty<?> next() {
206 return metaProperties[index++].getValue();
207 }
208 @Override
209 public void remove() {
210 throw new UnsupportedOperationException();
211 }
212 };
213 }
214
215 @Override
216 public int size() {
217 return metaProperties.length;
218 }
219 }
220
221 /**
222 * Collection implementation for the entries.
223 */
224 private static final class Entries extends AbstractSet<Entry<String, MetaProperty<?>>> {
225 private final Entry<String, MetaProperty<?>>[] metaProperties;
226
227 private Entries(Entry<String, MetaProperty<?>>[] metaProperties) {
228 this.metaProperties = metaProperties;
229 }
230
231 @Override
232 public Iterator<Entry<String, MetaProperty<?>>> iterator() {
233 return new Iterator<Entry<String, MetaProperty<?>>>() {
234 int index;
235 @Override
236 public boolean hasNext() {
237 return index < metaProperties.length;
238 }
239 @Override
240 public Entry<String, MetaProperty<?>> next() {
241 return metaProperties[index++];
242 }
243 @Override
244 public void remove() {
245 throw new UnsupportedOperationException();
246 }
247 };
248 }
249
250 @Override
251 public int size() {
252 return metaProperties.length;
253 }
254 }
255
256 }