package com.sap.ap.metamodel.eventhandlers; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.logging.Logger; import org.osgi.framework.BundleContext; import com.sap.tc.moin.globalmodellistener.GlobalEventListener; import com.sap.tc.moin.repository.Connection; import com.sap.tc.moin.repository.MRI; import com.sap.tc.moin.repository.events.EventChain; import com.sap.tc.moin.repository.events.EventListener; import com.sap.tc.moin.repository.events.UpdateListener; import com.sap.tc.moin.repository.events.filter.AndFilter; import com.sap.tc.moin.repository.events.filter.AssociationFilter; import com.sap.tc.moin.repository.events.filter.EventFilter; import com.sap.tc.moin.repository.events.filter.EventTypeFilter; import com.sap.tc.moin.repository.events.type.ChangeEvent; import com.sap.tc.moin.repository.events.type.LinkAddEvent; import com.sap.tc.moin.repository.mmi.model.Association; import com.sap.tc.moin.repository.mmi.reflect.RefClass; import data.classes.AConversionMethodConverter; import data.classes.ActualObjectParameter; import data.classes.ClassTypeDefinition; import data.classes.ConverterBetweenParametrizations; import data.classes.MethodSignature; import data.classes.Parameter; import dataaccess.expressions.VariableExpression; /** * Due to the current limitations of the Furcas/TCS approach we cannot create the actual object * parameters for the {@link ClassTypeDefinition} that is attached as the output of a converter * method for object-parameterized value classes, mostly because creating a number of elements * determined dynamically from the cardinality of some other feature is not supported at this time. * As a workaround, we install this global event listener which will get notified whenever a * {@link ConverterBetweenParametrizations} element is linked to a {@link MethodSignature} using the * {@link AConversionMethodConverter} association. This handler will determine the formal object * parameters of the class and create {@link VariableExpression}s, one for each input parameter of * the converter method signature, and set them as the actual object parameters for the class type * definition used as that very method's output. It does so in the scope of the connection that * caused the change event. * * @author Axel Uhl (D043530) * */ public class ConverterOutputSetter implements GlobalEventListener, UpdateListener { Logger log = Logger.getLogger(ConverterOutputSetter.class.getName()); @Override public void notifyUpdate(EventChain events) { for (ChangeEvent event : events.getEvents()) { if (event instanceof LinkAddEvent) { LinkAddEvent lre = (LinkAddEvent) event; MRI thisMri = lre.getSecondLinkEndMri(); Connection conn = event.getEventTriggerConnection(); ConverterBetweenParametrizations converter = (ConverterBetweenParametrizations) conn.getElement(thisMri.getLri()); MethodSignature methodSignature = (MethodSignature) conn.getElement(lre .getFirstLinkEndMri().getLri()); constructActualObjectParams(converter, methodSignature, conn); } } } private void constructActualObjectParams(ConverterBetweenParametrizations converter, MethodSignature methodSignature, Connection conn) { if (methodSignature == null) { log.severe("Converter's signature doesn't have input parameters yet."+ " Unable to establish actual object parameters on output."); } else { RefClass vec = conn.getClass(VariableExpression.CLASS_DESCRIPTOR); RefClass aopc = conn.getClass(ActualObjectParameter.CLASS_DESCRIPTOR); Iterator<Parameter> formalObjectParamIter = converter.getClazz().getFormalObjectParameters().iterator(); for (Parameter param:methodSignature.getInput()) { VariableExpression ve = (VariableExpression) vec.refCreateInstance(); ve.setVariable(param); ActualObjectParameter aop = (ActualObjectParameter) aopc.refCreateInstance(); aop.setFormalObjectParameter(formalObjectParamIter.next()); aop.setValue(ve); ((ClassTypeDefinition) methodSignature.getOutput()).getObjectParameters().add(aop); } } } @Override public Map<EventFilter, Map<ListenerType, EventListener>> getFilters(Connection connection, BundleContext context) { HashMap<EventFilter, Map<ListenerType, EventListener>> result = new HashMap<EventFilter, Map<ListenerType, EventListener>>(); Association converterMethodAssoc = connection.getAssociation( AConversionMethodConverter.ASSOCIATION_DESCRIPTOR).refMetaObject(); EventFilter assocFilter = new AssociationFilter(converterMethodAssoc); EventFilter andFilter = new AndFilter(assocFilter, new EventTypeFilter(LinkAddEvent.class)); Map<ListenerType, EventListener> listenerForType = new HashMap<ListenerType, EventListener>(); listenerForType.put(ListenerType.UPDATE, this); result.put(andFilter, listenerForType); return result; } }