]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/Methods.java
Improved Bindings.getBinding(Class) caching for Datatype.class
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / Methods.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
4  *  All rights reserved. This program and the accompanying materials
5  *  are made available under the terms of the Eclipse Public License v1.0
6  *  which accompanies this distribution, and is available at
7  *  http://www.eclipse.org/legal/epl-v10.html
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard;
13
14 import java.lang.reflect.Method;
15 import java.util.HashMap;
16 import java.util.Map;
17
18 import org.simantics.databoard.binding.error.BindingConstructionException;
19 import org.simantics.databoard.binding.error.DatatypeConstructionException;
20 import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
21 import org.simantics.databoard.method.Interface;
22 import org.simantics.databoard.method.MethodInterface;
23 import org.simantics.databoard.method.MethodInterfaceUtil;
24 import org.simantics.databoard.method.MethodNotSupportedException;
25 import org.simantics.databoard.method.MethodReflectionBinding;
26 import org.simantics.databoard.method.MethodType;
27 import org.simantics.databoard.method.MethodTypeBinding;
28 import org.simantics.databoard.method.MethodTypeDefinition;
29
30 /**
31  * This is a facade class for method services.
32  *
33  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
34  */
35 public class Methods {
36         
37         public static Interface NULL_INTERFACE = new Interface();
38         
39         public static MethodReflectionBinding methodReflectionBinding = new MethodReflectionBinding();
40
41         public static MethodInterface adaptMethods(MethodInterface mi, final MethodTypeDefinition[] rangeMethods)
42         {
43                 return MethodInterfaceUtil.adaptMethods(mi, rangeMethods);
44         }
45         
46     /**
47      * Bind an interface type to an instance. The <code>obj</code> must have all the
48      * methods described in the interface type. 
49      * 
50      * @param interfaceType interface type
51      * @param obj instance
52      * @return interface binding
53      * @throws BindingConstructionException
54      */
55     public static MethodInterface bindInterface(Interface interfaceType, Object obj) throws BindingConstructionException
56     {
57         return MethodInterfaceUtil.bindInterface(interfaceType, obj);
58     }
59
60     /**
61      * Creates a InterfaceBinding implementation out of an object that 
62      * implements an interface. All the methods of the interface are 
63      * represented in the resulting InterfaceBinding. MethodTypeDefinitions are 
64      * generated automatically. <p>
65      * 
66      * There are restrictions to interface methods. Methods cannot have as
67      * argument, return type or as an exception anything {@link Datatypes#getDatatype(Class)}
68      * cannot create data type out of. In other perspective, all classes must 
69      * be composed of simple array, record, union, and primitive types.<p>    
70      * 
71      * @param interfaze interface to inspect methods from
72      * @param obj implementing object
73      * @return method interface implementation
74      * @throws BindingConstructionException 
75      */
76         public static <T> MethodInterface bindInterface(Class<T> interfaze, final T obj) throws BindingConstructionException
77     {
78         return MethodInterfaceUtil.bindInterface(interfaze, obj);
79     }
80     
81     /**
82      * Creates a proxy implementation that implements all methods of the 
83      * <code>interface</code>. The interface binding <code>ib</code> must implement
84      * all the methods. 
85      * 
86      * @param interfaze interface 
87      * @param ib interface binding
88      * @return an implementation to interfaze
89      * @throws BindingConstructionException on construction error
90      */
91         public static <T> T createProxy(Class<T> interfaze, MethodInterface ib)
92         throws BindingConstructionException
93         {
94                 return MethodInterfaceUtil.createProxy(interfaze, ib);
95         }    
96         
97         
98     /**
99      * Get method description
100      * 
101      * @param m
102      * @return method description
103      * @throws DatatypeConstructionException 
104      */
105     public static MethodTypeDefinition getMethodDescription(Method m) throws DatatypeConstructionException
106     {
107         return methodReflectionBinding.getMethodDescription(m);
108     }
109     
110     /**
111      * Get method description
112      * 
113      * @param m
114      * @return method type
115      * @throws DatatypeConstructionException 
116      */
117     public static MethodType getMethodType(Method m) throws DatatypeConstructionException
118     {
119         return methodReflectionBinding.getMethodType(m);
120     }
121     
122     /**
123      * Get method binding of a method. 
124      * Method arguments are wrapped into an Object[].
125      * Throwables in an UnionType. 
126      * 
127      * @param m
128      * @return method bindings
129      * @throws BindingConstructionException 
130      */
131     public static MethodTypeBinding getMethodTypeBinding(Method m) throws BindingConstructionException
132     {
133         return methodReflectionBinding.getMethodBinding(m);
134     }
135
136     /**
137      * Get method type bindings of all methods of an interface
138      *  
139      * @param interfaze
140      * @return and array of method type bindings
141      */
142     public static MethodTypeBinding[] getMethodTypeBindingsUnchecked(Class<?> interfaze)
143     {
144         try {
145                 return methodReflectionBinding.getInterfaceBinding(interfaze);
146         } catch (BindingConstructionException e) {
147                 throw new RuntimeBindingConstructionException(e);
148         }       
149     }
150     
151     /**
152      * Get method bindings for all methods of an interface
153      * 
154      * @param interfaze
155      * @return an array of methods type bindings
156      * @throws BindingConstructionException
157      */
158     public static MethodTypeBinding[] getMethodTypeBindings(Class<?> interfaze) throws BindingConstructionException
159     {
160         return methodReflectionBinding.getInterfaceBinding(interfaze);
161     }
162     
163     public static Interface getInterfaceType(Class<?> interfaze) throws BindingConstructionException
164     {
165         return methodReflectionBinding.getInterfaceType(interfaze);
166     }
167     
168     public static Interface getInterfaceTypeUnchecked(Class<?> interfaze) 
169     {
170         try {
171                 return methodReflectionBinding.getInterfaceType(interfaze);
172         } catch (BindingConstructionException e) {
173                 throw new RuntimeBindingConstructionException(e);
174         }
175     }    
176         
177     public static MethodInterface composeMethods(MethodInterface...interfaces)
178     throws IllegalArgumentException
179     {
180         return new MethodComposition(interfaces);
181     }
182     
183     public static MethodInterface noMethods()
184     {
185         return NullMethods.INSTANCE;
186     }       
187         
188
189 }
190
191 class MethodComposition implements MethodInterface {
192         
193         MethodInterface[] interfaces;
194         Map<MethodTypeDefinition, MethodInterface> map = new HashMap<MethodTypeDefinition, MethodInterface>();
195         Interface interfaceType;
196         
197         public MethodComposition(MethodInterface ... interfaces)
198         {
199                 this.interfaces = interfaces;
200                 for (MethodInterface mi : interfaces)
201                 {
202                         for (MethodTypeDefinition md : mi.getInterface().getMethodDefinitions())
203                         {
204                                 if (map.containsKey(md))
205                                         throw new IllegalArgumentException("Method ("+md+") cannot be shard over multiple MethodInterface");
206                                 map.put(md, mi);
207                         }
208                 }
209                 MethodTypeDefinition[] methods = map.values().toArray(new MethodTypeDefinition[0]);
210                 interfaceType = new Interface(methods);
211         }
212
213         @Override
214         public Method getMethod(MethodTypeDefinition description)
215                         throws MethodNotSupportedException {
216                 MethodInterface mi = map.get(description);
217                 if (mi==null) throw new MethodNotSupportedException(description.getName());
218                 return mi.getMethod(description);
219         }
220
221         @Override
222         public Method getMethod(MethodTypeBinding binding)
223                         throws MethodNotSupportedException {
224                 MethodInterface mi = map.get(binding.getMethodDefinition());
225                 if (mi==null) throw new MethodNotSupportedException(binding.getMethodDefinition().getName());
226                 return mi.getMethod(binding);
227         }
228
229         @Override
230         public Interface getInterface() {
231                 return interfaceType;
232         }
233         
234 }
235
236 /**
237  * MethodInterface implementation that contains no methods.
238  */
239 class NullMethods implements MethodInterface {
240
241         public static final MethodInterface INSTANCE = new NullMethods();
242         
243         Interface interfaceType = new Interface();;
244         
245         @Override
246         public Method getMethod(MethodTypeDefinition description)
247                         throws MethodNotSupportedException {
248                 throw new MethodNotSupportedException(description.getName());
249         }
250
251         @Override
252         public Method getMethod(MethodTypeBinding binding)
253                         throws MethodNotSupportedException {            
254                 throw new MethodNotSupportedException(binding.getMethodDefinition().getName());
255         }
256
257         @Override
258         public Interface getInterface() {
259                 return interfaceType;
260         }
261
262 }
263
264