blob: a9a2fdbd0b6889a1f8675d9d266a35b4c5926fd7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tuscany.sca.implementation.osgi.runtime;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import org.apache.tuscany.sca.interfacedef.DataType;
import org.apache.tuscany.sca.interfacedef.Interface;
import org.apache.tuscany.sca.interfacedef.Operation;
import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
import org.apache.tuscany.sca.invocation.Invoker;
import org.apache.tuscany.sca.invocation.Message;
import org.apache.tuscany.sca.runtime.RuntimeComponent;
import org.apache.tuscany.sca.runtime.RuntimeComponentService;
import org.osgi.framework.Constants;
/**
* The Invoker looks up the corresponding OSGi service from the OSGi service registry
* and delegate the call to it.
*
* @version $Rev$ $Date$
*/
public class OSGiTargetInvoker implements Invoker {
private Operation operation;
private final OSGiImplementationProvider provider;
private final RuntimeComponent component;
private final RuntimeComponentService service;
public OSGiTargetInvoker(Operation operation, OSGiImplementationProvider provider, RuntimeComponentService service) {
this.operation = operation;
this.service = service;
this.provider = provider;
this.component = provider.getComponent();
}
private Object invokeTarget(Message msg) throws InvocationTargetException {
Operation op = msg.getOperation();
if (op == null) {
op = this.operation;
}
try {
Object instance = provider.getOSGiService(service);
Method m = findMethod(instance.getClass(), operation);
Object ret = invokeMethod(instance, m, msg);
return ret;
} catch (InvocationTargetException e) {
throw e;
} catch (Exception e) {
throw new InvocationTargetException(e);
}
}
protected Object invokeMethod(Object instance, Method m, Message msg) throws InvocationTargetException {
try {
Object payload = msg.getBody();
if (payload != null && !payload.getClass().isArray()) {
return m.invoke(instance, payload);
} else {
return m.invoke(instance, (Object[])payload);
}
} catch (InvocationTargetException e) {
throw e;
} catch (Exception e) {
throw new InvocationTargetException(e);
}
}
public Message invoke(Message msg) {
try {
Object resp = invokeTarget(msg);
msg.setBody(resp);
} catch (InvocationTargetException e) {
msg.setFaultBody(e.getCause());
}
return msg;
}
private String getOSGiFilter(Hashtable<String, Object> props) {
Object serviceID = props.get(Constants.SERVICE_ID);
if (serviceID != null) {
return "(" + Constants.SERVICE_ID + "=" + serviceID + ")";
}
String filter = "";
if (props != null && props.size() > 0) {
int propCount = 0;
for (String propName : props.keySet()) {
String value = String.valueOf(props.get(propName));
StringBuffer buf = new StringBuffer();
for (char c : value.toCharArray()) {
if (c == '(' || c == ')') {
buf.append("\\" + c);
} else {
buf.append(c);
}
}
filter = filter + "(" + propName + "=" + buf.toString() + ")";
propCount++;
}
if (propCount > 1) {
filter = "(&" + filter + ")";
}
} else {
filter = null;
}
return filter;
}
/**
* @Deprecated
*/
private static Class<?>[] getPhysicalTypes(Operation operation) {
DataType<List<DataType>> inputType = operation.getInputType();
if (inputType == null) {
return new Class<?>[] {};
}
List<DataType> types = inputType.getLogical();
Class<?>[] javaTypes = new Class<?>[types.size()];
for (int i = 0; i < javaTypes.length; i++) {
Type physical = types.get(i).getPhysical();
if (physical instanceof Class<?>) {
javaTypes[i] = (Class<?>)physical;
} else {
throw new UnsupportedOperationException();
}
}
return javaTypes;
}
/**
* Return the method on the implementation class that matches the operation.
*
* @param implClass the implementation class or interface
* @param operation the operation to match
* @return the method described by the operation
* @throws NoSuchMethodException if no such method exists
* @Deprecated
*/
public static Method findMethod(Class<?> implClass, Operation operation) throws NoSuchMethodException {
String name = operation.getName();
if (operation instanceof JavaOperation) {
name = ((JavaOperation)operation).getJavaMethod().getName();
}
Interface interface1 = operation.getInterface();
int numParams = operation.getInputType().getLogical().size();
if (interface1 != null && interface1.isRemotable()) {
List<Method> matchingMethods = new ArrayList<Method>();
for (Method m : implClass.getMethods()) {
if (m.getName().equals(name) && m.getParameterTypes().length == numParams) {
matchingMethods.add(m);
}
}
// TUSCANY-2180 If there is only one method then we just match on the name
// (this is the same as the existing behaviour)
if (matchingMethods.size() == 1) {
return matchingMethods.get(0);
}
if (matchingMethods.size() > 1) {
// TUSCANY-2180 We need to check the parameter types too
Class<?>[] paramTypes = getPhysicalTypes(operation);
return implClass.getMethod(name, paramTypes);
}
// No matching method found
throw new NoSuchMethodException("No matching method for operation " + operation.getName()
+ " is found on "
+ implClass);
}
Class<?>[] paramTypes = getPhysicalTypes(operation);
return implClass.getMethod(name, paramTypes);
}
}