+/*******************************************************************************\r
+ * Copyright (c) 2010 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard;
+
+import java.lang.reflect.Method;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.simantics.databoard.binding.error.BindingConstructionException;\r
+import org.simantics.databoard.binding.error.DatatypeConstructionException;\r
+import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
+import org.simantics.databoard.method.Interface;\r
+import org.simantics.databoard.method.MethodInterface;\r
+import org.simantics.databoard.method.MethodInterfaceUtil;\r
+import org.simantics.databoard.method.MethodNotSupportedException;\r
+import org.simantics.databoard.method.MethodReflectionBinding;\r
+import org.simantics.databoard.method.MethodType;\r
+import org.simantics.databoard.method.MethodTypeBinding;\r
+import org.simantics.databoard.method.MethodTypeDefinition;\r
+
+/**
+ * This is a facade class for method services.
+ *
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+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 <code>obj</code> 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. <p>
+ *
+ * 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.<p>
+ *
+ * @param interfaze interface to inspect methods from
+ * @param obj implementing object
+ * @return method interface implementation
+ * @throws BindingConstructionException
+ */
+ public static <T> MethodInterface bindInterface(Class<T> interfaze, final T obj) throws BindingConstructionException
+ {
+ return MethodInterfaceUtil.bindInterface(interfaze, obj);
+ }
+
+ /**
+ * Creates a proxy implementation that implements all methods of the
+ * <code>interface</code>. The interface binding <code>ib</code> 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> T createProxy(Class<T> 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<MethodTypeDefinition, MethodInterface> map = new HashMap<MethodTypeDefinition, MethodInterface>();
+ 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;
+ }
+
+}
+
+