Java tutorial
/* * JGraLab - The Java Graph Laboratory * * Copyright (C) 2006-2014 Institute for Software Technology * University of Koblenz-Landau, Germany * ist@uni-koblenz.de * * For bug reports, documentation and further information, visit * * https://github.com/jgralab/jgralab * * This program 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. * * 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 General Public License along * with this program; if not, see <http://www.gnu.org/licenses>. * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with Eclipse (or a modified version of that program or an Eclipse * plugin), containing parts covered by the terms of the Eclipse Public * License (EPL), the licensors of this Program grant you additional * permission to convey the resulting work. Corresponding Source for a * non-source form of such a combination shall include the source code for * the parts of JGraLab used as well as that of the covered work. */ package de.uni_koblenz.jgralab.utilities.rsa2tg; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.HashMap; import java.util.TreeSet; import java.util.regex.Pattern; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionGroup; import de.uni_koblenz.ist.utilities.option_handler.OptionHandler; import de.uni_koblenz.jgralab.EdgeDirection; import de.uni_koblenz.jgralab.GraphIO; import de.uni_koblenz.jgralab.JGraLab; import de.uni_koblenz.jgralab.exception.GraphIOException; import de.uni_koblenz.jgralab.greql.GreqlEnvironment; import de.uni_koblenz.jgralab.greql.GreqlQuery; import de.uni_koblenz.jgralab.greql.evaluator.GreqlEnvironmentAdapter; import de.uni_koblenz.jgralab.grumlschema.GrumlSchema; import de.uni_koblenz.jgralab.grumlschema.SchemaGraph; import de.uni_koblenz.jgralab.grumlschema.domains.BooleanDomain; import de.uni_koblenz.jgralab.grumlschema.domains.CollectionDomain; import de.uni_koblenz.jgralab.grumlschema.domains.Domain; import de.uni_koblenz.jgralab.grumlschema.domains.DoubleDomain; import de.uni_koblenz.jgralab.grumlschema.domains.EnumDomain; import de.uni_koblenz.jgralab.grumlschema.domains.HasRecordDomainComponent; import de.uni_koblenz.jgralab.grumlschema.domains.IntegerDomain; import de.uni_koblenz.jgralab.grumlschema.domains.LongDomain; import de.uni_koblenz.jgralab.grumlschema.domains.MapDomain; import de.uni_koblenz.jgralab.grumlschema.domains.RecordDomain; import de.uni_koblenz.jgralab.grumlschema.domains.StringDomain; import de.uni_koblenz.jgralab.grumlschema.structure.AggregationKind; import de.uni_koblenz.jgralab.grumlschema.structure.Annotates; import de.uni_koblenz.jgralab.grumlschema.structure.Attribute; import de.uni_koblenz.jgralab.grumlschema.structure.AttributedElementClass; import de.uni_koblenz.jgralab.grumlschema.structure.Comment; import de.uni_koblenz.jgralab.grumlschema.structure.Constraint; import de.uni_koblenz.jgralab.grumlschema.structure.ContainsDomain; import de.uni_koblenz.jgralab.grumlschema.structure.ContainsGraphElementClass; import de.uni_koblenz.jgralab.grumlschema.structure.ContainsSubPackage; import de.uni_koblenz.jgralab.grumlschema.structure.EdgeClass; import de.uni_koblenz.jgralab.grumlschema.structure.EndsAt; import de.uni_koblenz.jgralab.grumlschema.structure.GraphClass; import de.uni_koblenz.jgralab.grumlschema.structure.GraphElementClass; import de.uni_koblenz.jgralab.grumlschema.structure.HasAttribute; import de.uni_koblenz.jgralab.grumlschema.structure.HasConstraint; import de.uni_koblenz.jgralab.grumlschema.structure.IncidenceClass; import de.uni_koblenz.jgralab.grumlschema.structure.NamedElement; import de.uni_koblenz.jgralab.grumlschema.structure.Package; import de.uni_koblenz.jgralab.grumlschema.structure.SpecializesEdgeClass; import de.uni_koblenz.jgralab.grumlschema.structure.SpecializesVertexClass; import de.uni_koblenz.jgralab.grumlschema.structure.VertexClass; import de.uni_koblenz.jgralab.utilities.tg2schemagraph.Schema2SchemaGraph; /** * SchemaGraph2XMI is a utility that converts a SchemaGraph or a TG schema file * into a XMI file which can be imported by IBM (tm) Rational Software Architect * (tm). The converter the StAX writer to create the xmi. As intermediate * format, a grUML schema graph is created from the TG schema file. * * @author ist@uni-koblenz.de * */ public class SchemaGraph2XMI { /** * This {@link TreeSet} stores all domains which have to have an entry in * the package PrimitiveTypes, because they are no default attribute types * of UML and have no explicitly defined UML element in the XMI. Those * domains are the LongDomain, the DoubleDomain, all CollectionDomains and * all MapDomains. */ private final TreeSet<Domain> typesToBeDeclaredAtTheEnd = new TreeSet<>(); /** * If set to <code>true</code>, the EdgeClasses are created as associations * which are bidirectional navigable. */ private boolean isBidirectional = false; /** * Processes an TG-file as schema or a schema in a grUML graph to a XMI * file. For all command line options see * {@link Rsa2Tg#processCommandLineOptions(String[])}. * * @param args * {@link String} array of command line options. * @throws GraphIOException */ public static void main(String[] args) throws GraphIOException { System.out.println("SchemaGraph to XMI"); System.out.println("=================="); SchemaGraph2XMI s = new SchemaGraph2XMI(); // Retrieving all command line options CommandLine cli = processCommandLineOptions(args); assert cli != null : "No CommandLine object has been generated!"; s.isBidirectional = cli.hasOption("b"); String outputName = cli.getOptionValue("o"); try { if (cli.hasOption("ig")) { s.process(GrumlSchema.instance().loadSchemaGraph(cli.getOptionValue("ig")), outputName); } else { s.process(new Schema2SchemaGraph() .convert2SchemaGraph(GraphIO.loadSchemaFromFile(cli.getOptionValue("i"))), outputName); } } catch (Exception e) { System.err.println("An Exception occured while processing " + (cli.hasOption("i") ? cli.getOptionValue("i") : cli.getOptionValue("ig")) + "."); System.err.println(e.getMessage()); e.printStackTrace(); e.printStackTrace(); } System.out.println("Fini."); } /** * Processes all command line parameters and returns a {@link CommandLine} * object, which holds all values included in the given {@link String} * array. * * @param args * {@link CommandLine} parameters. * @return {@link CommandLine} object, which holds all necessary values. */ public static CommandLine processCommandLineOptions(String[] args) { // Creates a OptionHandler. String toolString = "java " + SchemaGraph2XMI.class.getName(); String versionString = JGraLab.getInfo(false); OptionHandler oh = new OptionHandler(toolString, versionString); // Several Options are declared. Option output = new Option("o", "output", true, "(required): the output xmi file name"); output.setRequired(true); output.setArgName("file"); oh.addOption(output); Option schemaGraph = new Option("ig", "inputSchemaGraph", true, "(required or -i):if set, the schemaGraph is converted into a xmi."); schemaGraph.setRequired(false); schemaGraph.setArgs(0); output.setArgName("file"); oh.addOption(schemaGraph); Option schema = new Option("i", "inputSchema", true, "(required or -ig): TG-file of the schema which should be converted into a xmi."); schema.setRequired(false); schema.setArgName("file"); oh.addOption(schema); // either graph or schema has to be provided OptionGroup input = new OptionGroup(); input.addOption(schemaGraph); input.addOption(schema); input.setRequired(true); oh.addOptionGroup(input); Option bidirectional = new Option("b", "bidirectional", false, "(optional): If set the EdgeClasses are created as bidirectional associations."); bidirectional.setRequired(false); oh.addOption(bidirectional); return oh.parse(args); } /** * Converts the {@link SchemaGraph} to the XMI file <code>xmiName</code>. * * @param schemaGraph * {@link SchemaGraph} the schema graph to be converted. * @param xmiName * {@link String} the path of the xmi file to be created. * @throws XMLStreamException * @throws IOException */ public void process(SchemaGraph schemaGraph, String xmiName) throws XMLStreamException, IOException { createXMI(xmiName, schemaGraph); } /** * This method creates the XMI file. Created content is:<br/> * <code><?xml version="{@link XMIConstants4SchemaGraph2XMI#XML_VERSION}" encoding="{@link XMIConstants4SchemaGraph2XMI#XML_ENCODING}"?><br/> * <!-- content created by {@link SchemaGraph2XMI#createRootElement(XMLStreamWriter, SchemaGraph)} --> * </code> * * @param xmiName * {@link String} the path of the XMI file * @param schemaGraph * {@link SchemaGraph} to be converted into an XMI * @throws XMLStreamException * @throws IOException */ private void createXMI(String xmiName, SchemaGraph schemaGraph) throws XMLStreamException, IOException { Writer out = null; XMLStreamWriter writer = null; try { // create the XMLStreamWriter which creates the current xmi-file. out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(xmiName), "UTF-8")); XMLOutputFactory factory = XMLOutputFactory.newInstance(); factory.setProperty("javax.xml.stream.isRepairingNamespaces", Boolean.TRUE); writer = factory.createXMLStreamWriter(out); // write the first line writer.writeStartDocument(XMIConstants4SchemaGraph2XMI.XML_ENCODING, XMIConstants4SchemaGraph2XMI.XML_VERSION); createRootElement(writer, schemaGraph); // write the end of the document writer.writeEndDocument(); // close the XMLStreamWriter writer.flush(); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { // no handling of exceptions, because they are throw as mentioned in // the declaration. if (writer != null) { writer.close(); } if (out != null) { out.close(); } } } /** * Creates the root <code>XMI</code> tag of the whole document. It calls * {@link SchemaGraph2XMI#createModelElement(XMLStreamWriter, SchemaGraph)} * to create its content. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param schemaGraph * {@link SchemaGraph} to be converted into an XMI * @throws XMLStreamException */ private void createRootElement(XMLStreamWriter writer, SchemaGraph schemaGraph) throws XMLStreamException { // start root element writer.writeStartElement(XMIConstants4SchemaGraph2XMI.NAMESPACE_PREFIX_XMI, XMIConstants4SchemaGraph2XMI.XMI_TAG_XMI, XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_VERSION, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_VERSION_VALUE); writer.setPrefix(XMIConstants4SchemaGraph2XMI.NAMESPACE_PREFIX_XSI, XMIConstants4SchemaGraph2XMI.NAMESPACE_XSI); writer.setPrefix(XMIConstants4SchemaGraph2XMI.NAMESPACE_PREFIX_EECORE, XMIConstants4SchemaGraph2XMI.NAMESPACE_EECORE); writer.setPrefix(XMIConstants4SchemaGraph2XMI.NAMESPACE_PREFIX_ECORE, XMIConstants4SchemaGraph2XMI.NAMESPACE_ECORE); writer.setPrefix(XMIConstants4SchemaGraph2XMI.NAMESPACE_PREFIX_UML, XMIConstants4SchemaGraph2XMI.NAMESPACE_UML); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XSI, XMIConstants4SchemaGraph2XMI.XSI_ATTRIBUTE_SCHEMALOCATION, XMIConstants4SchemaGraph2XMI.SCHEMALOCATION); // create model element createModelElement(writer, schemaGraph); // close root element writer.writeEndElement(); } /** * Creates the <code>Model</code> tag and its content consisting of * <ul> * <li>the {@link GraphClass},</li> * <li>the defaultPackage and its content,</li> * <li>the representation of the domains in * {@link SchemaGraph2XMI#typesToBeDeclaredAtTheEnd} and</li> * <li>and the profile application</li> * </ul> * by calling the corresponding methods. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param schemaGraph * {@link SchemaGraph} to be converted into an XMI * @throws XMLStreamException */ private void createModelElement(XMLStreamWriter writer, SchemaGraph schemaGraph) throws XMLStreamException { de.uni_koblenz.jgralab.grumlschema.structure.Schema schema = schemaGraph.getFirstSchema(); // start model writer.writeStartElement(XMIConstants4SchemaGraph2XMI.NAMESPACE_UML, XMIConstants4SchemaGraph2XMI.UML_TAG_MODEL); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, schema.get_packagePrefix() + "." + schema.get_name()); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, schema.get_packagePrefix() + "." + schema.get_name()); // convert graph class createAttributedElementClass(writer, schemaGraph.getFirstGraphClass()); createPackage(writer, (Package) schemaGraph.getFirstSchema().getFirstContainsDefaultPackageIncidence().getThat()); // create Types if (!typesToBeDeclaredAtTheEnd.isEmpty()) { createTypes(writer); } // create profileApplication createProfileApplication(writer); // end model writer.writeEndElement(); } /** * This method creates the representation of: * <ul> * <li>the {@link Package} <code>pack</code>, if it is not the * defaultPackage,</li> * <li>{@link Comment}s which are attached to <code>pack</code>,</li> * <li>{@link EnumDomain}s,</li> * <li>{@link RecordDomain}s,</li> * <li>{@link GraphElementClass}es and</li> * <li>{@link Package}s</li> * </ul> * contained in <code>pack</code>. The creation of other {@link Domain}s * except {@link EnumDomain}s and {@link RecordDomain}s are explained at * {@link SchemaGraph2XMI#createAttribute(XMLStreamWriter, String, String, Domain, String)} * . * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param pack * {@link Package} the current {@link Package} * @throws XMLStreamException */ private void createPackage(XMLStreamWriter writer, Package pack) throws XMLStreamException { boolean packageTagHasToBeClosed = false; if (!isPackageEmpty(pack)) { if (!pack.get_qualifiedName().equals(de.uni_koblenz.jgralab.schema.Package.DEFAULTPACKAGE_NAME)) { // for the default package there is not created a package tag packageTagHasToBeClosed = pack.getFirstAnnotatesIncidence() != null || pack.getFirstContainsDomainIncidence() != null || pack.getFirstContainsGraphElementClassIncidence() != null || pack.getFirstContainsSubPackageIncidence(EdgeDirection.OUT) != null; if (packageTagHasToBeClosed) { // start package writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); } else { // create empty package writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); } writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_TYPE_VALUE_PACKAGE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, pack.get_qualifiedName()); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, extractSimpleName(pack.get_qualifiedName())); } // create comments createComments(writer, pack); // create domains for (ContainsDomain cd : pack.getContainsDomainIncidences()) { Domain domain = (Domain) cd.getThat(); if (!domain.get_qualifiedName() .equals(de.uni_koblenz.jgralab.schema.BooleanDomain.BOOLEANDOMAIN_NAME) && !domain.get_qualifiedName() .equals(de.uni_koblenz.jgralab.schema.DoubleDomain.DOUBLEDOMAIN_NAME) && !domain.get_qualifiedName() .equals(de.uni_koblenz.jgralab.schema.IntegerDomain.INTDOMAIN_NAME) && !domain.get_qualifiedName() .equals(de.uni_koblenz.jgralab.schema.LongDomain.LONGDOMAIN_NAME) && !domain.get_qualifiedName() .equals(de.uni_koblenz.jgralab.schema.StringDomain.STRINGDOMAIN_NAME)) { // skip basic domains if (domain instanceof EnumDomain) { createEnum(writer, (EnumDomain) domain); } else if (domain instanceof RecordDomain) { createRecordDomain(writer, (RecordDomain) domain); } } } // create GraphElementClasses for (ContainsGraphElementClass cgec : pack.getContainsGraphElementClassIncidences()) { GraphElementClass gec = (GraphElementClass) cgec.getThat(); createAttributedElementClass(writer, gec); } // create subpackages for (ContainsSubPackage csp : pack.getContainsSubPackageIncidences(EdgeDirection.OUT)) { // create subpackages createPackage(writer, (Package) csp.getThat()); } if (packageTagHasToBeClosed) { // close packagedElement writer.writeEndElement(); } } } /** * Returns <code>true</code> if the {@link Package} <code>pack</code> does * not contain a {@link Comment}, a {@link Domain}, a * {@link GraphElementClass} and no nonempty {@link Package}. Otherwise * <code>false</code> is returned. * * @param pack * {@link Package} the current {@link Package} * @return boolean */ private boolean isPackageEmpty(Package pack) { boolean isPackageEmpty = pack.getFirstAnnotatesIncidence() == null && pack.getFirstContainsDomainIncidence() == null && pack.getFirstContainsGraphElementClassIncidence() == null; if (!isPackageEmpty) { return false; } else { for (ContainsSubPackage csp : pack.getContainsSubPackageIncidences(EdgeDirection.OUT)) { if (!isPackageEmpty((Package) csp.getThat())) { return false; } } return true; } } /** * Creates the representation of the {@link RecordDomain} * <code>recordDomain</code>. This representation consists of an UML class * with stereotype <code><<record>></code>. The components of * <code>recordDomain</code> are represented as attributes of the generated * UML class. Further more all {@link Comment}s attached to * <code>recordDomain</code> are created. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param recordDomain * {@link RecordDomain} the current {@link RecordDomain} * @throws XMLStreamException */ private void createRecordDomain(XMLStreamWriter writer, RecordDomain recordDomain) throws XMLStreamException { // start packagedElement writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_TYPE_VALUE_CLASS); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, recordDomain.get_qualifiedName()); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, extractSimpleName(recordDomain.get_qualifiedName())); // create stereotype <<record>> createExtension(writer, recordDomain, "record"); // create comments createComments(writer, recordDomain); // create attributes for (HasRecordDomainComponent hrdc : recordDomain .getHasRecordDomainComponentIncidences(EdgeDirection.OUT)) { createAttribute(writer, hrdc.get_name(), null, (Domain) hrdc.getThat(), recordDomain.get_qualifiedName() + "_" + hrdc.get_name()); } // end packagededElement writer.writeEndElement(); } /** * Creates the representation of the {@link EnumDomain} * <code>EnumDomain</code>. This representation is a UML enumeration with * stereotype <code><<record>></code>. The constants of * <code>enumDomain</code> are represented as constants of the generated UML * enumeration. Further more all {@link Comment}s attached to * <code>enumDomain</code> are created. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param enumDomain * {@link EnumDomain} the current {@link EnumDomain} * @throws XMLStreamException */ private void createEnum(XMLStreamWriter writer, EnumDomain enumDomain) throws XMLStreamException { // start packagedElement writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_TYPE_VALUE_ENUMERATION); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, enumDomain.get_qualifiedName()); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, extractSimpleName(enumDomain.get_qualifiedName())); // create comments createComments(writer, enumDomain); // create enumeration constants for (String enumConst : enumDomain.get_enumConstants()) { // create ownedLiteral writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_OWNEDLITERAL); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.OWNEDLITERAL_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, enumDomain.get_qualifiedName() + "_" + enumConst); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, enumConst); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.OWNEDLITERAL_ATTRIBUTE_CLASSIFIER, enumDomain.get_qualifiedName()); } // end packagedElement writer.writeEndElement(); } /** * Creates the profileApplication tag at the end of the model tag. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @throws XMLStreamException */ private void createProfileApplication(XMLStreamWriter writer) throws XMLStreamException { // start profileApplication writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_PROFILEAPPLICATION); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PROFILEAPPLICATION_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, XMIConstants4SchemaGraph2XMI.TAG_PROFILEAPPLICATION + System.currentTimeMillis()); // create content createExtension(writer, null, null); // create appliedProfile writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_APPLIEDPROFILE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.APPLIEDPROFILE_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_HREF, XMIConstants4SchemaGraph2XMI.APPLIEDPROFILE_HREF_VALUE); // end profileApplication writer.writeEndElement(); } /** * Defines all attributes of type {@link DoubleDomain}, {@link LongDomain}, * {@link MapDomain} or {@link CollectionDomain} which are used in the * {@link SchemaGraph} i.e. contained in * {@link SchemaGraph2XMI#typesToBeDeclaredAtTheEnd}. These definitions are * created in a new UML package, called <code>PrimitiveTypes</code>. This is * necessary because those {@link Domain}s are not UML primitive types and * are not represented by an own <code>packagedElement</code> in the XMI * file. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @throws XMLStreamException */ private void createTypes(XMLStreamWriter writer) throws XMLStreamException { // start packagedElement writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_TYPE_VALUE_PACKAGE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, XMIConstants4SchemaGraph2XMI.PACKAGE_PRIMITIVETYPES_NAME); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, XMIConstants4SchemaGraph2XMI.PACKAGE_PRIMITIVETYPES_NAME); // create entries for domains, which are not defined for (Domain domain : typesToBeDeclaredAtTheEnd) { writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_PRIMITIVETYPE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, domain.get_qualifiedName().replaceAll("\\s", "").replaceAll("<", "_").replaceAll(">", "_")); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, extractSimpleName(domain.get_qualifiedName())); } // end packagedElement writer.writeEndElement(); } /** * Creates the representation of the {@link AttributedElementClass} * <code>aeclass</code>.<br /> * A {@link GraphClass} is represented as a UML class with stereotype * <code><<graphclass>></code>.<br /> * A {@link VertexClass} is represented as a UML class.<br /> * An {@link EdgeClass} is represented as a UML association, if it has no * attributes and otherwise as a UML associationClass.<br /> * Furthermore the attribute abstract is generated, if the * {@link VertexClass} or {@link EdgeClass} is abstract. {@link Comment}s, * {@link Constraint}s, generalization and {@link Attribute}s are * represented as well.<br /> * The {@link IncidenceClass} representations are created if needed. To get * more information if it is needed, have a look at * {@link SchemaGraph2XMI#createIncidences(XMLStreamWriter, EdgeClass)} and * {@link SchemaGraph2XMI#createIncidences(XMLStreamWriter, VertexClass)}. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param aeclass * {@link AttributedElementClass} the current * {@link AttributedElementClass} * @throws XMLStreamException */ private void createAttributedElementClass(XMLStreamWriter writer, AttributedElementClass aeclass) throws XMLStreamException { // if aeclass is a GraphElementClass without any attributes, comments // and constraints then an empty tag is created. Furthermore an // EdgeClass could only be empty if the associations are created // bidirectional. boolean isEmptyGraphElementClass = aeclass.getFirstAnnotatesIncidence() == null && aeclass.getFirstHasAttributeIncidence() == null && aeclass.getFirstHasConstraintIncidence() == null && (aeclass instanceof GraphElementClass && !((GraphElementClass) aeclass).is_abstract()) && (aeclass instanceof VertexClass && ((VertexClass) aeclass) .getFirstSpecializesVertexClassIncidence(EdgeDirection.OUT) == null && !hasChildIncidence((VertexClass) aeclass) || aeclass instanceof EdgeClass && ((EdgeClass) aeclass) .getFirstSpecializesEdgeClassIncidence(EdgeDirection.OUT) == null && isBidirectional); // start packagedElement if (isEmptyGraphElementClass) { writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); } else { writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_PACKAGEDELEMENT); } // set type if (aeclass instanceof EdgeClass) { if (aeclass.getFirstHasAttributeIncidence() == null) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_TYPE_VALUE_ASSOCIATION); } else { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_TYPE_VALUE_ASSOCIATIONCLASS); } } else { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_TYPE_VALUE_CLASS); } writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, aeclass.get_qualifiedName()); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, extractSimpleName(aeclass.get_qualifiedName())); // set EdgeClass specific memberEnd if (aeclass instanceof EdgeClass) { EdgeClass ec = (EdgeClass) aeclass; writer.writeAttribute(XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_ATTRIBUTE_MEMBEREND, ((VertexClass) ((IncidenceClass) ec.getFirstComesFromIncidence().getThat()) .getFirstEndsAtIncidence().getThat()).get_qualifiedName() + "_incidence_" + ec.get_qualifiedName() + "_from " + ((VertexClass) ((IncidenceClass) ec.getFirstGoesToIncidence().getThat()) .getFirstEndsAtIncidence().getThat()).get_qualifiedName() + "_incidence_" + ec.get_qualifiedName() + "_to"); } // set abstract if (aeclass instanceof GraphElementClass && ((GraphElementClass) aeclass).is_abstract()) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_ATTRIBUTE_ISABSTRACT, XMIConstants4SchemaGraph2XMI.ATTRIBUTE_VALUE_TRUE); createExtension(writer, aeclass, "abstract"); } // create <<graphclass>> for graph classes if (aeclass instanceof GraphClass) { createExtension(writer, aeclass, "graphclass"); } // create comments createComments(writer, aeclass); // create constraints createConstraints(writer, aeclass); // create generalization if (aeclass instanceof VertexClass) { for (SpecializesVertexClass svc : ((VertexClass) aeclass) .getSpecializesVertexClassIncidences(EdgeDirection.OUT)) { createGeneralization(writer, "generalization_" + aeclass.get_qualifiedName(), ((VertexClass) svc.getThat()).get_qualifiedName()); } } else if (aeclass instanceof EdgeClass) { for (SpecializesEdgeClass svc : ((EdgeClass) aeclass) .getSpecializesEdgeClassIncidences(EdgeDirection.OUT)) { createGeneralization(writer, "generalization_" + aeclass.get_qualifiedName(), ((EdgeClass) svc.getThat()).get_qualifiedName()); } } // create attributes createAttributes(writer, aeclass); // create incidences of EdgeClasses at VertexClass aeclass if (aeclass instanceof VertexClass) { createIncidences(writer, (VertexClass) aeclass); } else if (aeclass instanceof EdgeClass) { createIncidences(writer, (EdgeClass) aeclass); } // close packagedElement if (!isEmptyGraphElementClass) { writer.writeEndElement(); } } /** * Returns <code>true</code>, iff there has to be created an incidence child * in the XMI file for <code>vertexClass</code>. Otherwise * <code>false</code> is returned. * * @param vertexClass * {@link VertexClass} to be checked * @return boolean */ private boolean hasChildIncidence(VertexClass vertexClass) { if (vertexClass.getFirstEndsAtIncidence() == null) { // VertexClass has no incidences return false; } for (EndsAt ea : vertexClass.getEndsAtIncidences()) { IncidenceClass ic = (IncidenceClass) ea.getThat(); if (hasToBeCreatedAtVertex(ic)) { return true; } } return false; } /** * Returns <code>true</code>, iff the <code>incidence</code> has to be * created at the {@link VertexClass} VC, to which <code>incidence</code> is * connected via an {@link EndsAt} edge. This is the case if * <ul> * <li>{@link SchemaGraph2XMI#isBidirectional} is set to <code>true</code>,</li> * <li>{@link SchemaGraph2XMI#isReverted} is set to <code>false</code> and * VC is the alpha {@link VertexClass} of the {@link EdgeClass} to which * <code>incidence</code> belongs or</li> * <li>{@link SchemaGraph2XMI#isReverted} is set to <code>true</code> and VC * is the omega {@link VertexClass} of the {@link EdgeClass} to which * <code>incidence</code> belongs.</li> * </ul> * Otherwise <code>false</code> is returned. * * @param incidence * {@link IncidenceClass} to be checked * @return boolean */ private boolean hasToBeCreatedAtVertex(IncidenceClass incidence) { boolean isAlphaVertexClass = incidence.getFirstComesFromIncidence() != null; if (isBidirectional) { // in the case of bidirectional edges, all incidences have to be // created at the vertices return true; } else { if (isAlphaVertexClass) { // the edge has a navigable incidence (aeclass-->otherEnd) return true; } } return false; } /** * Creates the representation for the alpha and omega {@link IncidenceClass} * of <code>edgeClass</code> if it wasn't already created at the * corresponding {@link VertexClass} (e.g. if * {@link SchemaGraph2XMI#hasToBeCreatedAtVertex(IncidenceClass)} returns * <code>false</code>). * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param edgeClass * {@link EdgeClass} of which the {@link IncidenceClass}es have * to be represented. * @throws XMLStreamException */ private void createIncidences(XMLStreamWriter writer, EdgeClass edgeClass) throws XMLStreamException { IncidenceClass alphaIncidence = (IncidenceClass) edgeClass.getFirstComesFromIncidence().getThat(); IncidenceClass omegaIncidence = (IncidenceClass) edgeClass.getFirstGoesToIncidence().getThat(); VertexClass alphaVertex = (VertexClass) alphaIncidence.getFirstEndsAtIncidence().getThat(); VertexClass omegaVertex = (VertexClass) omegaIncidence.getFirstEndsAtIncidence().getThat(); // create incidence which contains the information for the alpha // vertex (=omegaIncidence) if (!hasToBeCreatedAtVertex(alphaIncidence)) { createIncidence(writer, omegaIncidence, edgeClass, alphaIncidence, omegaVertex, alphaVertex.get_qualifiedName(), true); } // create incidence which contains the information for the omega // vertex (=alphaIncidence) if (!hasToBeCreatedAtVertex(omegaIncidence)) { createIncidence(writer, alphaIncidence, edgeClass, omegaIncidence, alphaVertex, omegaVertex.get_qualifiedName(), true); } } /** * Creates the representation of all {@link IncidenceClass}es which are * connected to <code>vertexClass</code> if * {@link SchemaGraph2XMI#hasToBeCreatedAtVertex(IncidenceClass)} returns * <code>true</code>. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param vertexClass * {@link VertexClass} of which the connected * {@link IncidenceClass}es are represented * @throws XMLStreamException */ private void createIncidences(XMLStreamWriter writer, VertexClass vertexClass) throws XMLStreamException { for (EndsAt ea : vertexClass.getEndsAtIncidences()) { // find incident EdgeClass and adjacent VertexClass IncidenceClass incidence = (IncidenceClass) ea.getThat(); if (hasToBeCreatedAtVertex(incidence)) { boolean isVertexClassAlphaVertex = incidence.getFirstComesFromIncidence() != null; EdgeClass edgeClass = (EdgeClass) (isVertexClassAlphaVertex ? incidence.getFirstComesFromIncidence() : incidence.getFirstGoesToIncidence()).getThat(); IncidenceClass otherIncidence = (IncidenceClass) (isVertexClassAlphaVertex ? edgeClass.getFirstGoesToIncidence() : edgeClass.getFirstComesFromIncidence()).getThat(); VertexClass connectedVertexClass = (VertexClass) otherIncidence.getFirstEndsAtIncidence().getThat(); // create incidence representation createIncidence(writer, otherIncidence, edgeClass, incidence, connectedVertexClass, vertexClass.get_qualifiedName(), false); } } } /** * Creates the representation of the {@link IncidenceClass} which contains * the information for the {@link VertexClass} which is specified by * <code>qualifiedNameOfVertexClass</code> e.g. <code>otherIncidence</code>.<br/> * The relevant information are: <ui> <li>the rolename,</li> <li>the min * value,</li> <li>the max value and</li> <li>composition or shared * information.</li> </ui> The default rolename for associations is * <code>qualifiedNameOfVertexClass_edgeClass.getQualifiedName()</code> and * <code>""</code> for associationClasses. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param otherIncidence * {@link IncidenceClass} which contains the information for the * incidence corresponding to the {@link VertexClass} of * <code>qualifiedNameOfVertexClass</code> in the xmi file. * @param connectedVertexClass * {@link VertexClass} at the other end of <code>edgeClass</code> * @param incidence * {@link IncidenceClass} connected to the {@link VertexClass} * specified by <code>qualifiedNameOfVertexClass</code> * @param edgeClass * {@link EdgeClass} which connects the {@link VertexClass} * specified by <code>qualifiedNameOfVertexClass</code> with * <code>connectedVertexClass</code> * @param qualifiedNameOfVertexClass * {@link String} the qualified name of the {@link VertexClass} * to which <code>incidence</code> is connected to. * @param createOwnedEnd * boolean if set to <code>true</code>, the tag ownedEnd is used * instead of ownedAttribute (ownedEnd has to be created, if you * create an incidence at an association.) * @throws XMLStreamException */ private void createIncidence(XMLStreamWriter writer, IncidenceClass otherIncidence, EdgeClass edgeClass, IncidenceClass incidence, VertexClass connectedVertexClass, String qualifiedNameOfVertexClass, boolean createOwnedEnd) throws XMLStreamException { String incidenceId = qualifiedNameOfVertexClass + "_incidence_" + edgeClass.get_qualifiedName() + (incidence.getFirstComesFromIncidence() != null ? "_from" : "_to"); // start ownedattribute writer.writeStartElement(createOwnedEnd ? XMIConstants4SchemaGraph2XMI.TAG_OWNEDEND : XMIConstants4SchemaGraph2XMI.TAG_OWNEDATTRIBUTE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, incidenceId); // set rolenames if (otherIncidence.get_roleName() != null && !otherIncidence.get_roleName().isEmpty()) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, otherIncidence.get_roleName()); } else if (isRoleNameNecessary(edgeClass, connectedVertexClass.get_qualifiedName())) { String newRoleName = createNewUniqueRoleName(connectedVertexClass); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, newRoleName); // to find already used rolenames set the newly created rolename otherIncidence.set_roleName(newRoleName); } writer.writeAttribute(XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_ATTRIBUTE_VISIBILITY, XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_VISIBILITY_VALUE_PRIVATE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_ATTRIBUTE_TYPE, connectedVertexClass.get_qualifiedName()); // set composite or shared if (otherIncidence.get_aggregation() == AggregationKind.SHARED) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_ATTRIBUTE_AGGREGATION, XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_ATTRIBUTE_AGGREGATION_VALUE_SHARED); } else if (otherIncidence.get_aggregation() == AggregationKind.COMPOSITE) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_ATTRIBUTE_AGGREGATION, XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_ATTRIBUTE_AGGREGATION_VALUE_COMPOSITE); } writer.writeAttribute(XMIConstants4SchemaGraph2XMI.PACKAGEDELEMENT_ATTRIBUTE_ASSOCIATION, edgeClass.get_qualifiedName()); // create upperValue writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_UPPERVALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_LITERALUNLIMITEDNATURAL); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, incidenceId + "_uppervalue"); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_VALUE, otherIncidence.get_max() == Integer.MAX_VALUE ? "*" : Integer.toString(otherIncidence.get_max())); // create lowerValue writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_LOWERVALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_LITERALINTEGER); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, incidenceId + "_lowervalue"); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_VALUE, incidence.get_min() == Integer.MAX_VALUE ? "*" : Integer.toString(otherIncidence.get_min())); // close ownedattribute writer.writeEndElement(); } /** * Find a new rolename which lets the new {@link Schema} still be * consistent. * * @param connectedVertexClass * {@link VertexClass} for which the new rolename should be * created * @return String the new rolename */ private String createNewUniqueRoleName(VertexClass connectedVertexClass) { String baseRolename = connectedVertexClass.get_qualifiedName().replaceAll(Pattern.quote("."), "_"); // ensure that the rolename starts with an lower case letter if (Character.isUpperCase(baseRolename.charAt(0))) { baseRolename = Character.toLowerCase(baseRolename.charAt(0)) + baseRolename.substring(1); } // find a unique rolename HashMap<String, Object> boundVars = new HashMap<>(); boundVars.put("start", connectedVertexClass); int counter = 0; Object result; do { counter++; GreqlQuery query = GreqlQuery.createQuery("using start:" + "exists ic:start<->{structure.SpecializesVertexClass}*<->{structure.EndsAt}<->{structure.ComesFrom,structure.GoesTo}^2@ic.roleName=\"" + baseRolename + (counter == 1 ? "" : counter) + "\""); GreqlEnvironment environment = new GreqlEnvironmentAdapter(boundVars); result = query.evaluate(connectedVertexClass.getGraph(), environment); } while (result instanceof Boolean ? (Boolean) result : false); return baseRolename + (counter == 1 ? "" : counter); } /** * Checks if the there have to be a rolename. If the {@link EdgeClass} * <code>edgeClass</code> is bidirectional navigable both rolenames have to * exist. If it is only navigable in one direction the navigable * {@link IncidenceClass} has to have an existing rolename. The other not. * * @param edgeClass * {@link EdgeClass} * @param qualifiedName * {@link String} the qualified name of the {@link VertexClass} * for which the existing of a rolename should be checked * @return boolean */ private boolean isRoleNameNecessary(EdgeClass edgeClass, String qualifiedName) { if (isBidirectional) { // the association is bidirectionally navigable return true; } else if (((VertexClass) ((IncidenceClass) edgeClass.getFirstGoesToIncidence().getThat()) .getFirstEndsAtIncidence().getThat()).get_qualifiedName().equals(qualifiedName)) { // if it is not reverted // the omega IncidenceClass of the EdgeClass must have a rolename return true; } else { return false; } } private void createGeneralization(XMLStreamWriter writer, String id, String idOfSpecializedClass) throws XMLStreamException { // create generalization writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_GENERALIZATION); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.GENERALIZATION_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, id); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.GENERALIZATION_ATTRIBUTE_GENERAL, idOfSpecializedClass); } /** * This method creates an <code>extension</code> tag. It is used in profile * application and to create stereotypes of the form * <code><<keyValue>></code>. In the first case a * <code>references</code> child is created in the other a * <code>details</code> child. To create the first one <code>nelement</code> * has to be <code>null</code>. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param nelement * {@link NamedElement} if null <code>references</code> is * created otherwise the stereotype <code>keyValue</code>. * @param keyValue * {@link String} the stereotype to be created * @throws XMLStreamException */ private void createExtension(XMLStreamWriter writer, NamedElement nelement, String keyValue) throws XMLStreamException { // start Extension writer.writeStartElement(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_TAG_EXTENSION); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_EXTENDER, XMIConstants4SchemaGraph2XMI.NAMESPACE_ECORE); // start eAnnotations writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_EANNOTATIONS); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.EANNOTATIONS_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, nelement != null ? nelement.get_qualifiedName() + "_" + XMIConstants4SchemaGraph2XMI.TAG_EANNOTATIONS : XMIConstants4SchemaGraph2XMI.TAG_EANNOTATIONS + System.currentTimeMillis()); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.EANNOTATIONS_ATTRIBUTE_SOURCE, XMIConstants4SchemaGraph2XMI.EANNOTATIONS_ATTRIBUTE_SOURCE_VALUE); if (nelement != null) { // write details writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_DETAILS); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.DETAILS_ATTRIBUTE_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, nelement.get_qualifiedName() + "_" + XMIConstants4SchemaGraph2XMI.TAG_DETAILS); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.DETAILS_ATTRIBUTE_KEY, keyValue); } else { // write references writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_REFERENCES); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.REFERENCES_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_HREF, XMIConstants4SchemaGraph2XMI.REFERENCES_HREF_VALUE); } // close eAnnotations writer.writeEndElement(); // close Extension writer.writeEndElement(); } /** * Creates the representation of all {@link Attribute}s of * <code>aeclass</code>. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param aeclass * {@link AttributedElementClass} of which all {@link Attribute}s * are created * @throws XMLStreamException */ private void createAttributes(XMLStreamWriter writer, AttributedElementClass aeclass) throws XMLStreamException { for (HasAttribute hasAttribute : aeclass.getHasAttributeIncidences()) { Attribute attribute = (Attribute) hasAttribute.getThat(); createAttribute(writer, attribute.get_name(), attribute.get_defaultValue(), (Domain) attribute.getFirstHasDomainIncidence().getThat(), aeclass.get_qualifiedName() + "_" + ((Attribute) hasAttribute.getThat()).get_name()); } } /** * Creates the representation of an {@link Attribute}. The represented * information are the name, the default value and the type. <br/> * If the {@link Attribute} is of type LongDomain, a DoubleDomain, a * CollectionDomain or a MapDomain the type is stored in * {@link SchemaGraph2XMI#typesToBeDeclaredAtTheEnd} because there has to be * created a representation in the primitive types package. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param attributeName * {@link String} the name of the current {@link Attribute} * @param defaultValue * {@link String} the default value of the current * {@link Attribute} * @param domain * {@link Domain} of the current {@link Attribute} * @param id * {@link String} the id of the tag which represents the current * {@link Attribute} * @throws XMLStreamException */ private void createAttribute(XMLStreamWriter writer, String attributeName, String defaultValue, Domain domain, String id) throws XMLStreamException { boolean hasDefaultValue = defaultValue != null && !defaultValue.isEmpty(); // start ownedAttribute if (!hasDefaultValue && !(domain instanceof BooleanDomain || domain instanceof IntegerDomain || domain instanceof StringDomain)) { writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_OWNEDATTRIBUTE); } else { writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_OWNEDATTRIBUTE); } writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, id); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, attributeName); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_ATTRIBUTE_VISIBILITY, XMIConstants4SchemaGraph2XMI.OWNEDATTRIBUTE_VISIBILITY_VALUE_PRIVATE); // create type if (domain instanceof BooleanDomain || domain instanceof IntegerDomain || domain instanceof StringDomain) { createType(writer, domain); } else { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, domain.get_qualifiedName().replaceAll("\\s", "").replaceAll("<", "_").replaceAll(">", "_")); } // create default value if (hasDefaultValue) { createDefaultValue(writer, defaultValue, id, domain); } if (hasDefaultValue || domain instanceof BooleanDomain || domain instanceof IntegerDomain || domain instanceof StringDomain) { // end ownedAttribute writer.writeEndElement(); } // if domain is a LongDomain, a DoubleDomain, a CollectionDomain or a // MapDomain there has to be created an entry in the package // PrimitiveTypes if (domain instanceof LongDomain || domain instanceof DoubleDomain || domain instanceof CollectionDomain || domain instanceof MapDomain) { typesToBeDeclaredAtTheEnd.add(domain); } } /** * Creates the default values. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param defaultValue * {@link String} the default value of the current * {@link Attribute} * @param id * {@link String} the id of the current {@link Attribute} * @param domain * {@link Domain} the type of the current {@link Attribute} * @throws XMLStreamException */ private void createDefaultValue(XMLStreamWriter writer, String defaultValue, String id, Domain domain) throws XMLStreamException { // start defaultValue if (domain instanceof LongDomain || domain instanceof EnumDomain) { writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_DEFAULTVALUE); } else { writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_DEFAULTVALUE); } if (domain instanceof BooleanDomain) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_LITERALBOOLEAN); } else if (domain instanceof IntegerDomain || domain instanceof LongDomain) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_LITERALINTEGER); } else if (domain instanceof EnumDomain) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_INSTANCEVALUE); } else { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_OPAQUEEXPRESSION); } writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, id + "_defaultValue"); if (domain instanceof BooleanDomain || domain instanceof IntegerDomain || domain instanceof LongDomain || domain instanceof EnumDomain) { if (domain instanceof BooleanDomain) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_VALUE, defaultValue.equals("t") ? "true" : "false"); } else if (domain instanceof EnumDomain) { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_NAME, defaultValue); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, domain.get_qualifiedName()); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.DEFAULTVALUE_ATTRIBUTE_INSTANCE, domain.get_qualifiedName() + "_" + defaultValue); } else { writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_VALUE, defaultValue); } // create type if (domain instanceof BooleanDomain || domain instanceof IntegerDomain) { createType(writer, domain); } } else { if (domain instanceof StringDomain) { // create type createType(writer, domain); } else { // there has to be created an entry for the current domain in // the package primitiveTypes writer.writeAttribute(XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, domain.get_qualifiedName().replaceAll("\\s", "").replaceAll("<", "_").replaceAll(">", "_")); } // start body writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_BODY); writer.writeCharacters(defaultValue); // end body writer.writeEndElement(); } if (!(domain instanceof LongDomain || domain instanceof EnumDomain)) { // end defaultValue writer.writeEndElement(); } } /** * Creates the <code>type</code> tag used for attributes and default values. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param domain * {@link Domain} the type of the current {@link Attribute} * @throws XMLStreamException */ private void createType(XMLStreamWriter writer, Domain domain) throws XMLStreamException { // create type writer.writeEmptyElement(XMIConstants4SchemaGraph2XMI.TAG_TYPE); if (domain instanceof BooleanDomain) { // BooleanDomain writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_PRIMITIVETYPE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_HREF, XMIConstants4SchemaGraph2XMI.TYPE_HREF_VALUE_BOOLEAN); } else if (domain instanceof IntegerDomain) { // IntegerDomain writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_PRIMITIVETYPE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_HREF, XMIConstants4SchemaGraph2XMI.TYPE_HREF_VALUE_INTEGER); } else { // StringDomain writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_PRIMITIVETYPE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.ATTRIBUTE_HREF, XMIConstants4SchemaGraph2XMI.TYPE_HREF_VALUE_STRING); } } /** * Creates the representation of all {@link Constraint}s attached to * <code>aeclass</code>. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param aeclass * {@link AttributedElementClass} of which the {@link Constraint} * s should be created * @throws XMLStreamException */ private void createConstraints(XMLStreamWriter writer, AttributedElementClass aeclass) throws XMLStreamException { int uniqueNumber = 0; for (HasConstraint hasConstraint : aeclass.getHasConstraintIncidences()) { createConstraint(writer, (Constraint) hasConstraint.getThat(), aeclass.get_qualifiedName() + "_" + XMIConstants4SchemaGraph2XMI.TAG_OWNEDRULE + uniqueNumber++, aeclass.get_qualifiedName()); } } /** * Creates the representation of <code>constraint</code>. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param constraint * {@link Constraint} to be represented * @param id * {@link String} the id of the created <code>ownedRule</code> * tag, which represents <code>constraint</code> * @param constrainedElement * {@link String} qualified name of the * {@link AttributedElementClass} which is constrained * @throws XMLStreamException */ private void createConstraint(XMLStreamWriter writer, Constraint constraint, String id, String constrainedElement) throws XMLStreamException { createConstraint(writer, "\"" + constraint.get_message() + "\" \"" + constraint.get_predicateQuery() + "\" \"" + constraint.get_offendingElementsQuery() + "\"", id, constrainedElement); } /** * Creates an constraint with the content <code>constraintContent</code>. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param constraintContent * {@link String} the content of the constraint which will be * created * @param id * {@link String} the id of the created <code>ownedRule</code> * tag, which represents <code>constraint</code> * @param constrainedElement * {@link String} qualified name of the * {@link AttributedElementClass} which is constrained * @throws XMLStreamException */ private void createConstraint(XMLStreamWriter writer, String constraintContent, String id, String constrainedElement) throws XMLStreamException { // start ownedRule writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_OWNEDRULE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.OWNEDRULE_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, id); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.OWNEDRULE_ATTRIBUTE_CONSTRAINEDELEMENT, constrainedElement); // start specification writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_SPECIFICATION); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.TYPE_VALUE_OPAQUEEXPRESSION); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, id + "_" + XMIConstants4SchemaGraph2XMI.TAG_SPECIFICATION); // start and end language writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_LANGUAGE); writer.writeEndElement(); // start body writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_BODY); writer.writeCharacters(constraintContent); // end body writer.writeEndElement(); // end specification writer.writeEndElement(); // end ownedRule writer.writeEndElement(); } /** * Creates the representation of all {@link Comment}s attached to * <code>nelement</code>. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param nelement * {@link NamedElement} of which the {@link Comment}s should be * created * @throws XMLStreamException */ private void createComments(XMLStreamWriter writer, NamedElement nelement) throws XMLStreamException { int uniqueNumber = 0; for (Annotates annotates : nelement.getAnnotatesIncidences()) { createComment( writer, (Comment) annotates.getThat(), nelement.get_qualifiedName() + "_" + XMIConstants4SchemaGraph2XMI.TAG_OWNEDCOMMENT + uniqueNumber++, nelement.get_qualifiedName()); } } /** * Creates the representation of one comment. * * @param writer * {@link XMLStreamWriter} of the current XMI file * @param comment * {@link Comment} which should be represented * @param id * {@link String} the id of the created <code>ownedComment</code> * tag, which represents <code>comment</code> * @param annotatedElement * {@link String} qualified name of the {@link NamedElement} * which is commented * @throws XMLStreamException */ private void createComment(XMLStreamWriter writer, Comment comment, String id, String annotatedElement) throws XMLStreamException { // start ownedComment writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_OWNEDCOMMENT); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_TYPE, XMIConstants4SchemaGraph2XMI.OWNEDCOMMENT_TYPE_VALUE); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.NAMESPACE_XMI, XMIConstants4SchemaGraph2XMI.XMI_ATTRIBUTE_ID, id); writer.writeAttribute(XMIConstants4SchemaGraph2XMI.OWNEDCOMMENT_ATTRIBUTE_ANNOTATEDELEMENT, annotatedElement); // start body writer.writeStartElement(XMIConstants4SchemaGraph2XMI.TAG_BODY); // write content writer.writeCharacters(XMIConstants4SchemaGraph2XMI.COMMENT_START + comment.get_text().replaceAll(Pattern.quote("\n"), XMIConstants4SchemaGraph2XMI.COMMENT_NEWLINE) + XMIConstants4SchemaGraph2XMI.COMMENT_END); // end body writer.writeEndElement(); // end ownedComment writer.writeEndElement(); } /** * Extracts the simple name out of <code>qualifiedName</code>. * * @param qualifiedName * {@link String} the qualified name of which the simple name * should be extracted * @return {@link String} the extracted simple name */ private String extractSimpleName(String qualifiedName) { int lastIndexOfDot = qualifiedName.lastIndexOf('.'); if (lastIndexOfDot >= 0) { return qualifiedName.substring(lastIndexOfDot + 1); } else { return qualifiedName; } } }