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.aop.support;
018:
019: import java.io.IOException;
020: import java.io.ObjectInputStream;
021: import java.io.Serializable;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.Map;
025: import java.util.Set;
026:
027: import org.aopalliance.intercept.MethodInvocation;
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import org.springframework.aop.IntroductionInfo;
032: import org.springframework.core.CollectionFactory;
033: import org.springframework.util.ClassUtils;
034:
035: /**
036: * Support for implementations of {@link org.springframework.aop.IntroductionInfo}.
037: *
038: * <p>Allows subclasses to conveniently add all interfaces from a given object,
039: * and to suppress interfaces that should not be added. Also allows for querying
040: * all introduced interfaces.
041: *
042: * @author Rod Johnson
043: * @author Juergen Hoeller
044: */
045: public class IntroductionInfoSupport implements IntroductionInfo,
046: Serializable {
047:
048: protected transient Log logger = LogFactory.getLog(getClass());
049:
050: /** Set of interface Classes */
051: protected Set publishedInterfaces = new HashSet();
052:
053: /**
054: * Methods that we know we should implement here: key is Method, value is Boolean.
055: **/
056: private transient Map rememberedMethods = createRememberedMethodMap();
057:
058: /**
059: * Suppress the specified interface, which may have been autodetected
060: * due to the delegate implementing it. Call this method to exclude
061: * internal interfaces from being visible at the proxy level.
062: * <p>Does nothing if the interface is not implemented by the delegate.
063: * @param intf the interface to suppress
064: */
065: public void suppressInterface(Class intf) {
066: this .publishedInterfaces.remove(intf);
067: }
068:
069: public Class[] getInterfaces() {
070: return (Class[]) this .publishedInterfaces
071: .toArray(new Class[this .publishedInterfaces.size()]);
072: }
073:
074: /**
075: * Check whether the specified interfaces is a published introduction interface.
076: * @param intf the interface to check
077: * @return whether the interface is part of this introduction
078: */
079: public boolean implements Interface(Class intf) {
080: for (Iterator it = this .publishedInterfaces.iterator(); it
081: .hasNext();) {
082: Class pubIntf = (Class) it.next();
083: if (intf.isInterface() && intf.isAssignableFrom(pubIntf)) {
084: return true;
085: }
086: }
087: return false;
088: }
089:
090: /**
091: * Publish all interfaces that the given delegate implements at the proxy level.
092: * @param delegate the delegate object
093: */
094: protected void implementInterfacesOnObject(Object delegate) {
095: this .publishedInterfaces.addAll(ClassUtils
096: .getAllInterfacesAsSet(delegate));
097: }
098:
099: private Map createRememberedMethodMap() {
100: return CollectionFactory.createIdentityMapIfPossible(32);
101: }
102:
103: /**
104: * Is this method on an introduced interface?
105: * @param mi the method invocation
106: * @return whether the invoked method is on an introduced interface
107: */
108: protected final boolean isMethodOnIntroducedInterface(
109: MethodInvocation mi) {
110: Boolean rememberedResult = (Boolean) this .rememberedMethods
111: .get(mi.getMethod());
112: if (rememberedResult != null) {
113: return rememberedResult.booleanValue();
114: } else {
115: // Work it out and cache it.
116: boolean result = implements Interface(mi.getMethod()
117: .getDeclaringClass());
118: this .rememberedMethods.put(mi.getMethod(),
119: (result ? Boolean.TRUE : Boolean.FALSE));
120: return result;
121: }
122: }
123:
124: //---------------------------------------------------------------------
125: // Serialization support
126: //---------------------------------------------------------------------
127:
128: /**
129: * This method is implemented only to restore the logger.
130: * We don't make the logger static as that would mean that subclasses
131: * would use this class's log category.
132: */
133: private void readObject(ObjectInputStream ois) throws IOException,
134: ClassNotFoundException {
135: // Rely on default serialization; just initialize state after deserialization.
136: ois.defaultReadObject();
137:
138: // Initialize transient fields.
139: this.logger = LogFactory.getLog(getClass());
140: this.rememberedMethods = createRememberedMethodMap();
141: }
142:
143: }
|