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.List;
027: import java.util.Map;
028: import java.util.Set;
029: import java.util.concurrent.ConcurrentHashMap;
030:
031: import javax.xml.namespace.QName;
032:
033: import org.apache.cxf.helpers.CastUtils;
034: import org.springframework.beans.BeanUtils;
035: import org.springframework.beans.BeansException;
036: import org.springframework.beans.Mergeable;
037: import org.springframework.beans.PropertyValue;
038: import org.springframework.beans.factory.BeanInitializationException;
039: import org.springframework.beans.factory.BeanIsAbstractException;
040: import org.springframework.beans.factory.InitializingBean;
041: import org.springframework.beans.factory.config.BeanDefinition;
042: import org.springframework.beans.factory.config.BeanReference;
043: import org.springframework.context.ApplicationContext;
044: import org.springframework.context.ApplicationContextAware;
045: import org.springframework.context.ConfigurableApplicationContext;
046:
047: public class SpringBeanQNameMap<V> implements ApplicationContextAware,
048: InitializingBean, Map<QName, V> {
049: private ApplicationContext context;
050: private Class<?> type;
051: private String idsProperty;
052: private Map<QName, String> idToBeanName = new ConcurrentHashMap<QName, String>();
053: private Map<QName, V> putStore = new ConcurrentHashMap<QName, V>();
054:
055: public void setApplicationContext(ApplicationContext ctx)
056: throws BeansException {
057: this .context = ctx;
058: }
059:
060: public void afterPropertiesSet() throws Exception {
061: processBeans(context);
062: }
063:
064: private void processBeans(ApplicationContext beanFactory) {
065: if (beanFactory == null) {
066: return;
067: }
068:
069: String[] beanNames = beanFactory.getBeanNamesForType(type);
070:
071: ConfigurableApplicationContext ctxt = (ConfigurableApplicationContext) beanFactory;
072:
073: // Take any bean name or alias that has a web service annotation
074: for (int i = 0; i < beanNames.length; i++) {
075:
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 values are not legal keys (for lazy-init bean definitions id values may be
106: // BeanDefinitionHolders), load the bean and get its id values instead
107: // for BeanReference type values, simply resolve reference
108: //
109: if (null != ids) {
110: Collection<Object> checked = new ArrayList<Object>(
111: ids.size());
112: for (Object id : ids) {
113: if (id instanceof QName) {
114: checked.add(id);
115: } else if (id instanceof BeanReference) {
116: BeanReference br = (BeanReference) id;
117: Object refId = context.getBean(br
118: .getBeanName());
119: checked.add(refId);
120: } else {
121: break;
122: }
123: }
124: if (checked.size() < ids.size()) {
125: ids = null;
126: } else {
127: ids = checked;
128: }
129: }
130: if (ids == null) {
131: ids = getIds(ctxt.getBean(beanNames[i]));
132: if (ids == null) {
133: continue;
134: }
135: }
136:
137: for (Object id : ids) {
138: QName key = (QName) id;
139: idToBeanName.put(key, beanNames[i]);
140: }
141: } catch (BeanIsAbstractException e) {
142: // The bean is abstract, we won't be doing anything with it.
143: continue;
144: }
145: }
146:
147: processBeans(ctxt.getParent());
148: }
149:
150: private Collection<QName> getIds(Object bean) {
151: try {
152: PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(
153: bean.getClass(), idsProperty);
154: Method method = pd.getReadMethod();
155: Collection<QName> c = CastUtils.cast((Collection<?>) method
156: .invoke(bean, new Object[0]), QName.class);
157:
158: return c;
159: } catch (IllegalArgumentException e) {
160: throw new BeanInitializationException(
161: "Could not retrieve ids.", e);
162: } catch (IllegalAccessException e) {
163: throw new BeanInitializationException(
164: "Could not access id getter.", e);
165: } catch (InvocationTargetException e) {
166: throw new BeanInitializationException(
167: "Could not invoke id getter.", e);
168: } catch (SecurityException e) {
169: throw new BeanInitializationException(
170: "Could not invoke id getter.", e);
171: }
172: }
173:
174: public Object postProcessBeforeInitialization(Object bean,
175: String beanName) throws BeansException {
176: return bean;
177: }
178:
179: public Class<?> getType() {
180: return type;
181: }
182:
183: public void setType(Class<?> type) {
184: this .type = type;
185: }
186:
187: public String getIdsProperty() {
188: return idsProperty;
189: }
190:
191: public void setIdsProperty(String idsProperty) {
192: this .idsProperty = idsProperty;
193: }
194:
195: public void clear() {
196: throw new UnsupportedOperationException();
197: }
198:
199: public boolean containsKey(Object key) {
200: return idToBeanName.containsKey(key)
201: || putStore.containsKey(key);
202: }
203:
204: public boolean containsValue(Object arg0) {
205: throw new UnsupportedOperationException();
206: }
207:
208: public Set<java.util.Map.Entry<QName, V>> entrySet() {
209: Set<Map.Entry<QName, V>> entries = new HashSet<Map.Entry<QName, V>>();
210: for (QName k : keySet()) {
211: entries.add(new Entry<V>(this , k));
212: }
213: return entries;
214: }
215:
216: @SuppressWarnings("unchecked")
217: public V get(Object key) {
218: String name = idToBeanName.get(key);
219: if (name != null) {
220: return (V) (context.getBean(name));
221: } else {
222: return putStore.get(key);
223: }
224: }
225:
226: public boolean isEmpty() {
227: return idToBeanName.isEmpty() && putStore.isEmpty();
228: }
229:
230: public Set<QName> keySet() {
231: Set<QName> keys = new HashSet<QName>();
232: keys.addAll(idToBeanName.keySet());
233: keys.addAll(putStore.keySet());
234: return keys;
235: }
236:
237: public V put(QName key, V value) {
238: // Make sure we don't take the key from Spring any more
239: idToBeanName.remove(key);
240: return putStore.put(key, value);
241: }
242:
243: public void putAll(Map<? extends QName, ? extends V> m) {
244: putStore.putAll(m);
245: }
246:
247: public V remove(Object key) {
248: V v = get(key);
249: if (v != null) {
250: idToBeanName.remove(key);
251: } else {
252: v = putStore.get(key);
253: }
254:
255: return v;
256: }
257:
258: public int size() {
259: return idToBeanName.size() + putStore.size();
260: }
261:
262: public Collection<V> values() {
263: List<V> values = new ArrayList<V>();
264: values.addAll(putStore.values());
265: for (QName id : idToBeanName.keySet()) {
266: values.add(get(id));
267: }
268: return values;
269: }
270:
271: public static class Entry<V> implements Map.Entry<QName, V> {
272: private SpringBeanQNameMap<V> map;
273: private QName key;
274:
275: public Entry(SpringBeanQNameMap<V> map, QName key) {
276: this .map = map;
277: this .key = key;
278: }
279:
280: public QName getKey() {
281: return key;
282: }
283:
284: public V getValue() {
285: return map.get(key);
286: }
287:
288: public V setValue(V value) {
289: return map.put(key, value);
290: }
291: }
292: }
|