RESequenceDiagramDialog.java
/* $Id$
*****************************************************************************
* Copyright (c) 2009-2013 Contributors - see below
* 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:
* bobtarling
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
*/
// Copyright (c) 1996-2008 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph appear in all copies. This software program and
// documentation are copyrighted by The Regents of the University of
// California. The software program and documentation are supplied "AS
// IS", without any accompanying services from The Regents. The Regents
// does not warrant that the operation of the program will be
// uninterrupted or error-free. The end-user understands that the program
// was developed for research purposes and is advised not to rely
// exclusively on the program for any reason. IN NO EVENT SHALL THE
// UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
package org.argouml.language.java.ui;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.SpinnerNumberModel;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.argouml.i18n.Translator;
import org.argouml.kernel.Project;
import org.argouml.kernel.ProjectManager;
import org.argouml.language.java.reveng.JavaLexer;
import org.argouml.language.java.reveng.JavaParser;
import org.argouml.language.java.reveng.Modeller;
import org.argouml.model.Model;
import org.argouml.profile.Profile;
import org.argouml.ui.CheckboxTableModel;
import org.argouml.ui.targetmanager.TargetManager;
import org.argouml.uml.diagram.ArgoDiagram;
import org.argouml.uml.diagram.DiagramElement;
import org.argouml.uml.diagram.DiagramFactory;
import org.argouml.uml.diagram.DiagramFactory.DiagramType;
import org.argouml.uml.ui.ActionDeleteModelElements;
import org.argouml.util.ArgoDialog;
//import org.tigris.gef.graph.MutableGraphModel;
//import org.tigris.gef.presentation.Fig;
/**
* The dialog that starts the reverse engineering of operations.<p>
*
* TODO: subsequent parsing of further operation bodies <p>
* TODO: suppressing multiple creation of already created messages<p>
* TODO: processing of non-constructor-calls to other classifiers<p>
* TODO: refactoring into many classes depending on their purpose.
* At the very least split dialog from processing and remove knowledge
* of sequence diagram implementation<p>
* TODO: work with import modules instead of the internal Java import<p>
* TODO: use java5 style for loops
* TODO: i18n<p>
*/
public class RESequenceDiagramDialog
extends ArgoDialog
implements ActionListener, ItemListener {
private static final Logger LOG =
Logger.getLogger(RESequenceDiagramDialog.class.getName());
private static final long serialVersionUID = -8595714827064181907L;
private static final int X_OFFSET = 10;
// Connected to commented-out code below:
// private static final Rectangle DEFAULT_BOUNDS = new Rectangle(10, 10);
/**
* The project this dialog is operating within
*/
private final Project project;
private final Object model;
// TODO: Why is this not final?
private Modeller modeller;
private final Object classifier;
private final Object operation;
// TODO: Need to remove knowledge of GEF.
//private final Fig figClassifierRole;
private final List<String> calls = new ArrayList<String>();
private final List<String> calldata = new ArrayList<String>();
private final Hashtable<String, String> types
= new Hashtable<String, String>();
private final ArgoDiagram diagram;
private CheckboxTableModel callTable;
private JComboBox modeChoice;
private JPanel changingPanel;
private JPanel manuPanel;
private JPanel autoPanel;
// Connected to commented-out code below:
// private int maxXPos = -X_OFFSET;
// private int anonCnt;
private final boolean isNewSequenceDiagram;
/**
* Constructor. A new sequence diagram will be created and the work
* happens in that new sequence diagram.
*
* @param oper The operation that should be reverse engineered.
*/
public RESequenceDiagramDialog(Object oper) {
this(oper, null, null);
}
/**
* Constructor. If a FigMessage object is passed, then it is assumed that
* the actual diagram is a sequence diagram, so no new one is created and
* the work happens in the actual sequence diagram.
*
* @param oper The operation that should be reverse engineered.
* @param figMessage the message figure where the result will be drawn to
* @param aDiagram the diagram to draw to or null is a new diagram required
*/
public RESequenceDiagramDialog(
final Object oper,
final DiagramElement figMessage,
final ArgoDiagram aDiagram) {
// TODO: don't depend on a Fig (but it is needed to extend an existing
// sequence diagram, i.e. to perform an action on a FigMessage!)
super(
"NOT FUNCTIONAL!!! "
+ Translator.localize(
"dialog.title.reverse-engineer-sequence-diagram")
+ (oper != null
? (' ' + Model.getFacade().getName(oper) + "()")
: ""),
ArgoDialog.OK_CANCEL_OPTION,
true);
setResizable(false);
project = ProjectManager.getManager().getCurrentProject();
operation = oper;
model = project.getUserDefinedModelList().get(0);
// get the Java profile from project, if available
Profile javaProfile = null;
for (Profile profile
: project.getProfileConfiguration().getProfiles()) {
if ("Java".equals(profile.getDisplayName())) {
javaProfile = profile;
}
}
try {
// TODO: must not depend on the Java modeller, but the needed one
// must be either derived from the method's notation, or chosen by
// the user from a list of available language importers
modeller = new Modeller(model, javaProfile, true, true, null);
} catch (Exception ex) {
// the only chance we have is to finish the current operation
LOG.log(Level.WARNING,
"Modeller not ready, so no more generation of calls", ex);
// TODO: Why do we continue here as if nothing has gone wrong?
// Can we really continue correctly without a modeller?
}
classifier = Model.getFacade().getOwner(operation);
if (figMessage != null) {
diagram = aDiagram;
isNewSequenceDiagram = false;
/*
figClassifierRole = getFigClassifierRole(classifier, "obj");
// TODO: There is only a single port on new implementation of SD
// so how do we resolve this?
// Layer layer =
diagram.getLayer();
// TODO: Fix for new sequence diagrams
// portCnt = 0;
// portCnt
// = layer.getNodeIndex(
// figMessage.getDestFigNode().getFigMessagePort().getY());
Iterator<Fig> it = diagram.getFigIterator();
while (it.hasNext()) {
Fig f = it.next();
Object modelElement = f.getOwner();
if (Model.getFacade().isAClassifierRole(modelElement)) {
int x = f.getX();
if (maxXPos < x) {
maxXPos = x;
}
if (Model.getFacade().getName(modelElement)
.startsWith("anon")) {
anonCnt++;
}
} else if (Model.getFacade().isAMessage(modelElement)) {
// TODO: Fix for new sequence diagrams
// int port =
// layer.getNodeIndex(
// ((FigMessage) f).getDestMessageNode()
// .getFigMessagePort().getY());
// if (maxPort < port) {
// maxPort = port;
// }
}
}
*/
} else {
isNewSequenceDiagram = true;
this.diagram = buildSequenceDiagram(classifier);
//figClassifierRole = getFigClassifierRole(classifier, "obj");
//maxXPos = figClassifierRole.getX();
}
parseBody();
JPanel contentPanel = getContentPanel();
setContent(contentPanel);
}
/*
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
if (e.getSource() == getOkButton()) {
//for (int i = 0; i < callTable.getRowCount(); i++) {
// if (Boolean.TRUE.equals(callTable.getValueAt(i, 1))) {
// /*
// buildAction(
// (String) callTable.getValueAt(i, 0),
// figClassifierRole,
// figClassifierRole);
// */
// }
//}
} else if (e.getSource() == getCancelButton()
&& isNewSequenceDiagram) {
// remove SD and clean up everything
Object newTarget = null;
if (ActionDeleteModelElements.sureRemove(diagram)) {
Object collaboration = diagram.getNamespace();
// remove from the model
newTarget = getNewTarget(diagram);
project.moveToTrash(diagram);
project.moveToTrash(collaboration);
}
if (newTarget != null) {
TargetManager.getInstance().setTarget(newTarget);
}
}
}
/*
* @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
*/
public void itemStateChanged(ItemEvent e) {
if (modeChoice.getSelectedIndex() != 1) {
changingPanel.remove(autoPanel);
changingPanel.add(manuPanel, BorderLayout.CENTER);
pack();
} else {
changingPanel.remove(manuPanel);
changingPanel.add(autoPanel, BorderLayout.CENTER);
pack();
}
}
/**
* Gets the object that should be target after the given target is
* deleted from the model.
*
* @param target the target to delete
* @return The object.
*/
private Object getNewTarget(Object target) {
Object newTarget = null;
//if (target instanceof Fig) {
// TODO: common method for getting the model element of a fig
//target = ((Fig) target).getOwner();
//}
if (Model.getFacade().isAModelElement(target)
&& Model.getFacade().getNamespace(target) != null) {
newTarget = Model.getFacade().getNamespace(target);
} else if (target instanceof ArgoDiagram) {
ArgoDiagram firstDiagram = project.getDiagramList().get(0);
if (target != firstDiagram) {
newTarget = firstDiagram;
} else {
if (project.getDiagramList().size() > 1) {
newTarget = project.getDiagramList().get(1);
} else {
newTarget = project.getRoots().iterator().next();
}
}
} else {
newTarget = project.getRoots().iterator().next();
}
return newTarget;
}
/**
* Gets the content panel, containing all the gui.
* @return the constructed panel
*/
private JPanel getContentPanel() {
JPanel content = new JPanel();
content.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.WEST;
constraints.fill =
GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.insets = new Insets(2, 2, 2, 2);
content.add(new JLabel("Mode:"), constraints);
constraints.gridy = 1;
modeChoice = new JComboBox();
modeChoice.addItem("Manually select calls of this operation");
modeChoice.addItem("Traverse calls automatically with a chosen depth");
modeChoice.addItemListener(this);
content.add(modeChoice, constraints);
manuPanel = getManuallyTab();
autoPanel = getAutomaticallyTab();
constraints.gridy = 2;
changingPanel = new JPanel(new BorderLayout(0, 0));
changingPanel.add(manuPanel, BorderLayout.CENTER);
content.add(changingPanel, constraints);
return content;
}
/**
* Gets the panel of the automatically tab.
* @return the constructed panel
*/
private JPanel getAutomaticallyTab() {
JPanel top = new JPanel();
top.setLayout(new GridBagLayout());
GridBagConstraints labelConstraints = new GridBagConstraints();
labelConstraints.anchor = GridBagConstraints.WEST;
labelConstraints.gridy = 0;
labelConstraints.gridx = 0;
labelConstraints.insets = new Insets(10, 2, 2, 2);
GridBagConstraints fieldConstraints = new GridBagConstraints();
fieldConstraints.anchor = GridBagConstraints.WEST;
fieldConstraints.fill = GridBagConstraints.NONE;
fieldConstraints.gridy = 0;
fieldConstraints.gridx = 1;
fieldConstraints.weightx = 1.0;
fieldConstraints.insets = new Insets(4, 2, 2, 2);
JPanel depthPanel = new JPanel(new FlowLayout());
JRadioButton unlimited = new JRadioButton("unlimited");
JRadioButton limited = new JRadioButton("limit to", true);
ButtonGroup group = new ButtonGroup();
group.add(unlimited);
group.add(limited);
depthPanel.add(limited);
depthPanel.add(new JSpinner(new SpinnerNumberModel(1, 0, 999, 1)));
depthPanel.add(unlimited);
labelConstraints.gridy = 0;
fieldConstraints.gridy = 0;
top.add(new JLabel("Depth:"), labelConstraints);
top.add(depthPanel, fieldConstraints);
labelConstraints.gridy = 1;
fieldConstraints.gridy = 1;
top.add(new JLabel("Assumption table:"), labelConstraints);
top.add(new JButton("Update"), fieldConstraints);
List<String> assumptions = new ArrayList<String>();
assumptions.add("calls.hasMoreElements()");
assumptions.add("methods != null && !methods.isEmpty()");
Object[] data = null;
JTable table =
new JTable(new CheckboxTableModel(
assumptions.toArray(),
data,
"Conditions",
"Assume true"));
table.setShowVerticalLines(true);
fieldConstraints.gridx = 0;
fieldConstraints.gridy = 2;
fieldConstraints.gridwidth = 2;
fieldConstraints.anchor = GridBagConstraints.CENTER;
fieldConstraints.fill = GridBagConstraints.BOTH;
fieldConstraints.weighty = 1.0;
top.add(new JScrollPane(table), fieldConstraints);
fieldConstraints.insets = new Insets(0, 2, 0, 2);
JCheckBox checkbox1 = new JCheckBox("also process create calls", true);
fieldConstraints.gridy = 3;
top.add(checkbox1, fieldConstraints);
JCheckBox checkbox2 = new JCheckBox("also process local calls", true);
fieldConstraints.gridy = 4;
top.add(checkbox2, fieldConstraints);
JCheckBox checkbox3 =
new JCheckBox("also process calls inside package", true);
fieldConstraints.gridy = 5;
top.add(checkbox3, fieldConstraints);
return top;
}
/**
* Gets the panel of the manually tab.
*
* @return the constructed panel
*/
private JPanel getManuallyTab() {
JPanel top = new JPanel();
top.setLayout(new GridBagLayout());
GridBagConstraints labelConstraints = new GridBagConstraints();
labelConstraints.anchor = GridBagConstraints.WEST;
labelConstraints.gridx = 0;
labelConstraints.gridy = 0;
labelConstraints.insets = new Insets(10, 2, 2, 2);
GridBagConstraints fieldConstraints = new GridBagConstraints();
fieldConstraints.anchor = GridBagConstraints.WEST;
fieldConstraints.fill = GridBagConstraints.NONE;
fieldConstraints.gridx = 1;
fieldConstraints.gridy = 0;
fieldConstraints.weightx = 1.0;
fieldConstraints.insets = new Insets(4, 2, 2, 2);
top.add(new JLabel("Method call table:"), labelConstraints);
callTable =
new CheckboxTableModel(
calls.toArray(),
calldata.toArray(),
"Method calls",
"Enable");
JTable table = new JTable(callTable);
table.setShowVerticalLines(true);
fieldConstraints.gridx = 0;
fieldConstraints.gridy = 1;
fieldConstraints.gridwidth = 2;
fieldConstraints.anchor = GridBagConstraints.CENTER;
fieldConstraints.fill = GridBagConstraints.BOTH;
fieldConstraints.weighty = 1.0;
top.add(new JScrollPane(table), fieldConstraints);
fieldConstraints.insets = new Insets(0, 2, 0, 2);
JCheckBox checkbox1 = new JCheckBox("(un)check create calls", true);
fieldConstraints.gridy = 2;
top.add(checkbox1, fieldConstraints);
JCheckBox checkbox2 = new JCheckBox("(un)check local calls", true);
fieldConstraints.gridy = 3;
top.add(checkbox2, fieldConstraints);
JCheckBox checkbox3 = new JCheckBox("(un)check package calls", true);
fieldConstraints.gridy = 4;
top.add(checkbox3, fieldConstraints);
JCheckBox checkbox4 = new JCheckBox("(un)check far calls", true);
fieldConstraints.gridy = 5;
top.add(checkbox4, fieldConstraints);
return top;
}
/**
* Builds the sequence diagram for a classifier.<p>
* TODO: find a better place for a similar method.
*/
private ArgoDiagram buildSequenceDiagram(Object theClassifier) {
Object collaboration =
Model.getCollaborationsFactory().buildCollaboration(
Model.getFacade().getNamespace(theClassifier),
theClassifier);
final ArgoDiagram newDiagram =
DiagramFactory.getInstance().createDiagram(
DiagramType.Sequence,
collaboration,
null);
project.addMember(newDiagram);
TargetManager.getInstance().setTarget(newDiagram);
return newDiagram;
}
/**
* Gets or builds the figure of the classifier role for a given classifier
* and object name.<p>
* TODO: Hide this method elsewhere and use it in the implementation of a
* to be defined method (see usage of this method in this class)
*/
/*
private Fig getFigClassifierRole(
Object theClassifier,
String objName) {
Fig crFig = null;
// first check if the fig of the classifier role already exists
Collection coll = diagram.getLayer().getContents();
Iterator iter = coll != null ? coll.iterator() : null;
while (iter != null && iter.hasNext()) {
Object fig = iter.next();
if (fig instanceof Fig) {
Object elem = ((Fig) fig).getOwner();
if (Model.getFacade().isAClassifierRole(elem)) {
// TODO: Do we really need to test for name here
// if we know we have the right classifier role?
if (Model.getFacade().getName(elem).equals(objName)) {
final Collection bases =
Model.getFacade().getBases(elem);
// TODO: Do we really have to test for null here?
// I suspect not, I'd expect an empty collection.
if (bases != null && bases.contains(theClassifier)) {
// yes found, so this will be returned
crFig = (Fig) fig;
break;
}
}
}
}
}
if (crFig == null) {
// classifier role does not exists, so create a new one
Object newClassifierRole =
Model.getCollaborationsFactory()
.buildClassifierRole(diagram.getNamespace());
if (objName != null) {
Model.getCoreHelper().setName(newClassifierRole, objName);
} else {
// TODO: I don't think it's normal to generate model element
// names
Model.getCoreHelper().setName(newClassifierRole,
"anon" + (++anonCnt));
}
coll = new ArrayList<Object>();
coll.add(theClassifier);
Model.getCollaborationsHelper().setBases(newClassifierRole, coll);
crFig = (Fig) diagram.createDiagramElement(
newClassifierRole, DEFAULT_BOUNDS);
// location must be set for correct automatic layouting (how funny)
// otherwise, the new classifier role is not the rightmost
maxXPos += X_OFFSET;
crFig.setLocation(maxXPos, 0);
// TODO: Do we need to do both of these?
diagram.add(crFig);
((MutableGraphModel)
(diagram.getGraphModel())).addNode(newClassifierRole);
// TODO: Send event instead of calling event adapter directly
ExplorerEventAdaptor.getInstance().modelElementChanged(
Model.getFacade().getNamespace(classifier));
}
return crFig;
}
*/
/**
* Parses a body of the actual operation.
*/
private void parseBody() {
JavaLexer lexer = null;
CommonTokenStream tokens = null;
JavaParser parser = null;
calls.clear();
types.clear();
if (modeller != null) {
modeller.clearMethodCalls();
modeller.clearLocalVariableDeclarations();
}
try {
lexer =
new JavaLexer(
new ANTLRStringStream('{' + getBody(operation) + '}'));
tokens = new CommonTokenStream(lexer);
parser = new JavaParser(tokens);
parser.setModeller(modeller);
parser.setParserMode(JavaParser.MODE_REVENG_SEQUENCE);
} catch (Exception ex) {
// the only chance we have is to finish the current operation
LOG.log(Level.WARNING,
"Parser not ready, so no more generation of calls", ex);
}
if (modeller != null && parser != null) {
try {
parser.block();
} catch (Exception ex) {
LOG.log(Level.FINE, "Parsing method body failed:", ex);
}
Collection<String> methodCalls = modeller.getMethodCalls();
if (methodCalls != null) {
calls.addAll(methodCalls);
types.putAll(modeller.getLocalVariableDeclarations());
}
}
}
/**
* Gets the (first) body of an operation.
* TODO: get the right body instead (notation!), else nothing.
*/
private static String getBody(Object operation) {
String body = null;
Collection methods = Model.getFacade().getMethods(operation);
if (methods != null && !methods.isEmpty()) {
Object expression =
Model.getFacade().getBody(methods.iterator().next());
body = (String) Model.getFacade().getBody(expression);
}
if (body == null) {
body = "";
}
return body;
}
/**
* Builds the complete action and its target
* classifier role (if not existing).
* TODO: Put a similar method in a to be defined interface.
*/
/*
private void buildAction(
String call,
Fig startFig,
Fig endFig) {
StringBuffer sb = new StringBuffer(call);
int findpos = sb.lastIndexOf(".");
int createPos = sb.indexOf("new ");
boolean isCreate =
createPos != -1
&& (createPos == 0 || sb.charAt(createPos - 1) == '=');
if (!isCreate && findpos == -1) {
// call of a method of the class
buildEdge(call, startFig, endFig,
Model.getMetaTypes().getCallAction());
} else if (!isCreate
&& findpos <= 5
&& (call.startsWith("super.") || call.startsWith("this."))) {
// also call of a method of the class,
// but prefixed with "super." or "this."
buildEdge(call, startFig, endFig,
Model.getMetaTypes().getCallAction());
} else {
String type = null;
if (isCreate) {
// creator (constructor) call
type = sb.substring(createPos + 4);
String objName =
createPos >= 2 ? sb.substring(0, createPos - 1) : null;
Object cls = getClassifierFromModel(type, objName);
buildEdge(
sb.substring(createPos),
startFig,
getFigClassifierRole(cls, objName),
Model.getMetaTypes().getCreateAction());
} else {
String teststring = call.substring(0, findpos);
type = (String) types.get(teststring);
if (type != null) {
Object cls = getClassifierFromModel(type, teststring);
buildEdge(
call,
startFig,
getFigClassifierRole(cls, teststring),
Model.getMetaTypes().getCallAction());
}
}
// if (type != null) {
// call of a method of a local object
// or call of a static method of a classifier
// } else {
// unknown type
// }
}
}
*/
/**
* Builds the edge figure for an action.<p>
* TODO: Hide this method in the implementation of a to be defined
* interface.
* TODO: When moving it would be better to take model elements rather than
* Figs as arguments here the implementation of that interface suggested
* above can then find the Figs itself without such diagram knowledge being
* in RE.
*/
/*
private void buildEdge(
String call,
Fig startFig,
Fig endFig,
Object callType) {
// TODO: Fix for new sequence diagram implementation
// SequenceDiagramLayer lay = (SequenceDiagramLayer) diagram.getLayer();
// int n = startFig == endFig ? 2 : 1;
// if (portCnt < maxPort) {
// lay.expandDiagram(portCnt + 1, n);
// }
// MessageNode startPort = startFig.getNode(portCnt + 1);
// MessageNode foundPort = endFig.getNode(portCnt + n);
// portCnt += n;
// maxPort += n;
// Fig startPortFig = startFig.getPortFig(startPort);
// Fig destPortFig = endFig.getPortFig(foundPort);
// Object messageType = Model.getMetaTypes().getMessage();
//
// // TODO: This has a bad smell. I don't think we should be using Modes
// // here. Modes are for user interactions.
// // Find a better way to do this.
// Editor ce = Globals.curEditor();
// Hashtable<String, Object> args = new Hashtable<String, Object>();
// args.put("action", callType);
// Mode mode = ce.getModeManager().top();
// mode.setArgs(args);
//
// SequenceDiagramGraphModel graphModel =
// (SequenceDiagramGraphModel) diagram.getGraphModel();
// Object newEdge =
// graphModel.connect(startPort, foundPort, messageType);
// if (null != newEdge) {
// Model.getCoreHelper().setName(newEdge, call);
// final FigMessage figMessage =
// (FigMessage) lay.presentationFor(newEdge);
// figMessage.setSourcePortFig(startPortFig);
// figMessage.setSourceFigNode(startFig);
// figMessage.setDestPortFig(destPortFig);
// figMessage.setDestFigNode(endFig);
// endFig.updateEdges();
// if (startFig != endFig) {
// startFig.updateEdges();
// }
// }
}
*/
// /**
// * Gets or builds a classifier role from a type. The type is a classifier
// * name, either fully qualified (with whole package path) or not.
// * Also ensures that there is an association to the actual classifier.<p>
// * TODO: Hide this method in the implementation of a to be defined
// * interface.
// * TODO: objName is not used. Are there plans for this?
// */
// private Object getClassifierFromModel(
// final String type,
// final String objName) {
// Object theClassifier = null;
// int pos = type.lastIndexOf(".");
// if (pos != -1) {
// // full package path given, so let's get it from the model
// Object namespace = model;
// pos = 0;
// StringTokenizer st = new StringTokenizer(type, ".");
// while (st.hasMoreTokens()) {
// String s = st.nextToken();
// pos += s.length();
// Object element = Model.getFacade().lookupIn(namespace, s);
// if (element == null) {
// // package/classifier is missing, so create one
// if (st.hasMoreTokens()) {
// // must be a package
// element =
// Model.getModelManagementFactory()
// .buildPackage(s);
// } else {
// // must be a classifier, let's assume a class
// element = Model.getCoreFactory().buildClass(s);
// }
// Model.getCoreHelper().setNamespace(element, namespace);
// Model.getCoreHelper().addOwnedElement(namespace, element);
// }
// namespace = element;
// pos++;
// }
// theClassifier = namespace;
// } else {
// // classifier without package information given
// // first, let's look in the namespace of the actual classifier
// Object namespace = Model.getFacade().getNamespace(classifier);
// theClassifier = Model.getFacade().lookupIn(namespace, type);
// if (!Model.getFacade().isAClassifier(theClassifier)) {
// theClassifier = null;
// // let's search for it in the imports (component dependencies)
// Collection sdeps =
// Model.getFacade().getSupplierDependencies(classifier);
// Iterator iter1 = sdeps != null ? sdeps.iterator() : null;
// while (theClassifier == null
// && iter1 != null
// && iter1.hasNext()) {
// Object dep = iter1.next();
// if (Model.getFacade().isADependency(dep)) {
// Collection clients =
// Model.getFacade().getClients(dep);
// Iterator iter2 =
// clients != null ? clients.iterator() : null;
// while (theClassifier == null
// && iter2 != null
// && iter2.hasNext()) {
// Object comp = iter2.next();
// if (Model.getFacade().isAComponent(comp)) {
// theClassifier = permissionLookup(comp, type);
// }
// }
// }
// }
// }
// }
// if (theClassifier == null) {
// // not found any matching classifier, so create one, and put it
// // into the namespace of the actual classifier
// theClassifier = Model.getCoreFactory().buildClass(type);
// Object namespace = Model.getFacade().getNamespace(classifier);
// Model.getCoreHelper().setNamespace(theClassifier, namespace);
// Model.getCoreHelper().addOwnedElement(namespace, theClassifier);
// }
// ensureDirectedAssociation(classifier, theClassifier);
// return theClassifier;
// }
/**
* Checks if there is a directed association between two classifiers, and
* creates one if necessary.<p>
* TODO: Hide this method in the implementation of a to be defined
* interface.
*/
private void ensureDirectedAssociation(Object fromCls, Object toCls) {
String fromName = Model.getFacade().getName(fromCls);
String toName = Model.getFacade().getName(toCls);
Object assocEnd = null;
for (Iterator i =
Model.getFacade().getAssociationEnds(toCls).iterator();
i.hasNext();) {
Object ae = i.next();
Object assoc = Model.getFacade().getAssociation(ae);
if (Model.getFacade().getConnections(assoc).size() == 2
&& Model.getFacade().getType(
Model.getFacade().getNextEnd(ae)) == fromCls
&& Model.getFacade().getName(ae) == null
&& Model.getFacade().isNavigable(ae)) {
assocEnd = ae;
}
}
if (assocEnd == null) {
String assocName = fromName + " -> " + toName;
Modeller.buildDirectedAssociation(assocName, fromCls, toCls);
}
}
/**
* Get the classifier with the given name from a permission
* (null if not found).<p>
* TODO: Hide this method in the implementation of a to be defined
* interface.
*/
private Object permissionLookup(Object comp, String clsName) {
Object theClassifier = null;
// TODO: This could use the new CoreHelper.getPackageImports()
Collection cdeps = Model.getFacade().getClientDependencies(comp);
// TODO: Do we really need to test for null here?
// We should get empty collections.
Iterator iter1 = cdeps != null ? cdeps.iterator() : null;
while (theClassifier == null && iter1 != null && iter1.hasNext()) {
Object perm = iter1.next();
if (Model.getFacade().isAPackageImport(perm)) {
Collection suppliers = Model.getFacade().getSuppliers(perm);
// TODO: Do we really need to test for null here?
// We should get empty collections.
Iterator iter2 =
suppliers != null ? suppliers.iterator() : null;
while (theClassifier == null
&& iter2 != null
&& iter2.hasNext()) {
Object elem = iter2.next();
// TODO: I'm not sure what this is trying to do, but it
// probably isn't what it thinks it is. The supplier to
// an import is going to be a Package, which is not a
// Classifier. Perhaps this intends to process the
// ownedElements of the Package. - tfm - 20070803
if (Model.getFacade().isAClassifier(elem)
&& clsName.equals(Model.getFacade().getName(elem))) {
theClassifier = elem;
}
}
}
}
return theClassifier;
}
}