/******************************************************************************* * Copyright 2005, 2009 CHISEL Group, University of Victoria, Victoria, BC, * Canada. 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: The Chisel Group, University of Victoria IBM CAS, IBM Toronto * Lab ******************************************************************************/ /******************************************************************************* * Modified work Copyright 2013 Temenos Holdings N.V. * The example code for XText visualisation has been modified to visualise * the IRIS RIMDSL. ******************************************************************************/ package com.temenos.interaction.rimdsl.visualisation.providers; /* * #%L * com.temenos.interaction.rimdsl.RimDsl - Visualisation * %% * Copyright (C) 2012 - 2013 Temenos Holdings N.V. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.viewers.Viewer; import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; import com.google.common.collect.Iterators; import com.temenos.interaction.rimdsl.rim.DomainModel; import com.temenos.interaction.rimdsl.rim.Expression; import com.temenos.interaction.rimdsl.rim.Function; import com.temenos.interaction.rimdsl.rim.NotFoundFunction; import com.temenos.interaction.rimdsl.rim.OKFunction; import com.temenos.interaction.rimdsl.rim.ResourceInteractionModel; import com.temenos.interaction.rimdsl.rim.State; import com.temenos.interaction.rimdsl.rim.Transition; import com.temenos.interaction.rimdsl.rim.TransitionAuto; import com.temenos.interaction.rimdsl.rim.TransitionEmbedded; import com.temenos.interaction.rimdsl.rim.TransitionForEach; import com.temenos.interaction.rimdsl.rim.TransitionSpec; /** * Content provider for a ZEST graph viewer * @author aphethean */ public class ResourceInteractionContentProvider implements IGraphEntityContentProvider { private boolean showIncomingRelations; private boolean showOutgoingRelations; private List<TransitionDescription> transitions; private Set<State> states; private EObject input; /** * A utility method called from the label provider * that is used to get the description of a relation * @param from The source entity of the relation * @param to The target entity of the relation * @return The description of the relation connecting the source entity to the target entity */ public List<String> getTransitionDescription(Object from, Object to) { List<String> result = new ArrayList<String>(); for (TransitionDescription transition : transitions) { if (transition.getFromState() == from && transition.getToState() == to) { if (transition.getTitle() != null) { result.add(transition.getEvent()+" "+transition.getTitle()); if (transition.getConditions().length() > 0) { result.add(transition.getConditions()); } } } } return result; } /** * Constructor * @param showIncomingRelations whether incoming relations are shown * @param showOutgoingRelations whether outgoing relations are shown */ public ResourceInteractionContentProvider(boolean showIncomingRelations, boolean showOutgoingRelations) { super(); this.showIncomingRelations = showIncomingRelations; this.showOutgoingRelations = showOutgoingRelations; transitions = new ArrayList<TransitionDescription>(); states = new HashSet<State>(); input = null; } /* (non-Javadoc) * @see org.eclipse.zest.core.viewers.IGraphEntityContentProvider#getConnectedTo(java.lang.Object) */ public Object[] getConnectedTo(Object o) { if (o instanceof State) { State state = (State)o; List<State> result = new ArrayList<State>(); for (TransitionDescription transition : transitions) { if (transition.getFromState() == state) { result.add(transition.getToState()); } } return result.toArray(); } return null; } /* (non-Javadoc) * @see org.eclipse.zest.core.viewers.IGraphEntityContentProvider#getElements(java.lang.Object) */ public Object[] getElements(Object inputElement) { List<EObject> result = new ArrayList<EObject>(); result.addAll(states); return result.toArray(); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ public void dispose() { input = null; states.clear(); transitions.clear(); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (newInput == null) { input = null; rebuildTransitions(); } else { if (newInput instanceof State) { input = (EObject) newInput; rebuildTransitions(); } else { throw new RuntimeException("Input element not supported! Need to be " + State.class.getCanonicalName()); } } } /** * Setter, shows or hides incoming relations * @param enable */ public void setShowIncomingRelations(boolean enable) { this.showIncomingRelations = enable; rebuildTransitions(); } /** * Setter, shows or hides outgoing relations * @param enable */ public void setShowOutgoingRelations(boolean enable) { this.showOutgoingRelations = enable; rebuildTransitions(); } /** * Used internally to build up all transitions and caches. * Must be called after the visualisation options have been changed */ private void rebuildTransitions() { states.clear(); transitions.clear(); if (input != null) { // Some temporary buffers Set<State> allStates = new HashSet<State>(); Map<State, Set<TransitionDescription>> incomingTransitions = new HashMap<State, Set<TransitionDescription>>(); Map<State, Set<TransitionDescription>> outgoingTransitions = new HashMap<State, Set<TransitionDescription>>(); if (input instanceof State) { State state = (State)input; // Iterate over all elements in model Iterator<EObject> iter = state.eResource().getAllContents(); while (iter.hasNext()) { EObject rootContent = iter.next(); if (rootContent instanceof DomainModel) { DomainModel model = (DomainModel) rootContent; Iterator<ResourceInteractionModel> rims = Iterators.filter(model.eAllContents(), ResourceInteractionModel.class); while (rims.hasNext()) { ResourceInteractionModel rim = rims.next(); processRIM(rim, allStates, incomingTransitions, outgoingTransitions); } } } // Then build the visual representation of the part of // the network that is to be shown if (showIncomingRelations) { retrieveStatesTransitions(state, incomingTransitions, true); } if (showOutgoingRelations) { retrieveStatesTransitions(state, outgoingTransitions, false); } } } } private void processRIM(ResourceInteractionModel model, Set<State> allStates, Map<State, Set<TransitionDescription>> incomingTransitions, Map<State, Set<TransitionDescription>> outgoingTransitions) { Iterator<State> states = Iterators.filter(model.eAllContents(), State.class); while (states.hasNext()) { State state = states.next(); System.out.println("Adding state " + state.getName()); allStates.add((State) state); Iterator<Transition> transitions = Iterators.filter(state.eAllContents(), Transition.class); while (transitions.hasNext()) { Transition transition = transitions.next(); String title = (transition.getSpec() != null && transition.getSpec().getTitle() != null ? transition.getSpec().getTitle().getName() : ""); assert(transition.eContainer() instanceof State); State fromState = (State)transition.eContainer(); State toState = transition.getState(); if (fromState != null && toState != null) { TransitionDescription t = new TransitionDescription.Builder() .title(title) .event(transition.getEvent().getName()) .conditions(createConditionsStr(transition.getSpec())) .fromState(fromState) .toState(toState) .build(); addInOut(t, incomingTransitions, outgoingTransitions); } } Iterator<TransitionForEach> transitionsForEach = Iterators.filter(state.eAllContents(), TransitionForEach.class); while (transitionsForEach.hasNext()) { TransitionForEach transition = transitionsForEach.next(); String title = (transition.getSpec() != null && transition.getSpec().getTitle() != null ? transition.getSpec().getTitle().getName() : ""); assert(transition.eContainer() instanceof State); State fromState = (State)transition.eContainer(); State toState = transition.getState(); if (fromState != null && toState != null) { TransitionDescription t = new TransitionDescription.Builder() .title(title) .event(transition.getEvent().getName()) .conditions(createConditionsStr(transition.getSpec())) .fromState(fromState) .toState(toState) .build(); addInOut(t, incomingTransitions, outgoingTransitions); } } Iterator<TransitionAuto> transitionsAuto = Iterators.filter(state.eAllContents(), TransitionAuto.class); while (transitionsAuto.hasNext()) { TransitionAuto transition = transitionsAuto.next(); String title = "-->"; assert(transition.eContainer() instanceof State); State fromState = (State)transition.eContainer(); State toState = transition.getState(); if (fromState != null && toState != null) { TransitionDescription t = new TransitionDescription.Builder() .title(title) .event(transition.getEvent().getName()) .conditions(createConditionsStr(transition.getSpec())) .fromState(fromState) .toState(toState) .build(); addInOut(t, incomingTransitions, outgoingTransitions); } } Iterator<TransitionEmbedded> transitionsEmbedded = Iterators.filter(state.eAllContents(), TransitionEmbedded.class); while (transitionsEmbedded.hasNext()) { TransitionEmbedded transition = transitionsEmbedded.next(); String title = "+->"; assert(transition.eContainer() instanceof State); State fromState = (State)transition.eContainer(); State toState = transition.getState(); if (fromState != null && toState != null) { TransitionDescription t = new TransitionDescription.Builder() .title(title) .event(transition.getEvent().getName()) .conditions(createConditionsStr(transition.getSpec())) .fromState(fromState) .toState(toState) .build(); addInOut(t, incomingTransitions, outgoingTransitions); } } } } private String createConditionsStr(TransitionSpec spec) { String result = ""; if (spec != null) { Expression expression = spec.getEval(); if (expression != null) { for (Function func : expression.getExpressions()) { if (result.length() > 0) { result += " "; } if (func instanceof NotFoundFunction) { result += "NOT_FOUND(" + ((NotFoundFunction)func).getState().getName()+ ")"; } if (func instanceof OKFunction) { result += "OK(" + ((OKFunction)func).getState().getName()+ ")"; } } } } return result; } private void addInOut(TransitionDescription t, Map<State, Set<TransitionDescription>> incomingTransitions, Map<State, Set<TransitionDescription>> outgoingTransitions) { State toState = t.getToState(); Set<TransitionDescription> incomingTransitionsForState = incomingTransitions.get(toState); if (incomingTransitionsForState == null) { incomingTransitionsForState = new HashSet<TransitionDescription>(); incomingTransitions.put(toState, incomingTransitionsForState); } incomingTransitionsForState.add(t); State fromState = t.getFromState(); assert(fromState instanceof State); Set<TransitionDescription> outgoingTransitionsForState = outgoingTransitions.get(fromState); if (outgoingTransitionsForState == null) { outgoingTransitionsForState = new HashSet<TransitionDescription>(); outgoingTransitions.put(fromState, outgoingTransitionsForState); } outgoingTransitionsForState.add(t); } private void retrieveStatesTransitions(State root, Map<State, Set<TransitionDescription>> allTransistions, boolean backwards) { Set<State> visitedStates = new HashSet<State>(); visitedStates.clear(); internalRetrieveStatesTransitions(root, visitedStates, allTransistions, backwards); } private void internalRetrieveStatesTransitions(State root, Set<State> visitedStates, Map<State, Set<TransitionDescription>> allTransitions, boolean backwards) { states.add(root); Set<TransitionDescription> transitionsForState = allTransitions.get(root); if (transitionsForState != null) { for (TransitionDescription t : transitionsForState) { if (!transitions.contains(t)) transitions.add(t); State next = null; if (backwards) { next = t.getFromState(); } else { next = t.getToState(); } // Recursive call if this element has not been in focus before if (!visitedStates.contains(next)) { visitedStates.add(next); internalRetrieveStatesTransitions(next, visitedStates, allTransitions, backwards); } } } } }