Creating a model exporter using the Converter API is a fairly simple task. In this exercise you will create one that generates a text file that enumerates the elements of an EMF model.
For your reference, here again is the UML class diagram describing the purchase order model:
At the end of the lab, you should be able to:
This exercise is carried out entirely using the Eclipse Software Development Kit (SDK) version 3.2 with the Eclipse Modeling Framework (EMF) 2.2 installed into it. The exercise instructions refer to this product as either Eclipse or as "the workbench".
These instructions are located in the exercises/Exercise5_Model_Exporter folder. If you browse into this location by expanding the folders, you should find one additional folder: org.eclipse.emf.tutorial.advanced.po. This is an Eclipse project that you will import into your workspace to complete this exercise.
The org.example.emf.exporter.text now available in the workspace could be considered the skelleton of any model exporter. Take some time now and look at the plugin.xml file, in which the wizard you will create during this exercise is registered using the org.eclipse.emf.exporter.modelExporterDescriptors extension point.
public String getID() { return "org.example.emf.exporter.text"; }
protected String getDefaultArtifactLocation(EPackage ePackage) { return getDefaultArtifactFileName(ePackage) + ".txt"; }
protected String doCheckEPackageArtifactLocation(String location, String packageName) { if (!location.endsWith(".txt")) { return TextExporterPlugin.INSTANCE.getString("_UI_InvalidArtifactFileNameExtension_message"); } return super.doCheckEPackageArtifactLocation(location, packageName); }
protected void doExport(Monitor monitor, ExportData exportData) throws Exception { System.out.println("TextExporter.doExport()"); }
Note: Eclipse provides a very handy way of doing this: type syst, invoke the content assitent using Ctrl+Space, and select the systrace - print the current method to standard out editor template.
protected ModelConverter createModelConverter() { return new TextExporter(); }
public void addPages() { ModelExporterDirectoryURIPage directoryURIPage = new ModelExporterDirectoryURIPage(getModelExporter(), "TextExporterBaseLocationPage"); directoryURIPage.setTitle(TextExporterPlugin.INSTANCE.getString("_UI_TextImport_title")); addPage(directoryURIPage); ModelExporterPackagePage packagePage = new ModelExporterPackagePage(getModelExporter(), "TextExporterGenModelDetailPage"); packagePage.setTitle(TextExporterPlugin.INSTANCE.getString("_UI_TextImport_title")); packagePage.setShowReferencedGenModels(true); addPage(packagePage); ModelExporterOptionsPage optionsPage = new ModelExporterOptionsPage(getModelExporter(), "TextExporterOptionsPage"); optionsPage.setTitle(TextExporterPlugin.INSTANCE.getString("_UI_TextImport_title")); addPage(optionsPage); }
Notice that all the pages above belong to the Converter API. You didn't have to write one single line of SWT code.
All steps below will be done in a second, testing workbench, or Eclipse Application workbench.
Of course the objective of the TextExporter is not to output a simple message in the console view. You will now add the code necessary to generate a textual description of each EPackage of any EMF model, and to create each exported artifact.
private String toString(GenPackage genPackage) { return null; } private void save(URI uri, String content) throws Exception { }
protected void doExport(Monitor monitor, ExportData exportData) throws Exception { for (Iterator i = exportData.genPackageToArtifactURI.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry)i.next(); GenPackage genPackage = (GenPackage)entry.getKey(); URI exportedArtifactURI = (URI)entry.getValue(); String content = toString(genPackage); save(exportedArtifactURI, content); } }
If you take some time to analyze the ExportData object, you will notice that it holds the following maps:
Paying closer attention to the "packages" page of the Exporter wizard, you will notice that the ExportData is an object representation of the information acquired there
private void save(URI uri, String content) throws Exception { URIConverter uriConverter = new URIConverterImpl(); OutputStream outputStream = uriConverter.createOutputStream(uri); outputStream.write(content.getBytes("UTF-8")); outputStream.close(); }
Although the URIConverter is being instantiated directly in the snippet above, it would be preferred to obtain a reference to it through a ResourceSet. You could, for example, change doExport(Monitor, ExportData) to cache the URIConverter of a GenPackage's ResourceSet.
uriConverter = genPackage.eResource().getResourceSet().getURIConverter()
private String toString(GenPackage genPackage) { StringBuffer sb = new StringBuffer(); sb.append("Package: ").append(genPackage.getQualifiedPackageName()); sb.append("\n"); EPackage ePackage = genPackage.getEcorePackage(); sb.append("\n").append("Ecore URI: ").append(ePackage.eResource().getURI().toString()); sb.append("\n").append("GenModel URI: ").append(genPackage.eResource().getURI().toString()); for (Iterator i = ePackage.getEClassifiers().iterator(); i.hasNext();) { sb.append("\n"); EClassifier eClassifier = (EClassifier)i.next(); if (eClassifier instanceof EClass) { EClass eClass = (EClass)eClassifier; sb.append("\n").append("Class: ").append(eClass.getName()); if (!eClass.getEAttributes().isEmpty()) { sb.append("\n\t").append("Attributes: "); for (Iterator j = eClass.getEAttributes().iterator(); j.hasNext();) { EAttribute eAttribute = (EAttribute)j.next(); sb.append(eAttribute.getName()); if (j.hasNext()) sb.append(", "); } } } else if (eClassifier instanceof EEnum) { EEnum eEnum = (EEnum)eClassifier; sb.append("\n").append("Enumeration: ").append(eEnum.getName()); if (!eEnum.getELiterals().isEmpty()) { sb.append("\n\t").append("Literals: "); for (Iterator j = eEnum.getELiterals().iterator(); j.hasNext();) { EEnumLiteral enumLiteral = (EEnumLiteral)j.next(); sb.append(enumLiteral.getName()); if (j.hasNext()) sb.append(", "); } } } else if (eClassifier instanceof EDataType) { EDataType eDataType = (EDataType)eClassifier; sb.append("\n").append("Data Type: ").append(eDataType.getName()); } } return sb.toString(); }
You created a simple model exporter, which exposed you to the Converter API and to the EMF metadata which can be use to traverse any model. You also saw how to use the URIConverter to easily create the file specified by a URI.