/******************************************************************************* * 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.method; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.HashMap; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.RecordBinding; import org.simantics.databoard.binding.UnionBinding; import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.error.DatatypeConstructionException; import org.simantics.databoard.binding.impl.OptionalBindingDefault; import org.simantics.databoard.type.Component; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.type.OptionalType; import org.simantics.databoard.type.RecordType; import org.simantics.databoard.type.UnionType; public class MethodReflectionBinding { private HashMap methodDescriptionCache = new HashMap(); private HashMap methodBindingCache = new HashMap(); private HashMap, MethodTypeBinding[]> interfaceBindingCache = new HashMap, MethodTypeBinding[]>(); private HashMap, Interface> interfaceTypeCache = new HashMap, Interface>(); /** * 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 synchronized MethodTypeBinding getMethodBinding(Method m) throws BindingConstructionException { MethodTypeBinding mb = methodBindingCache.get(m); if (mb==null) { mb = createMethodBinding(m); methodBindingCache.put(m, mb); } return mb; } private MethodTypeBinding createMethodBinding(Method m) throws BindingConstructionException { try { MethodTypeDefinition md = getMethodDescription(m); Class returnClass = m.getReturnType(); Class[] paramClasses = m.getParameterTypes(); Class[] errorClasses = m.getExceptionTypes(); return createMethodBinding(md, paramClasses, returnClass, errorClasses); } catch (DatatypeConstructionException e) { throw new BindingConstructionException(e); } } private MethodTypeBinding createMethodBinding(MethodTypeDefinition md, Class[] paramClasses, Class returnClass, Class[] errorClasses) throws BindingConstructionException { RecordBinding requestBinding; Binding responseBinding; UnionBinding errorBinding; responseBinding = Bindings.getBinding(returnClass); // Wrap arguments into Object[] // if (paramClasses.length==0) requestBinding = getBinding(void.class); // else { ObjectArrayRecordBinding rb = new ObjectArrayRecordBinding(); Binding[] cbs = new Binding[paramClasses.length]; rb.setType( md.getType().getRequestType() ); for (int i=0; i paramClass = paramClasses[i]; Binding binding = Bindings.getBinding(paramClass); // All arguments are optional binding = new OptionalBindingDefault( binding ); cbs[i] = binding; } rb.setComponentBindings(cbs); requestBinding = rb; } // if (errorClasses.length==0) errorBinding = getBinding(void.class); // else { Datatype type = md.getType().getErrorType(); ObjectUnionBinding ub = new ObjectUnionBinding(type, errorClasses); Binding cbs[] = new Binding[errorClasses.length]; for (int i=0; i returnClass = m.getReturnType(); Class[] paramClasses = m.getParameterTypes(); Class[] errorClasses = m.getExceptionTypes(); RecordType requestType; Datatype responseType; UnionType errorType; responseType = Datatypes.getDatatype(returnClass); // if (paramClasses.length==0) requestType = getDataType(void.class); // else if (paramClasses.length==1) requestType = getDataType(paramClasses[0]); // else { RecordType rt = new RecordType(); Component[] components = new Component[paramClasses.length]; rt.setReferable( false ); for (int i=0; i interfaze) throws BindingConstructionException { MethodTypeBinding[] result = interfaceBindingCache.get( interfaze ); if (result==null) { result = createInterfaceBinding(interfaze); interfaceBindingCache.put(interfaze, result); } return result; } private MethodTypeBinding[] createInterfaceBinding(Class interfaze) throws BindingConstructionException { Method methods[] = interfaze.getMethods(); MethodTypeBinding result[] = new MethodTypeBinding[methods.length]; for (int i=0; i interfaze) throws BindingConstructionException { Interface result = interfaceTypeCache.get( interfaze ); if (result==null) { result = createInterfaceType(interfaze); interfaceTypeCache.put(interfaze, result); } return result; } private Interface createInterfaceType(Class interfaze) throws BindingConstructionException { MethodTypeBinding[] bindings = getInterfaceBinding(interfaze); MethodTypeDefinition defs[] = new MethodTypeDefinition[bindings.length]; for (int i=0; i */ class ObjectUnionBinding extends UnionBinding { Class[] classes; public ObjectUnionBinding(Datatype type, Class[] classes) { this.classes = classes; this.type = type; } @Override public Object create(int tag, Object value) throws BindingException { return value; } @Override public void setValue(Object union, int tag, Object value) throws BindingException { throw new BindingException("Cannot change the class of an instance"); } @Override public int getTag(Object obj) throws BindingException { for (int i=0; i clazz : classes) if (clazz.isInstance(obj)) return true; return false; } @Override public boolean isImmutable() { return true; } @Override protected boolean baseEquals( Object obj ) { return super.baseEquals( obj ) && classes.equals( ((ObjectUnionBinding)obj).classes ); } @Override protected int baseHashCode() { return super.baseHashCode() + 27 * classes.hashCode(); } }