| /******************************************************************************* |
| * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro |
| * 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: |
| * Gabor Bergmann - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.viatra2.gtasm.patternmatcher.incremental.adapters; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.viatra2.core.ICoreNotificationListener; |
| import org.eclipse.viatra2.core.IEntity; |
| import org.eclipse.viatra2.core.IModelElement; |
| import org.eclipse.viatra2.core.IRelation; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObject; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectCreateEntity; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectCreateInstanceOf; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectCreateRelation; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectCreateSupertypeOf; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectDeleteContainment; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectDeleteEntity; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectDeleteInstanceOf; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectDeleteRelation; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectDeleteSupertypeOf; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectMoveTo; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectSetName; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectSetRelationFrom; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectSetRelationTo; |
| import org.eclipse.viatra2.core.notification.ICoreNotificationObjectSetValue; |
| import org.eclipse.viatra2.framework.IFramework; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.boundary.IManipulationListener; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.boundary.PredicateEvaluatorNode; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.boundary.ReteBoundary; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.matcher.ReteEngine; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.network.Direction; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.network.ReteContainer; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.network.Tunnel; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.remote.Address; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.tuple.FlatTuple; |
| import org.eclipse.viatra2.gtasm.patternmatcher.incremental.rete.tuple.Tuple; |
| |
| /** |
| * Registering/unregistering is synchronized, as well as notification |
| * processing. Reason: thread safety of Registering/unregistering and message |
| * sending and action notifications |
| * |
| * @author Gabor Bergmann |
| * |
| */ |
| public class GlobalModelspaceListener implements ICoreNotificationListener, |
| IManipulationListener { |
| |
| protected WeakReference<IFramework> framework; |
| protected ReteEngine<?> engine; |
| protected ReteBoundary<?> boundary; |
| protected ReteContainer headContainer; |
| |
| // TermEvaluatorNodes that have to be notified on changes affecting a given ModelElement |
| protected Map<Object, Set<PredicateEvaluatorNode>> sensitiveTerms; |
| |
| /** |
| * Prerequisite: engine has its network, framework and boundary fields |
| * initialized |
| * |
| * @param engine |
| */ |
| public GlobalModelspaceListener(ReteEngine<?> engine, IFramework framework) { |
| super(); |
| this.engine = engine; |
| this.boundary = engine.getBoundary(); |
| this.headContainer = engine.getReteNet().getHeadContainer(); |
| |
| this.sensitiveTerms = new HashMap<Object, Set<PredicateEvaluatorNode>>(); |
| |
| this.framework = new WeakReference<IFramework>(framework); |
| framework.getTopmodel().getNotificationManager() |
| .addAllListener(this); |
| engine.addDisconnectable(this); |
| } |
| |
| public synchronized void actionPerformed( |
| ICoreNotificationObject notification) { |
| //System.out.println("Core notification: "+notification.getActionType()) |
| // ; |
| |
| // if (notification.getActionType().equals(ICoreNotificationObject. |
| // TA_TRANSACTION_BEGIN)) |
| // { |
| // inTransaction = true; |
| // return; |
| // } |
| // else if (notification.getActionType().equals(ICoreNotificationObject. |
| // TA_UNDOABLE_TRANSACTION_BEGIN)) |
| // { |
| // return; |
| // } |
| // else if (notification.getActionType().equals(ICoreNotificationObject. |
| // TA_TRANSACTION_END)) |
| // { |
| // inTransaction = false; |
| // iTreeViewer.refresh(); |
| // iContentProvider.setDirty(); // notify editor that the model has |
| // changed |
| // return; |
| // } |
| // if (inTransaction) |
| // return; |
| // |
| |
| switch(notification.getActionTypeEnum()){ |
| case ACTION_SET_NAME: |
| ICoreNotificationObjectSetName n = (ICoreNotificationObjectSetName) notification; |
| notifyElementChange(n.getElement()); |
| break; |
| case ACTION_SET_VALUE: |
| ICoreNotificationObjectSetValue n1 = (ICoreNotificationObjectSetValue) notification; |
| notifyElementChange(n1.getEntity()); |
| break; |
| case ACTION_CREATE_INSTANCEOF: |
| ICoreNotificationObjectCreateInstanceOf n2 = (ICoreNotificationObjectCreateInstanceOf) notification; |
| |
| IModelElement instance = n2.getInstance(); |
| if (instance instanceof IEntity) |
| boundary.updateUnary(Direction.INSERT, instance, n2.getType()); |
| else if (instance instanceof IRelation) { |
| IRelation relation = (IRelation) instance; |
| boundary.updateTernaryEdge(Direction.INSERT, relation, |
| relation.getFrom(), relation.getTo(), n2.getType()); |
| } |
| boundary.updateInstantiation(Direction.INSERT, n2.getType(), |
| n2.getInstance()); |
| break; |
| case ACTION_DELETE_INSTANCEOF: |
| ICoreNotificationObjectDeleteInstanceOf n3 = (ICoreNotificationObjectDeleteInstanceOf) notification; |
| |
| instance = n3.getInstance(); |
| if (instance instanceof IEntity) |
| boundary.updateUnary(Direction.REVOKE, instance, n3.getType()); |
| else if (instance instanceof IRelation) { |
| IRelation relation = (IRelation) instance; |
| boundary.updateTernaryEdge(Direction.REVOKE, relation, |
| relation.getFrom(), relation.getTo(), n3.getType()); |
| } |
| boundary.updateInstantiation(Direction.REVOKE, n3.getType(), |
| n3.getInstance()); |
| break; |
| case ACTION_CREATE_SUPERTYPEOF: |
| ICoreNotificationObjectCreateSupertypeOf n4 = (ICoreNotificationObjectCreateSupertypeOf) notification; |
| |
| IModelElement superElement = n4.getSuper(); |
| IModelElement subElement = n4.getSub(); |
| boundary.updateGeneralization(Direction.INSERT, superElement, |
| subElement); |
| if (superElement instanceof IEntity) { |
| Address<? extends Tunnel> superRoot = boundary |
| .getUnaryRoot(superElement); |
| if (superRoot != null) // only if we have to keep track of the |
| // supertype |
| { |
| Address<? extends Tunnel> subRoot = boundary |
| .accessUnaryRoot(subElement); |
| engine.getReteNet().connectRemoteNodes(subRoot, superRoot, |
| true); |
| } |
| } else if (superElement instanceof IRelation) { |
| Address<? extends Tunnel> superRoot = boundary |
| .getTernaryEdgeRoot(superElement); |
| if (superRoot != null) // only if we have to keep track of the |
| // supertype |
| { |
| Address<? extends Tunnel> subRoot = boundary |
| .accessTernaryEdgeRoot(subElement); |
| engine.getReteNet().connectRemoteNodes(subRoot, superRoot, |
| true); |
| } |
| } |
| break; |
| case ACTION_DELETE_SUPERTYPEOF: |
| ICoreNotificationObjectDeleteSupertypeOf n5 = (ICoreNotificationObjectDeleteSupertypeOf) notification; |
| |
| superElement = n5.getSuper(); |
| subElement = n5.getSub(); |
| boundary.updateGeneralization(Direction.REVOKE, superElement, |
| subElement); |
| if (superElement instanceof IEntity) { |
| Address<? extends Tunnel> superRoot = boundary |
| .getUnaryRoot(superElement); |
| if (superRoot != null) // only if we have to keep track of the |
| // supertype |
| { |
| Address<? extends Tunnel> subRoot = boundary |
| .accessUnaryRoot(subElement); |
| engine.getReteNet().disconnectRemoteNodes(subRoot, |
| superRoot, true); |
| } |
| } else if (superElement instanceof IRelation) { |
| Address<? extends Tunnel> superRoot = boundary |
| .getTernaryEdgeRoot(superElement); |
| if (superRoot != null) // only if we have to keep track of the |
| // supertype |
| { |
| Address<? extends Tunnel> subRoot = boundary |
| .accessTernaryEdgeRoot(subElement); |
| engine.getReteNet().disconnectRemoteNodes(subRoot, |
| superRoot, true); |
| } |
| } |
| break; |
| // case ACTION_SET_VIEW_INFO: |
| // ICoreNotificationObjectSetViewInfo n = |
| // (ICoreNotificationObjectSetViewInfo)notification; |
| // iTreeViewer.update(n.getElement(), new String[]{"name"}); |
| // break; |
| case ACTION_CREATE_ENTITY: |
| ICoreNotificationObjectCreateEntity n6 = (ICoreNotificationObjectCreateEntity) notification; |
| |
| IEntity entity = n6.getCreated(); |
| // for (IModelElement type : entity.getTypes()) |
| // boundary.updateEntity(Direction.INSERT, entity, |
| // type.getFullyQualifiedName()); |
| boundary.updateUnary(Direction.INSERT, entity, null); |
| boundary.updateContainment(Direction.INSERT, n6.getContainer(), |
| entity); |
| break; |
| case ACTION_CREATE_RELATION: |
| ICoreNotificationObjectCreateRelation n7 = (ICoreNotificationObjectCreateRelation) notification; |
| |
| IRelation relation = n7.getNewRelation(); |
| // for (IModelElement type : relation.getTypes()) |
| // boundary.updateRelation(Direction.INSERT, relation, |
| // relation.getFrom(), relation.getTo(), |
| // type.getFullyQualifiedName()); |
| boundary.updateTernaryEdge(Direction.INSERT, relation, |
| n7.getFrom(), n7.getTo(), null); |
| break; |
| case ACTION_MOVE_ELEMENT_TO: |
| ICoreNotificationObjectMoveTo n8 = (ICoreNotificationObjectMoveTo) notification; |
| |
| IEntity element = n8.getElement(); |
| boundary.updateContainment(Direction.REVOKE, n8.getOldContainer(), |
| element); |
| boundary.updateContainment(Direction.INSERT, n8.getNewContainer(), |
| element); |
| |
| notifyElementChange(n8.getElement()); |
| break; |
| case ACTION_DELETE_ENTITY: |
| ICoreNotificationObjectDeleteEntity n9 = (ICoreNotificationObjectDeleteEntity) notification; |
| |
| entity = n9.getDeleted(); |
| // for (IModelElement type : entity.getTypes()) |
| // boundary.updateEntity(Direction.REVOKE, entity, |
| // type.getFullyQualifiedName()); |
| boundary.updateUnary(Direction.REVOKE, entity, null); |
| // boundary.revokeRelation(n.getParent(), entity, |
| // ReteBoundary.containmentLabel); |
| break; |
| case ACTION_DELETE_RELATION: |
| ICoreNotificationObjectDeleteRelation n10 = (ICoreNotificationObjectDeleteRelation) notification; |
| |
| relation = n10.getDeleted(); |
| // for (IModelElement type : relation.getTypes()) |
| // boundary.updateRelation(Direction.REVOKE, relation, |
| // relation.getFrom(), relation.getTo(), |
| // type.getFullyQualifiedName()); |
| boundary.updateTernaryEdge(Direction.REVOKE, relation, |
| n10.getFrom(), n10.getTo(), null); |
| break; |
| case ACTION_DELETE_CONTAINMENT: |
| ICoreNotificationObjectDeleteContainment n11 = (ICoreNotificationObjectDeleteContainment) notification; |
| boundary.updateContainment(Direction.REVOKE, n11.getParent(), |
| n11.getChild()); |
| break; |
| case ACTION_SET_RELATION_FROM: |
| ICoreNotificationObjectSetRelationFrom n12 = (ICoreNotificationObjectSetRelationFrom) notification; |
| |
| relation = n12.getRelation(); |
| for (IModelElement type : relation.getTypes()) { |
| boundary.updateTernaryEdge(Direction.REVOKE, relation, |
| n12.getOldFrom(), relation.getTo(), type); |
| boundary.updateTernaryEdge(Direction.INSERT, relation, |
| n12.getNewFrom(), relation.getTo(), type); |
| } |
| boundary.updateTernaryEdge(Direction.REVOKE, relation, |
| n12.getOldFrom(), relation.getTo(), null); |
| boundary.updateTernaryEdge(Direction.INSERT, relation, |
| n12.getNewFrom(), relation.getTo(), null); |
| notifyElementChange(relation); |
| break; |
| case ACTION_SET_RELATION_TO: |
| ICoreNotificationObjectSetRelationTo n13 = (ICoreNotificationObjectSetRelationTo) notification; |
| |
| relation = n13.getRelation(); |
| for (IModelElement type : relation.getTypes()) { |
| boundary.updateTernaryEdge(Direction.REVOKE, relation, |
| relation.getFrom(), n13.getOldTo(), type); |
| boundary.updateTernaryEdge(Direction.INSERT, relation, |
| relation.getFrom(), n13.getNewTo(), type); |
| } |
| boundary.updateTernaryEdge(Direction.REVOKE, relation, |
| relation.getFrom(), n13.getOldTo(), null); |
| boundary.updateTernaryEdge(Direction.INSERT, relation, |
| relation.getFrom(), n13.getNewTo(), null); |
| notifyElementChange(relation); |
| break; |
| case TA_TRANSACTION_END: |
| engine.runAfterUpdateCallbacks(); |
| break; |
| } |
| |
| } |
| |
| protected void notifyElementChange(Object element) { |
| synchronized (sensitiveTerms) { |
| Set<PredicateEvaluatorNode> nodes = sensitiveTerms.get(element); |
| if (nodes != null) { |
| Tuple tuple = new FlatTuple(element); |
| for (PredicateEvaluatorNode node : nodes) |
| boundary.notifyEvaluator(node.getElementChangeNotifier(), tuple); |
| } |
| } |
| } |
| |
| public void registerSensitiveTerm(Object element, PredicateEvaluatorNode node) { |
| synchronized (sensitiveTerms) { |
| Set<PredicateEvaluatorNode> nodes = sensitiveTerms.get(element); |
| if (nodes == null) { |
| nodes = new HashSet<PredicateEvaluatorNode>(); |
| sensitiveTerms.put(element, nodes); |
| } |
| nodes.add(node); |
| } |
| } |
| |
| public void unregisterSensitiveTerm(Object element, PredicateEvaluatorNode node) { |
| synchronized (sensitiveTerms) { |
| Set<PredicateEvaluatorNode> nodes = sensitiveTerms.get(element); |
| nodes.remove(node); |
| if (nodes.isEmpty()) sensitiveTerms.remove(element); |
| } |
| } |
| |
| public int getListenerCategory() { |
| // TODO Auto-generated method stub |
| return 0; |
| } |
| |
| public void disconnect() { |
| framework.get().getTopmodel().getNotificationManager() |
| .removeAllListener(this); |
| } |
| |
| } |