/******************************************************************************* * Copyright (c) 2012 Olivier Moises * * 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: Olivier Moises- initial API and implementation *******************************************************************************/ package org.eclipse.wazaabi.ide.mapping.rules; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EEnum; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.wazaabi.ide.mapping.annotations.AbstractComponentMappingRule; import org.eclipse.wazaabi.ide.mapping.annotations.EAttributeMappingRule; import org.eclipse.wazaabi.ide.mapping.annotations.EClassMappingRule; import org.eclipse.wazaabi.mm.core.widgets.AbstractComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MappingRuleManager { final static Logger logger = LoggerFactory.getLogger(MappingRuleManager.class); private HashSet<MappingMethodDescriptor> descriptors = new HashSet<MappingMethodDescriptor>(); public List<?> get(EObject target, int index, EObject source, EClass droppedType, Object context) { return get(target, index, source, droppedType.getInstanceClass(), context); } public List<?> get(Object target, int index, Object source, Class<?> droppedType, Object context) { return get(target, null, index, source, droppedType, context); } public List<?> get(Object target, Class<?> targetType, int index, Object source, Class<?> droppedType, Object context) { if (target == null || source == null || droppedType == null) return Collections.emptyList(); if (targetType == null) targetType = getTargetType(target); Object sourceType = getSourceType(source); if (targetType == null || sourceType == null) return Collections.emptyList(); MappingMethodDescriptor descriptor = getDescriptor(targetType, sourceType, droppedType, context); if (descriptor != null) try { List<?> result = (List<?>) descriptor.getMethod().invoke( descriptor.getContainingInstance(), new Object[] { target, index, source, context }); return result != null ? result : Collections.emptyList(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return Collections.emptyList(); } protected Class<?> getTargetType(Object target) { if (target != null) { if (target instanceof EObject) return ((EObject) target).eClass().getInstanceClass(); else if (target instanceof Class<?>) return (Class<?>) target; else if (target instanceof Object) return target.getClass(); } return null; } protected Object getSourceType(Object source) { if (source instanceof EAttribute) if (((EAttribute) source).getEAttributeType() instanceof EEnum) return EEnum.class; else return ((EAttribute) source).getEAttributeType() .getInstanceClass(); else if (source instanceof EReference) return null; // TODO : not supported yet else if (source instanceof EClass) return EClass.class; else if (source instanceof EObject) return ((EObject) source).eClass().getInstanceClass(); return null; } protected MappingMethodDescriptor getDescriptor(Class<?> target, Object sourceType, Class<?> droppedType, Object context) { for (MappingMethodDescriptor descriptor : descriptors) { if (sourceType.equals(descriptor.getSourceType()) && target.equals(descriptor.getTargetType()) && droppedType.equals(descriptor.getDroppedType())) return descriptor; } return null; } public List<MappingMethodDescriptor> getDescriptors(EObject targetUI, EClassifier sourceValue, EClass droppedType) { List<MappingMethodDescriptor> result = new ArrayList<MappingMethodDescriptor>(); for (MappingMethodDescriptor descriptor : descriptors) { if (sourceValue.equals(descriptor.getSourceType()) && targetUI.eClass().getInstanceClass() .equals(descriptor.getTargetType()) && droppedType.getInstanceClass() == descriptor .getDroppedType()) result.add(descriptor); } return result; } public void registerContainingInstance(Object instance) { if (instance == null) return; Method methods[] = instance.getClass().getDeclaredMethods(); for (Method method : methods) registerMethod(method, instance); } protected void registerMethod(Method method, Object containingInstance) { if (method == null || containingInstance == null) return; EAttributeMappingRule eAttributeAnnotation = (EAttributeMappingRule) method .getAnnotation(EAttributeMappingRule.class); EClassMappingRule eClassAnnotation = (EClassMappingRule) method .getAnnotation(EClassMappingRule.class); AbstractComponentMappingRule abstractComponentAnnotation = (AbstractComponentMappingRule) method .getAnnotation(AbstractComponentMappingRule.class); if (eAttributeAnnotation != null && eClassAnnotation != null && abstractComponentAnnotation == null) return; Class<?> sourceType = null; if (abstractComponentAnnotation != null) { registerMethodForAbstractComponentMappingRule(method, containingInstance); } else if (eAttributeAnnotation != null) { sourceType = getDataType(eAttributeAnnotation.datatype()) .getInstanceClass(); registerMethodForEAttributeMappingRule(method, containingInstance, sourceType); } else if (eClassAnnotation != null) { sourceType = EClass.class; registerMethodForEClassMappingRule(method, containingInstance, sourceType); } } protected void registerMethodForEAttributeMappingRule(Method method, Object containingInstance, Class<?> sourceType) { if (sourceType != null) { Class<?> parameterTypes[] = method.getParameterTypes(); if (parameterTypes.length != 4) return; if (parameterTypes[1].equals(int.class) && parameterTypes[2].equals(EAttribute.class) && parameterTypes[3].equals(Object.class) && method.getReturnType().equals(List.class)) { Type returnType = method.getGenericReturnType(); if (returnType instanceof ParameterizedType) { ParameterizedType type = (ParameterizedType) returnType; Type[] typeArguments = type.getActualTypeArguments(); if (typeArguments.length == 1 && typeArguments[0] instanceof Class<?>) { logger.debug("Adding {}.{}", new Object[] { containingInstance, method.getName() }); descriptors .add(new MappingMethodDescriptor( containingInstance, method, sourceType, parameterTypes[0], (Class<?>) typeArguments[0])); } } } } } protected void registerMethodForEClassMappingRule(Method method, Object containingInstance, Class<?> sourceType) { if (sourceType != null) { Class<?> parameterTypes[] = method.getParameterTypes(); if (parameterTypes.length != 4) return; if (parameterTypes[1].equals(int.class) && parameterTypes[2].equals(EClass.class) && parameterTypes[3].equals(Object.class) && method.getReturnType().equals(List.class)) { Type returnType = method.getGenericReturnType(); if (returnType instanceof ParameterizedType) { ParameterizedType type = (ParameterizedType) returnType; Type[] typeArguments = type.getActualTypeArguments(); if (typeArguments.length == 1 && typeArguments[0] instanceof Class<?>) { logger.debug("Adding {}.{}", new Object[] { containingInstance, method.getName() }); descriptors .add(new MappingMethodDescriptor( containingInstance, method, sourceType, parameterTypes[0], (Class<?>) typeArguments[0])); } } } } } protected void registerMethodForAbstractComponentMappingRule(Method method, Object containingInstance) { Class<?> parameterTypes[] = method.getParameterTypes(); if (parameterTypes.length != 4) return; if (parameterTypes[1].equals(int.class) && AbstractComponent.class.isAssignableFrom(parameterTypes[2]) && parameterTypes[2].isInterface() && parameterTypes[3].equals(Object.class) && method.getReturnType().equals(List.class)) { Type returnType = method.getGenericReturnType(); if (returnType instanceof ParameterizedType) { ParameterizedType type = (ParameterizedType) returnType; Type[] typeArguments = type.getActualTypeArguments(); if (typeArguments.length == 1 && typeArguments[0] instanceof Class<?>) { logger.debug("Adding {}.{}", new Object[] { containingInstance, method.getName() }); descriptors.add(new MappingMethodDescriptor( containingInstance, method, parameterTypes[2], parameterTypes[0], (Class<?>) typeArguments[0])); } } } } public EClassifier getDataType(String name) { if (name == null || "".equals(name)) //$NON-NLS-1$ return null; int idx = name.lastIndexOf('/'); if (idx != -1) { String packageURI = name.substring(0, idx); return getDataType( (EPackage) EPackage.Registry.INSTANCE.get(packageURI), name.substring(idx + 1)); } return getDataType(EcorePackage.eINSTANCE, name); } protected EClassifier getDataType(EPackage p, String name) { if (p == null || name == null || "".equals(name)) //$NON-NLS-1$ return null; for (EClassifier eClassifier : p.getEClassifiers()) { if (name.equals(((EClassifier) eClassifier).getName())) { if (eClassifier instanceof EDataType || (eClassifier instanceof EClass && EcorePackage.Literals.EDATA_TYPE .isSuperTypeOf((EClass) eClassifier))) // TODO: not really sure about the second predicate return eClassifier; } } return null; } }