View Javadoc

1   /*
2    * Copyright 2005, 2008 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package net.sf.morph.wrap.support;
17  
18  import java.lang.reflect.InvocationTargetException;
19  import java.lang.reflect.Method;
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import net.sf.composite.util.CompositeUtils;
27  import net.sf.composite.util.ObjectUtils;
28  import net.sf.morph.Defaults;
29  import net.sf.morph.reflect.BeanReflector;
30  import net.sf.morph.reflect.ContainerReflector;
31  import net.sf.morph.reflect.GrowableContainerReflector;
32  import net.sf.morph.reflect.IndexedContainerReflector;
33  import net.sf.morph.reflect.Reflector;
34  import net.sf.morph.reflect.SizableReflector;
35  import net.sf.morph.util.BidirectionalMap;
36  import net.sf.morph.wrap.Bean;
37  import net.sf.morph.wrap.Container;
38  import net.sf.morph.wrap.GrowableContainer;
39  import net.sf.morph.wrap.IndexedContainer;
40  import net.sf.morph.wrap.MutableIndexedContainer;
41  import net.sf.morph.wrap.Sizable;
42  
43  /**
44   * Default WrapperInvocationHandler implementation.
45   * @author Matt Sgarlata
46   * @since Jan 16, 2005
47   */
48  public class DefaultWrapperInvocationHandler implements WrapperInvocationHandler {
49  
50  	private static final Map DEFAULT_REFLECTOR_WRAPPER_MAP;
51  
52  	static {
53  		DEFAULT_REFLECTOR_WRAPPER_MAP = new BidirectionalMap(6);
54  		DEFAULT_REFLECTOR_WRAPPER_MAP.put(BeanReflector.class, Bean.class);
55  		DEFAULT_REFLECTOR_WRAPPER_MAP.put(ContainerReflector.class, Container.class);
56  		DEFAULT_REFLECTOR_WRAPPER_MAP.put(GrowableContainerReflector.class, GrowableContainer.class);
57  		DEFAULT_REFLECTOR_WRAPPER_MAP.put(IndexedContainerReflector.class, IndexedContainer.class);
58  		DEFAULT_REFLECTOR_WRAPPER_MAP.put(MutableIndexedContainer.class, MutableIndexedContainer.class);
59  		DEFAULT_REFLECTOR_WRAPPER_MAP.put(SizableReflector.class, Sizable.class);
60  	}
61  
62  	private Map reflectorWrapperMap;
63  	private Reflector reflector;
64  	private Object wrapped;
65  
66  	/**
67  	 * Create a new DefaultWrapperInvocationHandler.
68  	 * @param wrapped object
69  	 */
70  	public DefaultWrapperInvocationHandler(Object wrapped) {
71  		super();
72  		this.wrapped = wrapped;
73  	}
74  
75  	/**
76  	 * Create a new DefaultWrapperInvocationHandler.
77  	 * @param wrapped object
78  	 * @param reflector to use
79  	 */
80  	public DefaultWrapperInvocationHandler(Object wrapped, Reflector reflector) {
81  		this(wrapped);
82  		this.reflector = reflector;
83  	}
84  
85  	/**
86  	 * {@inheritDoc}
87  	 */
88  	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
89  
90  		try {
91  
92  			Class declaringClass = method.getDeclaringClass();
93  			if (declaringClass.equals(getWrapped().getClass())) {
94  				return method.invoke(getWrapped(), args);
95  			}
96  			Class wrapperClass = method.getDeclaringClass();
97  			Class reflectorClass = (Class) getBiDirectionalReflectorWrapperMap().getKey(wrapperClass);
98  			if (reflectorClass == null) {
99  				throw new IllegalArgumentException(
100 						"Cannot invoke method "
101 								+ method
102 								+ " because it is not declared in one of the recognized wrapper classes, which are: "
103 								+ ObjectUtils
104 										.getObjectDescription(getReflectorWrapperMap()
105 												.values()));
106 			}
107 
108 			Reflector reflector = (Reflector) CompositeUtils.specialize(getReflector(), reflectorClass);
109 
110 			int wrapperNumArgs = method.getParameterTypes().length;
111 			int reflectorNumArgs = wrapperNumArgs + 1;
112 
113 			Class[] reflectorParameterTypes = new Class[reflectorNumArgs];
114 			reflectorParameterTypes[0] = Object.class;
115 			if (method.getParameterTypes() != null) {
116 				System.arraycopy(method.getParameterTypes(), 0,
117 					reflectorParameterTypes, 1, wrapperNumArgs);
118 			}
119 
120 			Object[] reflectorArgs = new Object[reflectorNumArgs];
121 			reflectorArgs[0] = getWrapped();
122 			if (args != null) {
123 				System.arraycopy(args, 0, reflectorArgs, 1, wrapperNumArgs);
124 			}
125 
126 			Method reflectorMethod = reflector.getClass().getMethod(method.getName(), reflectorParameterTypes);
127 
128 			return reflectorMethod.invoke(reflector, reflectorArgs);
129 		}
130 		// if an exception is thrown by the invoke method, just rethrow it
131 		// without it wrapped in an InvocationTargetException
132 		catch (InvocationTargetException e) {
133 			throw e.getTargetException();
134 		}
135 
136 	}
137 
138 	/**
139 	 * {@inheritDoc}
140 	 */
141 	public Class[] getInterfaces(Object object) {
142 		Class[] baseInterfaces = object.getClass().getInterfaces();
143 		List interfaces;
144 		if (baseInterfaces == null) {
145 			interfaces = new ArrayList();
146 		}
147 		else {
148 			// wrap the list in an ArrayList so that new elements can be added
149 			interfaces = new ArrayList(Arrays.asList(baseInterfaces));
150 		}
151 		Map reflectorWrapperMap = getReflectorWrapperMap();
152 		Iterator reflectorClasses =  reflectorWrapperMap.keySet().iterator();
153 		while (reflectorClasses.hasNext()) {
154 			Class reflectorClass = (Class) reflectorClasses.next();
155 			Class wrapperClass = (Class) reflectorWrapperMap.get(reflectorClass);
156 			if (CompositeUtils.isSpecializable(getReflector(), reflectorClass)) {
157 				interfaces.add(wrapperClass);
158 			}
159 		}
160 		return (Class[]) interfaces.toArray(new Class[interfaces.size()]);
161 	}
162 
163 	/**
164 	 * Get the bidirectional reflector map.
165 	 * @return BidirectionalMap
166 	 */
167 	protected BidirectionalMap getBiDirectionalReflectorWrapperMap() {
168 		return (BidirectionalMap) getReflectorWrapperMap();
169 	}
170 
171 	/**
172 	 * Get the reflectorWrapperMap.
173 	 * @return Map
174 	 */
175 	public Map getReflectorWrapperMap() {
176 		if (reflectorWrapperMap == null) {
177 			setReflectorWrapperMap(DEFAULT_REFLECTOR_WRAPPER_MAP);
178 		}
179 		return reflectorWrapperMap;
180 	}
181 
182 	/**
183 	 * Set the reflectorWrapperMap.
184 	 * @param reflectorWrapperMap to set
185 	 */
186 	public void setReflectorWrapperMap(Map reflectorWrapperMap) {
187 		this.reflectorWrapperMap = BidirectionalMap.getInstance(reflectorWrapperMap);
188 	}
189 
190 	/**
191 	 * Get the reflector.
192 	 * @return Reflector
193 	 */
194 	public synchronized Reflector getReflector() {
195 		if (reflector == null) {
196 			setReflector(Defaults.createReflector());
197 		}
198 		return reflector;
199 	}
200 
201 	/**
202 	 * Set the reflector.
203 	 * @param reflector to set
204 	 */
205 	public synchronized void setReflector(Reflector reflector) {
206 		this.reflector = reflector;
207 	}
208 
209 	/**
210 	 * Get the wrapped object.
211 	 * @return Object
212 	 */
213 	public Object getWrapped() {
214 		return wrapped;
215 	}
216 
217 	/**
218 	 * Set the wrapped object.
219 	 * @param wrapped object to set
220 	 */
221 	public void setWrapped(Object wrapped) {
222 		this.wrapped = wrapped;
223 	}
224 }