001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.configuration.spring;
019:
020: import java.beans.PropertyDescriptor;
021: import java.lang.reflect.InvocationTargetException;
022: import java.lang.reflect.Method;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029: import java.util.Set;
030: import java.util.concurrent.ConcurrentHashMap;
031:
032: import org.apache.cxf.helpers.CastUtils;
033: import org.springframework.beans.BeanUtils;
034: import org.springframework.beans.BeansException;
035: import org.springframework.beans.Mergeable;
036: import org.springframework.beans.PropertyValue;
037: import org.springframework.beans.factory.BeanInitializationException;
038: import org.springframework.beans.factory.BeanIsAbstractException;
039: import org.springframework.beans.factory.InitializingBean;
040: import org.springframework.beans.factory.config.BeanDefinition;
041: import org.springframework.beans.factory.config.TypedStringValue;
042: import org.springframework.beans.factory.support.ManagedList;
043: import org.springframework.beans.factory.support.ManagedSet;
044: import org.springframework.context.ApplicationContext;
045: import org.springframework.context.ApplicationContextAware;
046: import org.springframework.context.ConfigurableApplicationContext;
047:
048: public class SpringBeanMap<V> implements ApplicationContextAware,
049: InitializingBean, Map<String, V> {
050: private ApplicationContext context;
051: private Class<?> type;
052: private String idsProperty;
053: private Map<String, String> idToBeanName = new ConcurrentHashMap<String, String>();
054: private Map<String, V> putStore = new ConcurrentHashMap<String, V>();
055:
056: public void setApplicationContext(ApplicationContext ctx)
057: throws BeansException {
058: this .context = ctx;
059: }
060:
061: public void afterPropertiesSet() throws Exception {
062: processBeans(context);
063: }
064:
065: private void processBeans(ApplicationContext beanFactory) {
066: if (beanFactory == null) {
067: return;
068: }
069:
070: String[] beanNames = beanFactory.getBeanNamesForType(type);
071:
072: ConfigurableApplicationContext ctxt = (ConfigurableApplicationContext) beanFactory;
073:
074: // Take any bean name or alias that has a web service annotation
075: for (int i = 0; i < beanNames.length; i++) {
076: BeanDefinition def = ctxt.getBeanFactory()
077: .getBeanDefinition(beanNames[i]);
078:
079: if (!def.isSingleton() || def.isAbstract()) {
080: continue;
081: }
082:
083: try {
084: Collection<?> ids = null;
085: PropertyValue pv = def.getPropertyValues()
086: .getPropertyValue(idsProperty);
087:
088: if (pv != null) {
089: Object value = pv.getValue();
090: if (!(value instanceof Collection)) {
091: throw new RuntimeException("The property "
092: + idsProperty
093: + " must be a collection!");
094: }
095:
096: if (value instanceof Mergeable) {
097: if (!((Mergeable) value).isMergeEnabled()) {
098: ids = (Collection<?>) value;
099: }
100: } else {
101: ids = (Collection<?>) value;
102: }
103: }
104:
105: if (ids == null) {
106: ids = getIds(ctxt.getBean(beanNames[i]));
107: if (ids == null) {
108: continue;
109: }
110: }
111:
112: if (ids instanceof ManagedSet
113: || ids instanceof ManagedList) {
114: List<String> newIds = new ArrayList<String>();
115: for (Iterator itr = ids.iterator(); itr.hasNext();) {
116: Object o = itr.next();
117: if (o instanceof TypedStringValue) {
118: newIds.add(((TypedStringValue) o)
119: .getValue());
120: } else {
121: newIds.add((String) o);
122: }
123: }
124: ids = newIds;
125: }
126: for (Object id : ids) {
127: idToBeanName.put(id.toString(), beanNames[i]);
128: }
129: } catch (BeanIsAbstractException e) {
130: // The bean is abstract, we won't be doing anything with it.
131: continue;
132: }
133: }
134:
135: processBeans(ctxt.getParent());
136: }
137:
138: private Collection<String> getIds(Object bean) {
139: try {
140: PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(
141: bean.getClass(), idsProperty);
142: Method method = pd.getReadMethod();
143: Collection<String> c = CastUtils
144: .cast((Collection<?>) method.invoke(bean,
145: new Object[0]));
146:
147: return c;
148: } catch (IllegalArgumentException e) {
149: throw new BeanInitializationException(
150: "Could not retrieve ids.", e);
151: } catch (IllegalAccessException e) {
152: throw new BeanInitializationException(
153: "Could not access id getter.", e);
154: } catch (InvocationTargetException e) {
155: throw new BeanInitializationException(
156: "Could not invoke id getter.", e);
157: } catch (SecurityException e) {
158: throw new BeanInitializationException(
159: "Could not invoke id getter.", e);
160: }
161: }
162:
163: public Object postProcessBeforeInitialization(Object bean,
164: String beanName) throws BeansException {
165: return bean;
166: }
167:
168: public Class<?> getType() {
169: return type;
170: }
171:
172: public void setType(Class<?> type) {
173: this .type = type;
174: }
175:
176: public String getIdsProperty() {
177: return idsProperty;
178: }
179:
180: public void setIdsProperty(String idsProperty) {
181: this .idsProperty = idsProperty;
182: }
183:
184: public void clear() {
185: throw new UnsupportedOperationException();
186: }
187:
188: public boolean containsKey(Object key) {
189: return idToBeanName.containsKey(key)
190: || putStore.containsKey(key);
191: }
192:
193: public boolean containsValue(Object arg0) {
194: throw new UnsupportedOperationException();
195: }
196:
197: public Set<java.util.Map.Entry<String, V>> entrySet() {
198: Set<Map.Entry<String, V>> entries = new HashSet<Map.Entry<String, V>>();
199: for (String k : keySet()) {
200: entries.add(new Entry<V>(this , k));
201: }
202: return entries;
203: }
204:
205: @SuppressWarnings("unchecked")
206: public V get(Object key) {
207: String name = idToBeanName.get(key);
208: if (name != null) {
209: return (V) context.getBean(name);
210: } else {
211: return putStore.get(key);
212: }
213: }
214:
215: public boolean isEmpty() {
216: return idToBeanName.isEmpty() && putStore.isEmpty();
217: }
218:
219: public Set<String> keySet() {
220: Set<String> keys = new HashSet<String>();
221: keys.addAll(idToBeanName.keySet());
222: keys.addAll(putStore.keySet());
223: return keys;
224: }
225:
226: public V put(String key, V value) {
227: // Make sure we don't take the key from Spring any more
228: idToBeanName.remove(key);
229: return putStore.put(key, value);
230: }
231:
232: public void putAll(Map<? extends String, ? extends V> m) {
233: putStore.putAll(m);
234: }
235:
236: public V remove(Object key) {
237: V v = get(key);
238: if (v != null) {
239: idToBeanName.remove(key);
240: } else {
241: v = putStore.get(key);
242: }
243:
244: return v;
245: }
246:
247: public int size() {
248: return idToBeanName.size() + putStore.size();
249: }
250:
251: public Collection<V> values() {
252: List<V> values = new ArrayList<V>();
253: values.addAll(putStore.values());
254: for (String id : idToBeanName.keySet()) {
255: values.add(get(id));
256: }
257: return values;
258: }
259:
260: public static class Entry<V> implements Map.Entry<String, V> {
261: private SpringBeanMap<V> map;
262: private String key;
263:
264: public Entry(SpringBeanMap<V> map, String key) {
265: this .map = map;
266: this .key = key;
267: }
268:
269: public String getKey() {
270: return key;
271: }
272:
273: public V getValue() {
274: return map.get(key);
275: }
276:
277: public V setValue(V value) {
278: return map.put(key, value);
279: }
280: }
281: }
|