/******************************************************************************* * Copyright (c) 2010 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.error.DatatypeConstructionException; import org.simantics.databoard.binding.error.RuntimeBindingConstructionException; import org.simantics.databoard.method.Interface; import org.simantics.databoard.method.MethodInterface; import org.simantics.databoard.method.MethodInterfaceUtil; import org.simantics.databoard.method.MethodNotSupportedException; import org.simantics.databoard.method.MethodReflectionBinding; import org.simantics.databoard.method.MethodType; import org.simantics.databoard.method.MethodTypeBinding; import org.simantics.databoard.method.MethodTypeDefinition; /** * This is a facade class for method services. * * @author Toni Kalajainen */ public class Methods { public static Interface NULL_INTERFACE = new Interface(); public static MethodReflectionBinding methodReflectionBinding = new MethodReflectionBinding(); public static MethodInterface adaptMethods(MethodInterface mi, final MethodTypeDefinition[] rangeMethods) { return MethodInterfaceUtil.adaptMethods(mi, rangeMethods); } /** * Bind an interface type to an instance. The obj must have all the * methods described in the interface type. * * @param interfaceType interface type * @param obj instance * @return interface binding * @throws BindingConstructionException */ public static MethodInterface bindInterface(Interface interfaceType, Object obj) throws BindingConstructionException { return MethodInterfaceUtil.bindInterface(interfaceType, obj); } /** * Creates a InterfaceBinding implementation out of an object that * implements an interface. All the methods of the interface are * represented in the resulting InterfaceBinding. MethodTypeDefinitions are * generated automatically.

* * There are restrictions to interface methods. Methods cannot have as * argument, return type or as an exception anything {@link Datatypes#getDatatype(Class)} * cannot create data type out of. In other perspective, all classes must * be composed of simple array, record, union, and primitive types.

* * @param interfaze interface to inspect methods from * @param obj implementing object * @return method interface implementation * @throws BindingConstructionException */ public static MethodInterface bindInterface(Class interfaze, final T obj) throws BindingConstructionException { return MethodInterfaceUtil.bindInterface(interfaze, obj); } /** * Creates a proxy implementation that implements all methods of the * interface. The interface binding ib must implement * all the methods. * * @param interfaze interface * @param ib interface binding * @return an implementation to interfaze * @throws BindingConstructionException on construction error */ public static T createProxy(Class interfaze, MethodInterface ib) throws BindingConstructionException { return MethodInterfaceUtil.createProxy(interfaze, ib); } /** * Get method description * * @param m * @return method description * @throws DatatypeConstructionException */ public static MethodTypeDefinition getMethodDescription(Method m) throws DatatypeConstructionException { return methodReflectionBinding.getMethodDescription(m); } /** * Get method description * * @param m * @return method type * @throws DatatypeConstructionException */ public static MethodType getMethodType(Method m) throws DatatypeConstructionException { return methodReflectionBinding.getMethodType(m); } /** * Get method binding of a method. * Method arguments are wrapped into an Object[]. * Throwables in an UnionType. * * @param m * @return method bindings * @throws BindingConstructionException */ public static MethodTypeBinding getMethodTypeBinding(Method m) throws BindingConstructionException { return methodReflectionBinding.getMethodBinding(m); } /** * Get method type bindings of all methods of an interface * * @param interfaze * @return and array of method type bindings */ public static MethodTypeBinding[] getMethodTypeBindingsUnchecked(Class interfaze) { try { return methodReflectionBinding.getInterfaceBinding(interfaze); } catch (BindingConstructionException e) { throw new RuntimeBindingConstructionException(e); } } /** * Get method bindings for all methods of an interface * * @param interfaze * @return an array of methods type bindings * @throws BindingConstructionException */ public static MethodTypeBinding[] getMethodTypeBindings(Class interfaze) throws BindingConstructionException { return methodReflectionBinding.getInterfaceBinding(interfaze); } public static Interface getInterfaceType(Class interfaze) throws BindingConstructionException { return methodReflectionBinding.getInterfaceType(interfaze); } public static Interface getInterfaceTypeUnchecked(Class interfaze) { try { return methodReflectionBinding.getInterfaceType(interfaze); } catch (BindingConstructionException e) { throw new RuntimeBindingConstructionException(e); } } public static MethodInterface composeMethods(MethodInterface...interfaces) throws IllegalArgumentException { return new MethodComposition(interfaces); } public static MethodInterface noMethods() { return NullMethods.INSTANCE; } } class MethodComposition implements MethodInterface { MethodInterface[] interfaces; Map map = new HashMap(); Interface interfaceType; public MethodComposition(MethodInterface ... interfaces) { this.interfaces = interfaces; for (MethodInterface mi : interfaces) { for (MethodTypeDefinition md : mi.getInterface().getMethodDefinitions()) { if (map.containsKey(md)) throw new IllegalArgumentException("Method ("+md+") cannot be shard over multiple MethodInterface"); map.put(md, mi); } } MethodTypeDefinition[] methods = map.values().toArray(new MethodTypeDefinition[0]); interfaceType = new Interface(methods); } @Override public Method getMethod(MethodTypeDefinition description) throws MethodNotSupportedException { MethodInterface mi = map.get(description); if (mi==null) throw new MethodNotSupportedException(description.getName()); return mi.getMethod(description); } @Override public Method getMethod(MethodTypeBinding binding) throws MethodNotSupportedException { MethodInterface mi = map.get(binding.getMethodDefinition()); if (mi==null) throw new MethodNotSupportedException(binding.getMethodDefinition().getName()); return mi.getMethod(binding); } @Override public Interface getInterface() { return interfaceType; } } /** * MethodInterface implementation that contains no methods. */ class NullMethods implements MethodInterface { public static final MethodInterface INSTANCE = new NullMethods(); Interface interfaceType = new Interface();; @Override public Method getMethod(MethodTypeDefinition description) throws MethodNotSupportedException { throw new MethodNotSupportedException(description.getName()); } @Override public Method getMethod(MethodTypeBinding binding) throws MethodNotSupportedException { throw new MethodNotSupportedException(binding.getMethodDefinition().getName()); } @Override public Interface getInterface() { return interfaceType; } }