001: /*
002: * Copyright 2002-2007 the original author or authors.
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:
017: package org.springframework.dao.support;
018:
019: import java.util.Iterator;
020: import java.util.Map;
021:
022: import org.aopalliance.intercept.MethodInterceptor;
023: import org.aopalliance.intercept.MethodInvocation;
024:
025: import org.springframework.beans.BeansException;
026: import org.springframework.beans.factory.BeanFactory;
027: import org.springframework.beans.factory.BeanFactoryAware;
028: import org.springframework.beans.factory.BeanFactoryUtils;
029: import org.springframework.beans.factory.InitializingBean;
030: import org.springframework.beans.factory.ListableBeanFactory;
031: import org.springframework.util.Assert;
032: import org.springframework.util.ReflectionUtils;
033:
034: /**
035: * AOP Alliance MethodInterceptor that provides persistence exception translation
036: * based on a given PersistenceExceptionTranslator.
037: *
038: * <p>Delegates to the given {@link PersistenceExceptionTranslator} to translate
039: * a RuntimeException thrown into Spring's DataAccessException hierarchy
040: * (if appropriate). If the RuntimeException in question is declared on the
041: * target method, it is always propagated as-is (with no translation applied).
042: *
043: * @author Rod Johnson
044: * @author Juergen Hoeller
045: * @since 2.0
046: * @see PersistenceExceptionTranslator
047: */
048: public class PersistenceExceptionTranslationInterceptor implements
049: MethodInterceptor, BeanFactoryAware, InitializingBean {
050:
051: private PersistenceExceptionTranslator persistenceExceptionTranslator;
052:
053: /**
054: * Create a new PersistenceExceptionTranslationInterceptor.
055: * Needs to be configured with a PersistenceExceptionTranslator afterwards.
056: * @see #setPersistenceExceptionTranslator
057: */
058: public PersistenceExceptionTranslationInterceptor() {
059: }
060:
061: /**
062: * Create a new PersistenceExceptionTranslationInterceptor
063: * for the given PersistenceExceptionTranslator.
064: * @param persistenceExceptionTranslator the PersistenceExceptionTranslator to use
065: */
066: public PersistenceExceptionTranslationInterceptor(
067: PersistenceExceptionTranslator persistenceExceptionTranslator) {
068: setPersistenceExceptionTranslator(persistenceExceptionTranslator);
069: }
070:
071: /**
072: * Create a new PersistenceExceptionTranslationInterceptor, autodetecting
073: * PersistenceExceptionTranslators in the given BeanFactory.
074: * @param beanFactory the ListableBeanFactory to obtaining all
075: * PersistenceExceptionTranslators from
076: */
077: public PersistenceExceptionTranslationInterceptor(
078: ListableBeanFactory beanFactory) {
079: this .persistenceExceptionTranslator = detectPersistenceExceptionTranslators(beanFactory);
080: }
081:
082: /**
083: * Specify the PersistenceExceptionTranslator to use.
084: * <p>Default is to autodetect all PersistenceExceptionTranslators
085: * in the containing BeanFactory, using them in a chain.
086: * @see #detectPersistenceExceptionTranslators
087: */
088: public void setPersistenceExceptionTranslator(
089: PersistenceExceptionTranslator pet) {
090: Assert.notNull(pet,
091: "PersistenceExceptionTranslator must not be null");
092: this .persistenceExceptionTranslator = pet;
093: }
094:
095: public void setBeanFactory(BeanFactory beanFactory)
096: throws BeansException {
097: if (this .persistenceExceptionTranslator == null) {
098: // No explicit exception translator specified - perform autodetection.
099: if (!(beanFactory instanceof ListableBeanFactory)) {
100: throw new IllegalArgumentException(
101: "Cannot use PersistenceExceptionTranslator autodetection without ListableBeanFactory");
102: }
103: this .persistenceExceptionTranslator = detectPersistenceExceptionTranslators((ListableBeanFactory) beanFactory);
104: }
105: }
106:
107: public void afterPropertiesSet() {
108: if (this .persistenceExceptionTranslator == null) {
109: throw new IllegalArgumentException(
110: "Property 'persistenceExceptionTranslator' is required");
111: }
112: }
113:
114: /**
115: * Detect all PersistenceExceptionTranslators in the given BeanFactory.
116: * @param beanFactory the ListableBeanFactory to obtaining all
117: * PersistenceExceptionTranslators from
118: * @return a chained PersistenceExceptionTranslator, combining all
119: * PersistenceExceptionTranslators found in the factory
120: * @see ChainedPersistenceExceptionTranslator
121: */
122: protected PersistenceExceptionTranslator detectPersistenceExceptionTranslators(
123: ListableBeanFactory beanFactory) {
124: // Find all translators, being careful not to activate FactoryBeans.
125: Map pets = BeanFactoryUtils.beansOfTypeIncludingAncestors(
126: beanFactory, PersistenceExceptionTranslator.class,
127: false, false);
128: if (pets.isEmpty()) {
129: throw new IllegalStateException(
130: "No persistence exception translators found in bean factory. Cannot perform exception translation.");
131: }
132: ChainedPersistenceExceptionTranslator cpet = new ChainedPersistenceExceptionTranslator();
133: for (Iterator it = pets.values().iterator(); it.hasNext();) {
134: cpet
135: .addDelegate((PersistenceExceptionTranslator) it
136: .next());
137: }
138: return cpet;
139: }
140:
141: public Object invoke(MethodInvocation mi) throws Throwable {
142: try {
143: return mi.proceed();
144: } catch (RuntimeException ex) {
145: // Let it throw raw if the type of the exception is on the throws clause of the method.
146: if (ReflectionUtils.declaresException(mi.getMethod(), ex
147: .getClass())) {
148: throw ex;
149: } else {
150: throw DataAccessUtils.translateIfNecessary(ex,
151: this.persistenceExceptionTranslator);
152: }
153: }
154: }
155:
156: }
|