001: // Copyright 2006, 2007 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.tapestry.ioc.internal.services;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newLinkedList;
018: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
019: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newConcurrentMap;
020:
021: import java.beans.BeanInfo;
022: import java.beans.IntrospectionException;
023: import java.beans.Introspector;
024: import java.beans.PropertyDescriptor;
025: import java.util.LinkedList;
026: import java.util.List;
027: import java.util.Map;
028:
029: import org.apache.tapestry.ioc.services.ClassPropertyAdapter;
030: import org.apache.tapestry.ioc.services.PropertyAccess;
031:
032: public class PropertyAccessImpl implements PropertyAccess {
033: private final Map<Class, ClassPropertyAdapter> _adapters = newConcurrentMap();
034:
035: public Object get(Object instance, String propertyName) {
036: return getAdapter(instance).get(instance, propertyName);
037: }
038:
039: public void set(Object instance, String propertyName, Object value) {
040: getAdapter(instance).set(instance, propertyName, value);
041: }
042:
043: /** Clears the cache of adapters and asks the Introspector to clear its cache. */
044: public synchronized void clearCache() {
045: _adapters.clear();
046:
047: Introspector.flushCaches();
048: }
049:
050: public ClassPropertyAdapter getAdapter(Object instance) {
051: return getAdapter(instance.getClass());
052: }
053:
054: public ClassPropertyAdapter getAdapter(Class forClass) {
055: ClassPropertyAdapter result = _adapters.get(forClass);
056:
057: if (result == null) {
058: result = buildAdapter(forClass);
059: _adapters.put(forClass, result);
060: }
061:
062: return result;
063: }
064:
065: /**
066: * Builds a new adapter and updates the _adapters cache. This not only guards access to the
067: * adapter cache, but also serializes access to the Java Beans Introspector, which is not thread
068: * safe. In addition, handles the case where the class in question is an interface, accumulating
069: * properties inherited from super-classes.
070: */
071: private synchronized ClassPropertyAdapter buildAdapter(
072: Class forClass) {
073: // In some race conditions, we may hit this method for the same class multiple times.
074: // We just let it happen, replacing the old ClassPropertyAdapter with a new one.
075:
076: try {
077: BeanInfo info = Introspector.getBeanInfo(forClass);
078:
079: List<PropertyDescriptor> descriptors = newList();
080:
081: addAll(descriptors, info.getPropertyDescriptors());
082:
083: if (forClass.isInterface())
084: addPropertiesFromExtendedInterfaces(forClass,
085: descriptors);
086:
087: return new ClassPropertyAdapterImpl(forClass, descriptors);
088: } catch (Throwable ex) {
089: throw new RuntimeException(ex);
090: }
091: }
092:
093: private <T> void addAll(List<T> list, T[] array) {
094: for (T i : array)
095: list.add(i);
096: }
097:
098: private void addPropertiesFromExtendedInterfaces(Class forClass,
099: List<PropertyDescriptor> descriptors)
100: throws IntrospectionException {
101: LinkedList<Class> queue = newLinkedList();
102:
103: // Seed the queue
104: addAll(queue, forClass.getInterfaces());
105:
106: while (!queue.isEmpty()) {
107: Class c = queue.removeFirst();
108:
109: BeanInfo info = Introspector.getBeanInfo(c);
110:
111: addAll(descriptors, info.getPropertyDescriptors());
112: addAll(queue, c.getInterfaces());
113: }
114: }
115:
116: }
|