001    // Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.ioc.internal.services;
016    
017    import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
018    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
019    import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
020    import org.apache.tapestry5.ioc.services.PropertyAdapter;
021    
022    import java.beans.PropertyDescriptor;
023    import java.lang.reflect.Field;
024    import java.lang.reflect.Method;
025    import java.util.List;
026    import java.util.Map;
027    
028    import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
029    
030    public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
031    {
032        private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap();
033    
034        private final Class beanType;
035    
036        public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors)
037        {
038            this.beanType = beanType;
039    
040            for (PropertyDescriptor pd : descriptors)
041            {
042                // Indexed properties will have a null propertyType (and a non-null
043                // indexedPropertyType). We ignore indexed properties.
044    
045                if (pd.getPropertyType() == null)
046                    continue;
047    
048                Method readMethod = pd.getReadMethod();
049    
050                Class propertyType = readMethod == null ? pd.getPropertyType() : GenericsUtils.extractGenericReturnType(
051                        beanType, readMethod);
052    
053                PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, pd
054                        .getWriteMethod());
055    
056                adapters.put(pa.getName(), pa);
057            }
058    
059            // Now, add any public fields (even if static) that do not conflict
060    
061            for (Field f : beanType.getFields())
062            {
063                String name = f.getName();
064    
065                if (!adapters.containsKey(name))
066                {
067                    Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f);
068                    PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f);
069    
070                    adapters.put(name, pa);
071                }
072            }
073        }
074    
075        public Class getBeanType()
076        {
077            return beanType;
078        }
079    
080        @Override
081        public String toString()
082        {
083            String names = InternalUtils.joinSorted(adapters.keySet());
084    
085            return String.format("<ClassPropertyAdaptor %s : %s>", beanType.getName(), names);
086        }
087    
088        public List<String> getPropertyNames()
089        {
090            return InternalUtils.sortedKeys(adapters);
091        }
092    
093        public PropertyAdapter getPropertyAdapter(String name)
094        {
095            return adapters.get(name);
096        }
097    
098        public Object get(Object instance, String propertyName)
099        {
100            return adaptorFor(propertyName).get(instance);
101        }
102    
103        public void set(Object instance, String propertyName, Object value)
104        {
105            adaptorFor(propertyName).set(instance, value);
106        }
107    
108        private PropertyAdapter adaptorFor(String name)
109        {
110            PropertyAdapter pa = adapters.get(name);
111    
112            if (pa == null)
113                throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
114    
115            return pa;
116        }
117    
118    }