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.service.invoker;
019:
020: import java.lang.reflect.InvocationTargetException;
021: import java.lang.reflect.Method;
022: import java.lang.reflect.Proxy;
023: import java.util.List;
024:
025: import org.apache.cxf.frontend.MethodDispatcher;
026: import org.apache.cxf.helpers.CastUtils;
027: import org.apache.cxf.interceptor.Fault;
028: import org.apache.cxf.message.Exchange;
029: import org.apache.cxf.message.FaultMode;
030: import org.apache.cxf.message.MessageContentsList;
031: import org.apache.cxf.service.Service;
032: import org.apache.cxf.service.model.BindingOperationInfo;
033:
034: /**
035: * Abstract implementation of Invoker.
036: * <p>
037: *
038: * @author Ben Yu Feb 10, 2006 10:57:23 PM
039: */
040: public abstract class AbstractInvoker implements Invoker {
041:
042: public Object invoke(Exchange exchange, Object o) {
043:
044: final Object serviceObject = getServiceObject(exchange);
045:
046: BindingOperationInfo bop = exchange
047: .get(BindingOperationInfo.class);
048: MethodDispatcher md = (MethodDispatcher) exchange.get(
049: Service.class).get(MethodDispatcher.class.getName());
050: Method m = md.getMethod(bop);
051: //Method m = (Method)bop.getOperationInfo().getProperty(Method.class.getName());
052: m = matchMethod(m, serviceObject);
053:
054: List<Object> params = null;
055: if (o instanceof List) {
056: params = CastUtils.cast((List<?>) o);
057: } else if (o != null) {
058: params = new MessageContentsList(o);
059: }
060:
061: return invoke(exchange, serviceObject, m, params);
062: }
063:
064: protected Object invoke(Exchange exchange,
065: final Object serviceObject, Method m, List<Object> params) {
066: Object res;
067: try {
068: Object[] paramArray = new Object[] {};
069: if (params != null) {
070: paramArray = params.toArray();
071: }
072:
073: res = performInvocation(exchange, serviceObject, m,
074: paramArray);
075:
076: if (exchange.isOneWay()) {
077: return null;
078: }
079:
080: return new MessageContentsList(res);
081: } catch (InvocationTargetException e) {
082: Throwable t = e.getCause();
083: if (t == null) {
084: t = e;
085: }
086: exchange.getInMessage().put(FaultMode.class,
087: FaultMode.CHECKED_APPLICATION_FAULT);
088: throw new Fault(t);
089: } catch (Fault f) {
090: exchange.getInMessage().put(FaultMode.class,
091: FaultMode.UNCHECKED_APPLICATION_FAULT);
092: throw f;
093: } catch (Exception e) {
094: exchange.getInMessage().put(FaultMode.class,
095: FaultMode.UNCHECKED_APPLICATION_FAULT);
096: throw new Fault(e);
097: }
098: }
099:
100: protected Object performInvocation(Exchange exchange,
101: final Object serviceObject, Method m, Object[] paramArray)
102: throws Exception {
103: paramArray = insertExchange(m, paramArray, exchange);
104: return m.invoke(serviceObject, paramArray);
105: }
106:
107: public Object[] insertExchange(Method method, Object[] params,
108: Exchange context) {
109: Object[] newParams = params;
110: for (int i = 0; i < method.getParameterTypes().length; i++) {
111: if (method.getParameterTypes()[i].equals(Exchange.class)) {
112: newParams = new Object[params.length + 1];
113:
114: for (int j = 0; j < newParams.length; j++) {
115: if (j == i) {
116: newParams[j] = context;
117: } else if (j > i) {
118: newParams[j] = params[j - 1];
119: } else {
120: newParams[j] = params[j];
121: }
122: }
123: }
124: }
125: return newParams;
126: }
127:
128: /**
129: * Creates and returns a service object depending on the scope.
130: */
131: public abstract Object getServiceObject(final Exchange context);
132:
133: /**
134: * Returns a Method that has the same declaring class as the class of
135: * targetObject to avoid the IllegalArgumentException when invoking the
136: * method on the target object. The methodToMatch will be returned if the
137: * targetObject doesn't have a similar method.
138: *
139: * @param methodToMatch The method to be used when finding a matching method
140: * in targetObject
141: * @param targetObject The object to search in for the method.
142: * @return The methodToMatch if no such method exist in the class of
143: * targetObject; otherwise, a method from the class of targetObject
144: * matching the matchToMethod method.
145: */
146: private static Method matchMethod(Method methodToMatch,
147: Object targetObject) {
148: if (isJdkDynamicProxy(targetObject)) {
149: Class[] interfaces = targetObject.getClass()
150: .getInterfaces();
151: for (int i = 0; i < interfaces.length; i++) {
152: Method m = getMostSpecificMethod(methodToMatch,
153: interfaces[i]);
154: if (!methodToMatch.equals(m)) {
155: return m;
156: }
157: }
158: }
159: return methodToMatch;
160: }
161:
162: /**
163: * Return whether the given object is a J2SE dynamic proxy.
164: *
165: * @param object the object to check
166: * @see java.lang.reflect.Proxy#isProxyClass
167: */
168: public static boolean isJdkDynamicProxy(Object object) {
169: return object != null && Proxy.isProxyClass(object.getClass());
170: }
171:
172: /**
173: * Given a method, which may come from an interface, and a targetClass used
174: * in the current AOP invocation, find the most specific method if there is
175: * one. E.g. the method may be IFoo.bar() and the target class may be
176: * DefaultFoo. In this case, the method may be DefaultFoo.bar(). This
177: * enables attributes on that method to be found.
178: *
179: * @param method method to be invoked, which may come from an interface
180: * @param targetClass target class for the curren invocation. May be
181: * <code>null</code> or may not even implement the method.
182: * @return the more specific method, or the original method if the
183: * targetClass doesn't specialize it or implement it or is null
184: */
185: public static Method getMostSpecificMethod(Method method,
186: Class<?> targetClass) {
187: if (method != null && targetClass != null) {
188: try {
189: method = targetClass.getMethod(method.getName(), method
190: .getParameterTypes());
191: } catch (NoSuchMethodException ex) {
192: // Perhaps the target class doesn't implement this method:
193: // that's fine, just use the original method
194: }
195: }
196: return method;
197: }
198: }
|