/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package cb.xmi; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Stack; import ru.novosoft.uml.foundation.core.MAbstraction; import ru.novosoft.uml.foundation.core.MAssociation; import ru.novosoft.uml.foundation.core.MAttribute; import ru.novosoft.uml.foundation.core.MClassifier; import ru.novosoft.uml.foundation.core.MDependency; import ru.novosoft.uml.foundation.core.MGeneralization; import ru.novosoft.uml.foundation.core.MModelElement; import ru.novosoft.uml.foundation.core.MOperation; import ru.novosoft.uml.foundation.core.MUsage; import ru.novosoft.uml.model_management.MModel; import ru.novosoft.uml.model_management.MPackage; import ru.novosoft.uml.xmi.XMIWriter; import cb.petal.Association; import cb.petal.ClassAttribute; import cb.petal.DependencyRelationship; import cb.petal.DescendingVisitor; import cb.petal.InheritanceRelationship; import cb.petal.LogicalCategory; import cb.petal.Module; import cb.petal.Operation; import cb.petal.PetalFile; import cb.petal.PetalObject; import cb.petal.QuidObject; import cb.petal.RealizeRelationship; import cb.petal.SubSystem; import cb.petal.UseCase; import cb.petal.UseCaseCategory; import cb.petal.UsesRelationship; /** * Convert a Rose petal file into the <a href="http://xml.coverpages.org/xmi.html">XMI</a> format using NovoSoft's <a * href="http://nsuml.sourceforge.net/"> NSUML</a> package which implements the entities defined in the <a * href="http://www.omg.org/uml/">UML</a> specification 1.3. * * @version $Id: XMIGenerator.java,v 1.3 2011/09/12 11:47:01 gpolet Exp $ * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> */ public class XMIGenerator extends DescendingVisitor { /** * Where to dump the XMI file */ protected String dump; /** * Which factory to use */ protected XMIFactory factory; /** * The Rose Petal file to convert */ protected PetalFile tree; /** * The XMI model being set up */ protected MModel model; /** * Stack<MPackage> */ Stack packages = new Stack(); /** * The current package level (may be nested) */ MPackage pack; /** * Register created objects by the quid of the petal object. */ protected HashMap quid_map = new HashMap(); // Map<quid, MClassifier> protected HashMap package_map = new HashMap(); // Map<ClassCategory, MPackage> protected final void addObject(String quid, MClassifier obj) { quid_map.put(quid, obj); } protected void removeObject(String quid) { quid_map.remove(quid); } protected final MClassifier getClassifier(String quid) { return (MClassifier) quid_map.get(quid); } /** * @param tree * the Rose petal file to convert * @param dump * where to dump the generated XMI file */ public XMIGenerator(PetalFile tree, String dump) { this.dump = dump; this.tree = tree; factory = getFactory(); model = factory.createModel(); pack = model; } /** * Start generation of XMI code. */ public void start() { /* Run a first pass visitor to add all packages, classes, use * cases, etc. that may be referenced from different places, or * even be referenced in a forward declaration. */ tree.accept(new DescendingVisitor() { private void addPackage(QuidObject obj, MPackage p) { package_map.put(obj, p); pack.addOwnedElement(p); packages.push(pack); // Save old value pack = p; super.visitObject(obj); // Default traversal pack = (MPackage) packages.pop(); } @Override public void visit(LogicalCategory obj) { addPackage(obj, factory.createPackage(obj)); } @Override public void visit(UseCaseCategory obj) { addPackage(obj, factory.createPackage(obj)); } @Override public void visit(SubSystem sub) { /** * ArgoUML can't handle subsystems */ addPackage(sub, factory.createPackage(sub)); } @Override public void visit(cb.petal.Class clazz) { String quid = clazz.getQuid(); MClassifier cl = factory.createClass(clazz); pack.addOwnedElement(cl); addObject(quid, cl); } @Override public void visit(UseCase caze) { String quid = caze.getQuid(); MClassifier cl = factory.createUseCase(caze); pack.addOwnedElement(cl); addObject(quid, cl); } @Override public void visit(Module module) { String quid = module.getQuid(); MClassifier cl = factory.createComponent(module); pack.addOwnedElement(cl); addObject(quid, cl); } }); tree.accept(this); } /** * Override this if you don't like the default factory */ protected XMIFactory getFactory() { return new XMIFactory(tree, this); } private void setPackage(QuidObject obj) { MPackage p = (MPackage) package_map.get(obj); packages.push(pack); // Save old value pack = p; visitObject(obj); // Default traversal pack = (MPackage) packages.pop(); } @Override public void visit(LogicalCategory obj) { setPackage(obj); } @Override public void visit(UseCaseCategory obj) { setPackage(obj); } @Override public void visit(SubSystem obj) { /** * ArgoUML can't handle subsystems */ setPackage(obj); } @Override public void visit(ClassAttribute attr) { MAttribute a = factory.createAttribute(attr); MClassifier clazz = getContainingClassifier(attr); clazz.addFeature(a); } @Override public void visit(Operation op) { MOperation m = factory.createOperation(op); MClassifier clazz = getContainingClassifier(op); clazz.addFeature(m); } @Override public void visit(InheritanceRelationship rel) { MGeneralization gen = factory.createGeneralization(rel); pack.addOwnedElement(gen); } @Override public void visit(UsesRelationship rel) { MUsage usage = factory.createUsage(rel); pack.addOwnedElement(usage); } @Override public void visit(DependencyRelationship rel) { MDependency dependency = factory.createDependency(rel); pack.addOwnedElement(dependency); } @Override public void visit(RealizeRelationship rel) { MAbstraction real = factory.createRealization(rel); pack.addOwnedElement(real); } /** * If this association contains an association class, use that object, otherwise create new object. */ @Override public void visit(Association assoc) { MAssociation a; /* ArgoUML/Poseidon can't handle AssociationClass correctly */ cb.petal.Class clazz = assoc.getAssociationClass(); if (clazz != null) { a = (MAssociation) getClassifier(clazz.getQuid()); factory.setupAssociation(assoc, a); } else { a = factory.createAssociation(assoc); pack.addOwnedElement(a); } } /*************************** Utility method *******************************/ /** * Search for element of given name in model (and all sub-packages) * * @param name * name to look for with getName() * @param clazz * Class searched element is an instance of * @return found element or null */ public MModelElement searchElement(String name, java.lang.Class clazz) { return searchElement(model, name, clazz); } private static MModelElement searchElement(MPackage pack, String name, java.lang.Class clazz) { for (Iterator i = pack.getOwnedElements().iterator(); i.hasNext();) { MModelElement elem = (MModelElement) i.next(); if (name.equals(elem.getName()) && clazz.isInstance(elem)) { return elem; } else if (elem instanceof MPackage) { MModelElement found = searchElement((MPackage) elem, name, clazz); if (found != null) { return found; } } } return null; } /** * @return XMI object for containing class of obj */ protected final MClassifier getContainingClassifier(PetalObject obj) { return getClassifier(((QuidObject) obj.getParent()).getQuid()); } public void dump() throws IOException, ru.novosoft.uml.xmi.IncompleteXMIException { XMIWriter writer = new XMIWriter(model, dump); writer.gen(); } /** * @return generated model */ public MModel getModel() { return model; } /** * @return current package */ public MPackage getPackage() { return pack; } }