package com.sap.ap.metamodel.eventhandlers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
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.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.AttributeFilter;
import com.sap.tc.moin.repository.events.filter.ClassFilter;
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.AttributeValueEvent;
import com.sap.tc.moin.repository.events.type.ChangeEvent;
import com.sap.tc.moin.repository.events.type.LinkAddEvent;
import com.sap.tc.moin.repository.events.type.LinkChangeEvent;
import com.sap.tc.moin.repository.events.type.LinkRemoveEvent;
import com.sap.tc.moin.repository.mmi.model.Association;
import com.sap.tc.moin.repository.mmi.model.Attribute;
import com.sap.tc.moin.repository.mmi.model.MofClass;
import com.sap.tc.moin.repository.mmi.model.TypedElement;
import data.classes.AImplementationFunctionSignature;
import data.classes.FunctionSignature;
import data.classes.Parameter;
import dataaccess.analytics.ADimensionsCellSet;
import dataaccess.analytics.CellSet;
import dataaccess.analytics.Dimension;
/**
* Due to the current limitations of the Furcas/TCS approach we cannot create the parameters
* for the {@link FunctionSignature} used for the type of a {@link CellSet}. We want to
* create one {@link Parameter} element per {@link Dimension} element where the name is
* initialized from the dimension's name. The parameter's type is left unset because it is
* inferred by {@link TypedElement#getType()}.<p>
*
* This listener watches for establishing the link between a {@link CellSet} and its
* {@link FunctionSignature} (see {@link CellSet#setFunctionSignature(FunctionSignature)}) as
* well as for any changes in a cell set's dimensions (names, additions, deletions).
*
* @author Axel Uhl (D043530)
*
*/
public class CellSetFunctionSignatureParameterSetter implements GlobalEventListener, UpdateListener {
Logger log = Logger.getLogger(CellSetFunctionSignatureParameterSetter.class.getName());
@Override
public void notifyUpdate(EventChain events) {
for (ChangeEvent event : events.getEvents()) {
Connection conn = event.getEventTriggerConnection();
if (event instanceof LinkChangeEvent) {
LinkChangeEvent lce = (LinkChangeEvent) event;
if (lce.getAffectedMetaObject(conn).equals(conn.getAssociation(ADimensionsCellSet.ASSOCIATION_DESCRIPTOR).refMetaObject())) {
Dimension dimension = (Dimension) lce.getFirstLinkEnd(conn);
if (dimension != null) { // if it has been deleted already, we're out of luck
CellSet cellSet = dimension.getCellSet();
// continue only if a function signature has already been set
if (cellSet.getFunctionSignature() != null) {
int pos = lce.getPosition();
if (event instanceof LinkAddEvent) {
Parameter p = conn.createElement(Parameter.CLASS_DESCRIPTOR);
p.setName(dimension.getName());
// add 1 to skip the first argument which is the facts base
cellSet.getFunctionSignature().getInput().add(
(pos == -1) ? cellSet.getFunctionSignature().getInput().size() : pos + 1, p);
}
if (event instanceof LinkRemoveEvent) {
// add 1 to skip the first argument which is the facts base
cellSet.getFunctionSignature().getInput().remove(pos + 1);
}
}
}
} else if (lce.getAffectedMetaObject(conn).equals(
conn.getAssociation(AImplementationFunctionSignature.ASSOCIATION_DESCRIPTOR).refMetaObject())) {
if (lce instanceof LinkAddEvent) {
CellSet cellSet = (CellSet) lce.getFirstLinkEnd(conn);
if (cellSet != null) { // if deleted by later change, we're out of luck
setFactsAndDimensionParams(conn, cellSet, cellSet.getFunctionSignature());
}
}
}
} else if (event instanceof AttributeValueEvent) {
// synchronize the dimension's name to the parameter name
AttributeValueEvent ave = (AttributeValueEvent) event;
Dimension dim = (Dimension) ave.getAffectedElement(conn);
if (dim != null && dim.getCellSet() != null) {
FunctionSignature sig = dim.getCellSet().getFunctionSignature();
if (sig != null) {
int pos = dim.getCellSet().getDimensions().indexOf(dim);
if (pos < sig.getInput().size()) {
// add 1 to skip the first argument which is the facts base
sig.getInput().get(pos+1).setName(dim.getName());
}
}
}
}
}
}
private void setFactsAndDimensionParams(Connection conn, CellSet cellSet, FunctionSignature functionSignature) {
List<Parameter> params = new ArrayList<Parameter>(functionSignature.getInput());
for (Parameter param : params) {
param.refDelete();
}
Parameter factsParam = conn.createElement(Parameter.CLASS_DESCRIPTOR);
factsParam.setName("facts");
functionSignature.getInput().add(factsParam);
for (Dimension dim : cellSet.getDimensions()) {
Parameter p = conn.createElement(Parameter.CLASS_DESCRIPTOR);
p.setName(dim.getName());
functionSignature.getInput().add(p);
}
}
@Override
public Map<EventFilter, Map<ListenerType, EventListener>> getFilters(Connection connection, BundleContext context) {
HashMap<EventFilter, Map<ListenerType, EventListener>> result = new HashMap<EventFilter, Map<ListenerType, EventListener>>();
// the assoc between a function signature and its implementation (the cell set)
Association sigImplAssoc = connection.getAssociation(
AImplementationFunctionSignature.ASSOCIATION_DESCRIPTOR).refMetaObject();
EventFilter assocFilter = new AssociationFilter(sigImplAssoc);
EventFilter cellSetTypeFilter = new ClassFilter(connection.getClass(
CellSet.CLASS_DESCRIPTOR).refMetaObject(),
/* includeSubclasses */ true);
EventFilter andFilter = new AndFilter(assocFilter, cellSetTypeFilter, new EventTypeFilter(LinkAddEvent.class));
Map<ListenerType, EventListener> listenerForType = new HashMap<ListenerType, EventListener>();
listenerForType.put(ListenerType.UPDATE, this);
result.put(andFilter, listenerForType);
// name change on Dimension
MofClass dimension = connection.getClass(Dimension.CLASS_DESCRIPTOR).refMetaObject();
Attribute dimNameAttr = connection.getJmiHelper().getAttributeByName(
dimension, "name", /* includeSupertypes */true);
EventFilter dimensionNameChangeFilter = new AttributeFilter(dimNameAttr);
EventFilter dimTypeFilter = new ClassFilter(dimension, /* includeSubtypes */ true);
AndFilter dimensionNameChangeFilterWithTypeFilter = new AndFilter(dimensionNameChangeFilter, dimTypeFilter);
result.put(dimensionNameChangeFilterWithTypeFilter, listenerForType);
// changes on dimensions of a CellSet
Association dimensionsAssoc = connection.getAssociation(
ADimensionsCellSet.ASSOCIATION_DESCRIPTOR).refMetaObject();
EventFilter dimAssocFilter = new AssociationFilter(dimensionsAssoc);
result.put(dimAssocFilter, listenerForType);
return result;
}
}