From 945a37994dda7a786ac28e33bec6ce396e97b223 Mon Sep 17 00:00:00 2001 From: "Michael H. Siemaszko" Date: Tue, 31 Jan 2023 10:34:32 +0100 Subject: [PATCH 1/6] ODS (OpenDocument Spreadsheet) Exporter for EMF Signed-off-by: Michael H. Siemaszko --- cnf/central.mvn | 8 + org.gecko.emf.exporter.ods.tests/.classpath | 11 + org.gecko.emf.exporter.ods.tests/.gitignore | 2 + org.gecko.emf.exporter.ods.tests/.project | 23 + .../org.eclipse.core.resources.prefs | 6 + .../.settings/org.eclipse.jdt.core.prefs | 14 + org.gecko.emf.exporter.ods.tests/bnd.bnd | 15 + .../emf/ods/tests/EMFODSExporterTest.java | 94 ++++ .../helper/EMFODSExporterTestHelper.java | 378 ++++++++++++++ org.gecko.emf.exporter.ods.tests/test.bndrun | 57 +++ org.gecko.emf.exporter.ods/.classpath | 11 + org.gecko.emf.exporter.ods/.gitignore | 2 + org.gecko.emf.exporter.ods/.project | 23 + .../org.eclipse.core.resources.prefs | 5 + .../.settings/org.eclipse.jdt.core.prefs | 14 + org.gecko.emf.exporter.ods/bnd.bnd | 14 + .../emf/exporter/ods/EMFODSExporter.java | 484 ++++++++++++++++++ org.gecko.emf.exporter/.classpath | 11 + org.gecko.emf.exporter/.gitignore | 2 + org.gecko.emf.exporter/.project | 23 + .../org.eclipse.core.resources.prefs | 5 + .../.settings/org.eclipse.jdt.core.prefs | 14 + org.gecko.emf.exporter/bnd.bnd | 22 + .../emf/exporter/EMFExportException.java | 26 + .../gecko/emf/exporter/EMFExportOptions.java | 20 + .../org/gecko/emf/exporter/EMFExporter.java | 24 + .../org/gecko/emf/exporter/package-info.java | 3 + 27 files changed, 1311 insertions(+) create mode 100644 org.gecko.emf.exporter.ods.tests/.classpath create mode 100644 org.gecko.emf.exporter.ods.tests/.gitignore create mode 100644 org.gecko.emf.exporter.ods.tests/.project create mode 100644 org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.core.resources.prefs create mode 100644 org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.gecko.emf.exporter.ods.tests/bnd.bnd create mode 100644 org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java create mode 100644 org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java create mode 100644 org.gecko.emf.exporter.ods.tests/test.bndrun create mode 100644 org.gecko.emf.exporter.ods/.classpath create mode 100644 org.gecko.emf.exporter.ods/.gitignore create mode 100644 org.gecko.emf.exporter.ods/.project create mode 100644 org.gecko.emf.exporter.ods/.settings/org.eclipse.core.resources.prefs create mode 100644 org.gecko.emf.exporter.ods/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.gecko.emf.exporter.ods/bnd.bnd create mode 100644 org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java create mode 100644 org.gecko.emf.exporter/.classpath create mode 100644 org.gecko.emf.exporter/.gitignore create mode 100644 org.gecko.emf.exporter/.project create mode 100644 org.gecko.emf.exporter/.settings/org.eclipse.core.resources.prefs create mode 100644 org.gecko.emf.exporter/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.gecko.emf.exporter/bnd.bnd create mode 100644 org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java create mode 100644 org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java create mode 100644 org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java create mode 100644 org.gecko.emf.exporter/src/org/gecko/emf/exporter/package-info.java diff --git a/cnf/central.mvn b/cnf/central.mvn index f6a61045..bb64092d 100644 --- a/cnf/central.mvn +++ b/cnf/central.mvn @@ -162,3 +162,11 @@ org.eclipse.emfcloud:emfjson-jackson:2.2.0 de.undercouch:bson4jackson:2.13.1 org.yaml:snakeyaml:1.33 org.geckoprojects.emf:org.gecko.emf.osgi.example.model.basic:4.1.1-SNAPSHOT + +com.github.jferard:fastods:0.8.1 + +org.apache.commons:commons-text:1.10.0 +org.apache.commons:commons-lang3:3.12.0 + +com.google.guava:guava:31.1-jre +com.google.guava:failureaccess:1.0.1 diff --git a/org.gecko.emf.exporter.ods.tests/.classpath b/org.gecko.emf.exporter.ods.tests/.classpath new file mode 100644 index 00000000..66e477cd --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.gecko.emf.exporter.ods.tests/.gitignore b/org.gecko.emf.exporter.ods.tests/.gitignore new file mode 100644 index 00000000..7fdbdef7 --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/bin_test/ diff --git a/org.gecko.emf.exporter.ods.tests/.project b/org.gecko.emf.exporter.ods.tests/.project new file mode 100644 index 00000000..711a40ed --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/.project @@ -0,0 +1,23 @@ + + + org.gecko.emf.exporter.ods.tests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.core.resources.prefs b/org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..b905f5e1 --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//.settings/org.eclipse.core.resources.prefs=UTF-8 +encoding//.settings/org.eclipse.jdt.core.prefs=UTF-8 +encoding//.settings/org.eclipse.jdt.ui.prefs=UTF-8 +encoding/bnd.bnd=UTF-8 +encoding/test.bndrun=UTF-8 diff --git a/org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.jdt.core.prefs b/org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f2525a8b --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,14 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/org.gecko.emf.exporter.ods.tests/bnd.bnd b/org.gecko.emf.exporter.ods.tests/bnd.bnd new file mode 100644 index 00000000..2e3084da --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/bnd.bnd @@ -0,0 +1,15 @@ +-enable-junit5: true +-library: enable-emf + +javac.source: 11 +javac.target: 11 + +Bundle-Version: 1.0.0.SNAPSHOT + +-buildpath: \ + org.gecko.emf.osgi.component,\ + org.eclipse.emf.ecore.xmi,\ + org.eclipse.emf.ecore,\ + org.gecko.emf.osgi.example.model.basic,\ + org.gecko.emf.exporter;version=latest,\ + org.apache.commons.commons-text diff --git a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java new file mode 100644 index 00000000..f534ced3 --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2012 - 2023 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.tests; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createBusinessPerson; +import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createFlintstonesFamily; +import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createResourceSet; +import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createSimpsonFamily; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Locale; +import java.util.Map; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.gecko.emf.exporter.EMFExportOptions; +import org.gecko.emf.exporter.EMFExporter; +import org.gecko.emf.osgi.example.model.basic.BasicFactory; +import org.gecko.emf.osgi.example.model.basic.BasicPackage; +import org.gecko.emf.osgi.example.model.basic.BusinessPerson; +import org.gecko.emf.osgi.example.model.basic.Family; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.platform.commons.annotation.Testable; +import org.osgi.framework.ServiceReference; +import org.osgi.test.common.annotation.InjectService; +import org.osgi.test.common.service.ServiceAware; +import org.osgi.test.junit5.context.BundleContextExtension; +import org.osgi.test.junit5.service.ServiceExtension; + +@Testable +@ExtendWith(BundleContextExtension.class) +@ExtendWith(ServiceExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class EMFODSExporterTest { + + @Order(value=-1) + @Test + public void testServices( + @InjectService(cardinality = 1, timeout = 4000, filter = "(component.name=EMFODSExporter)") ServiceAware emfOdsExporterAware) { + + assertThat(emfOdsExporterAware.getServices()).hasSize(1); + ServiceReference emfOdsExporterReference = emfOdsExporterAware.getServiceReference(); + assertThat(emfOdsExporterReference).isNotNull(); + } + + @Test + public void testExportResourceToOds( + @InjectService(cardinality = 1, timeout = 4000, filter = "(component.name=EMFODSExporter)") ServiceAware emfOdsExporterAware, + @InjectService BasicFactory bf, @InjectService BasicPackage bp) throws Exception { + + assertThat(emfOdsExporterAware.getServices()).hasSize(1); + EMFExporter emfOdsExporterService = emfOdsExporterAware.getService(); + assertThat(emfOdsExporterService).isNotNull(); + + ResourceSet resourceSet = createResourceSet(bp); + Resource xmiResource = resourceSet.createResource(URI.createURI("exporter.test")); + assertNotNull(xmiResource); + + Family simpsonFamily = createSimpsonFamily(bf); + xmiResource.getContents().add(simpsonFamily); + + Family flintstonesFamily = createFlintstonesFamily(bf); + xmiResource.getContents().add(flintstonesFamily); + + BusinessPerson businessPerson = createBusinessPerson(bf); + xmiResource.getContents().add(businessPerson); + + Path filePath = Files.createTempFile("testExport", ".ods"); + + OutputStream fileOutputStream = Files.newOutputStream(filePath); + + emfOdsExporterService.exportResourceTo(xmiResource, Locale.GERMANY, fileOutputStream, + Map.of(EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, + EMFExportOptions.OPTION_EXPORT_METADATA, true)); + } +} diff --git a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java new file mode 100644 index 00000000..57c3ceaf --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java @@ -0,0 +1,378 @@ +/** + * Copyright (c) 2012 - 2023 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.tests.helper; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.UUID; + +import org.apache.commons.text.RandomStringGenerator; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.gecko.emf.osgi.example.model.basic.Address; +import org.gecko.emf.osgi.example.model.basic.BasicFactory; +import org.gecko.emf.osgi.example.model.basic.BasicPackage; +import org.gecko.emf.osgi.example.model.basic.BusinessPerson; +import org.gecko.emf.osgi.example.model.basic.ContactContextType; +import org.gecko.emf.osgi.example.model.basic.ContactType; +import org.gecko.emf.osgi.example.model.basic.EmployeeInfo; +import org.gecko.emf.osgi.example.model.basic.Family; +import org.gecko.emf.osgi.example.model.basic.GenderType; +import org.gecko.emf.osgi.example.model.basic.Person; +import org.gecko.emf.osgi.example.model.basic.PersonContact; +import org.gecko.emf.osgi.example.model.basic.Tag; +import org.gecko.emf.osgi.example.model.basic.util.BasicResourceFactoryImpl; + +public class EMFODSExporterTestHelper { + + public static Family createSimpsonFamily(BasicFactory bf) { + Family simpsonFamily = bf.createFamily(); + simpsonFamily.setId("Simpsons"); + + Address address = createSimpsonsAddress(bf); + + Person homerSimpson = createHomerSimpson(bf, address); + simpsonFamily.setFather(homerSimpson); + + Person margeSimpson = createMargeSimpson(bf, address); + simpsonFamily.setMother(margeSimpson); + + Person bartSimpson = createBartSimpson(bf, address); + simpsonFamily.getChildren().add(bartSimpson); + + Person lisaSimpson = createLisaSimpson(bf, address); + simpsonFamily.getChildren().add(lisaSimpson); + + Person maggieSimpson = createMaggieSimpson(bf, address); + simpsonFamily.getChildren().add(maggieSimpson); + + homerSimpson.getRelatives().add(margeSimpson); + homerSimpson.getRelatives().add(bartSimpson); + homerSimpson.getRelatives().add(lisaSimpson); + homerSimpson.getRelatives().add(maggieSimpson); + + margeSimpson.getRelatives().add(homerSimpson); + margeSimpson.getRelatives().add(bartSimpson); + margeSimpson.getRelatives().add(lisaSimpson); + margeSimpson.getRelatives().add(maggieSimpson); + + bartSimpson.getRelatives().add(homerSimpson); + bartSimpson.getRelatives().add(margeSimpson); + bartSimpson.getRelatives().add(lisaSimpson); + bartSimpson.getRelatives().add(maggieSimpson); + + lisaSimpson.getRelatives().add(homerSimpson); + lisaSimpson.getRelatives().add(margeSimpson); + lisaSimpson.getRelatives().add(bartSimpson); + lisaSimpson.getRelatives().add(maggieSimpson); + + maggieSimpson.getRelatives().add(homerSimpson); + maggieSimpson.getRelatives().add(margeSimpson); + maggieSimpson.getRelatives().add(lisaSimpson); + maggieSimpson.getRelatives().add(maggieSimpson); + + homerSimpson.getTags().add(createMultiLevelTag(bf, createUniquePrefix(10))); + + homerSimpson.setBigInt(BigInteger.TEN); + + homerSimpson.getBigDec().add(BigDecimal.ZERO); + homerSimpson.getBigDec().add(BigDecimal.ONE); + homerSimpson.getBigDec().add(BigDecimal.TEN); + + homerSimpson.setImage(createByteArr()); + + homerSimpson.getProperties().putAll(createProperties(createUniquePrefix(10))); + + return simpsonFamily; + } + + private static Address createSimpsonsAddress(BasicFactory bf) { + return createAddress(bf, "742 Evergreen Terrace", "Springfield", "97482"); + } + + private static Person createHomerSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Homer", "Simpson", GenderType.MALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createMargeSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Marge", "Simpson", GenderType.FEMALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createBartSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Bart", "Simpson", GenderType.MALE, address); + + return p; + } + + private static Person createLisaSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Lisa", "Simpson", GenderType.FEMALE, address); + + return p; + } + + private static Person createMaggieSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Maggie", "Simpson", GenderType.FEMALE, address); + + return p; + } + + public static Family createFlintstonesFamily(BasicFactory bf) { + Family flintstonesFamily = bf.createFamily(); + flintstonesFamily.setId("Flintstones"); + + Address address = createFlintstonesAddress(bf); + + Person fredFlintstone = createFredFlintstone(bf, address); + flintstonesFamily.setFather(fredFlintstone); + + Person wilmaFlintstone = createWilmaFlintstone(bf, address); + flintstonesFamily.setMother(wilmaFlintstone); + + Person pebblesFlintstone = createPebblesFlintstone(bf, address); + flintstonesFamily.getChildren().add(pebblesFlintstone); + + Person stonyFlintstone = createStonyFlintstone(bf, address); + flintstonesFamily.getChildren().add(stonyFlintstone); + + fredFlintstone.getRelatives().add(wilmaFlintstone); + fredFlintstone.getRelatives().add(pebblesFlintstone); + fredFlintstone.getRelatives().add(stonyFlintstone); + + wilmaFlintstone.getRelatives().add(fredFlintstone); + wilmaFlintstone.getRelatives().add(pebblesFlintstone); + wilmaFlintstone.getRelatives().add(stonyFlintstone); + + pebblesFlintstone.getRelatives().add(fredFlintstone); + pebblesFlintstone.getRelatives().add(wilmaFlintstone); + pebblesFlintstone.getRelatives().add(stonyFlintstone); + + stonyFlintstone.getRelatives().add(fredFlintstone); + stonyFlintstone.getRelatives().add(wilmaFlintstone); + stonyFlintstone.getRelatives().add(pebblesFlintstone); + + fredFlintstone.getTags().add(createMultiLevelTag(bf, createUniquePrefix(10))); + + fredFlintstone.setBigInt(BigInteger.TEN); + + fredFlintstone.getBigDec().add(BigDecimal.ZERO); + fredFlintstone.getBigDec().add(BigDecimal.ONE); + fredFlintstone.getBigDec().add(BigDecimal.TEN); + + fredFlintstone.setImage(createByteArr()); + + fredFlintstone.getProperties().putAll(createProperties(createUniquePrefix(10))); + + return flintstonesFamily; + } + + private static Address createFlintstonesAddress(BasicFactory bf) { + return createAddress(bf, "301 Cobblestone Way", "Bedrock", "70777"); + } + + private static Person createFredFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Fred", "Flintstone", GenderType.MALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createWilmaFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Wilma", "Flintstone", GenderType.FEMALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createPebblesFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Pebbles", "Flintstone", GenderType.FEMALE, address); + + return p; + } + + private static Person createStonyFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Stony", "Flintstone", GenderType.MALE, address); + + return p; + } + + public static BusinessPerson createBusinessPerson(BasicFactory bf) { + BusinessPerson bp = bf.createBusinessPerson(); + + bp.setId(UUID.randomUUID().toString()); + bp.setFirstName("Thomas"); + bp.setLastName("Edison"); + bp.setGender(GenderType.MALE); + + bp.setCompanyIdCardNumber(UUID.randomUUID().toString()); + + EmployeeInfo nikolaTesla = bf.createEmployeeInfo(); + nikolaTesla.setPosition("one-time employee"); + bp.getEmployeeInfo().add(nikolaTesla); + + return bp; + } + + private static Person createPerson(BasicFactory bf, String firstName, String lastName, GenderType gender, + Address address) { + Person p = bf.createPerson(); + + p.setId(UUID.randomUUID().toString()); + p.setFirstName(firstName); + p.setLastName(lastName); + p.setGender(gender); + + p.setAddress(address); + + return p; + } + + private static Address createAddress(BasicFactory bf, String street, String city, String zip) { + Address a = bf.createAddress(); + + a.setId(UUID.randomUUID().toString()); + a.setStreet(street); + a.setCity(city); + a.setZip(zip); + + return a; + } + + private static PersonContact createHomePhonePersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.PHONE, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeMobilePersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.MOBILE, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeWhatsAppPersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.WHATSAPP, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeEmailPersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.EMAIL, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeSkypePersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.SKYPE, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeWebAddressPersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.WEBADDRESS, ContactContextType.HOME, UUID.randomUUID().toString(), + p); + } + + private static PersonContact createPersonContact(BasicFactory bf, ContactType type, ContactContextType context, + String value, Person p) { + PersonContact pc = bf.createPersonContact(); + + pc.setContext(context); + pc.setType(type); + pc.setValue(value); + + pc.setContactPerson(p); + + return pc; + } + + private static Tag createMultiLevelTag(BasicFactory bf, String namePrefix) { + Tag t1 = createTag(bf, namePrefix, "tag_level_1", "tag_level_1_value", "tag_level_1_description"); + + t1.setTag(createTag(bf, namePrefix, "tag_level_2", "tag_level_2_value", "tag_level_2_description")); + + t1.getTags().add(createTag(bf, namePrefix, "tag_level_3", "tag_level_3_value", "tag_level_3_description")); + + return t1; + } + + private static Tag createTag(BasicFactory bf, String namePrefix, String name, String value, String description) { + Tag t = bf.createTag(); + + t.setName(namePrefix + "_" + name); + t.setValue(value); + t.setDescription(description); + + return t; + } + + private static byte[] createByteArr() { + byte[] b = new byte[20]; + new Random().nextBytes(b); + return b; + } + + private static Map createProperties(String namePrefix) { + Map props = new HashMap(); + + props.put(createPropertyName(namePrefix, "prop_1"), "prop_1_value"); + props.put(createPropertyName(namePrefix, "prop_2"), "prop_2_value"); + props.put(createPropertyName(namePrefix, "prop_3"), "prop_3_value"); + props.put(createPropertyName(namePrefix, "prop_4"), "prop_4_value"); + + return props; + } + + private static String createPropertyName(String prefix, String name) { + return (prefix + "_" + name); + } + + public static ResourceSet createResourceSet(BasicPackage bp) { + ResourceSet resourceSet = new ResourceSetImpl(); + resourceSet.getPackageRegistry().put(BasicPackage.eNS_URI, bp); + resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("test", new BasicResourceFactoryImpl()); + resourceSet.getResourceFactoryRegistry().getContentTypeToFactoryMap().put(BasicPackage.eCONTENT_TYPE, + new BasicResourceFactoryImpl()); + return resourceSet; + } + + private static String createUniquePrefix(int maxChars) { + // @formatter:off + return new RandomStringGenerator.Builder() + .withinRange('a', 'z') + .build() + .generate(maxChars); + // @formatter:on + } +} diff --git a/org.gecko.emf.exporter.ods.tests/test.bndrun b/org.gecko.emf.exporter.ods.tests/test.bndrun new file mode 100644 index 00000000..77f6615d --- /dev/null +++ b/org.gecko.emf.exporter.ods.tests/test.bndrun @@ -0,0 +1,57 @@ + +-runfw: org.apache.felix.framework;version='[7.0.1,7.0.1]' +-runprovidedcapabilities: ${native_capability} + +-resolve.effective: active + +-runbundles.junit5: ${test.runbundles} + +-runbundles: \ + junit-jupiter-api;version='[5.8.2,5.8.3)',\ + junit-platform-commons;version='[1.8.2,1.8.3)',\ + org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.eclipse.emf.common;version='[2.23.0,2.23.1)',\ + org.eclipse.emf.ecore;version='[2.25.0,2.25.1)',\ + org.eclipse.emf.ecore.xmi;version='[2.16.0,2.16.1)',\ + org.gecko.emf.osgi.api;version='[4.1.1,4.1.2)',\ + org.gecko.emf.osgi.component;version='[4.1.1,4.1.2)',\ + org.gecko.emf.osgi.example.model.basic;version='[4.1.1,4.1.2)',\ + org.opentest4j;version='[1.2.0,1.2.1)',\ + org.osgi.util.function;version='[1.1.0,1.1.1)',\ + org.osgi.util.pushstream;version='[1.0.1,1.0.2)',\ + org.apache.felix.converter;version='[1.0.18,1.0.19)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)',\ + org.gecko.emf.collections;version=snapshot,\ + assertj-core;version='[3.22.0,3.22.1)',\ + junit-jupiter-params;version='[5.8.2,5.8.3)',\ + org.osgi.test.common;version='[1.1.0,1.1.1)',\ + org.osgi.test.junit5;version='[1.1.0,1.1.1)',\ + org.yaml.snakeyaml;version='[1.33.0,1.33.1)',\ + org.gecko.emf.exporter;version=snapshot,\ + org.gecko.emf.exporter.ods;version=snapshot,\ + org.gecko.emf.exporter.ods.tests;version=snapshot,\ + com.fasterxml.jackson.core.jackson-annotations;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.core.jackson-core;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.core.jackson-databind;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.dataformat.jackson-dataformat-properties;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.14.1,2.14.2)',\ + com.google.guava;version='[31.1.0,31.1.1)',\ + com.google.guava.failureaccess;version='[1.0.1,1.0.2)',\ + de.undercouch.bson4jackson;version='[2.13.1,2.13.2)',\ + fastods;version='[0.8.1,0.8.2)',\ + org.apache.commons.commons-text;version='[1.10.0,1.10.1)',\ + org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ + org.eclipse.emfcloud.emfjson-jackson;version='[2.2.0,2.2.1)',\ + org.gecko.emf.json;version=snapshot + +-runrequires: bnd.identity;id='org.gecko.emf.exporter.ods.tests' + +-runee: JavaSE-11 + +-runtrace: true + +-runproperties.debug: \ + felix.log.level=4,\ + org.osgi.service.log.admin.loglevel=DEBUG + diff --git a/org.gecko.emf.exporter.ods/.classpath b/org.gecko.emf.exporter.ods/.classpath new file mode 100644 index 00000000..66e477cd --- /dev/null +++ b/org.gecko.emf.exporter.ods/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.gecko.emf.exporter.ods/.gitignore b/org.gecko.emf.exporter.ods/.gitignore new file mode 100644 index 00000000..7fdbdef7 --- /dev/null +++ b/org.gecko.emf.exporter.ods/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/bin_test/ diff --git a/org.gecko.emf.exporter.ods/.project b/org.gecko.emf.exporter.ods/.project new file mode 100644 index 00000000..739cd2ab --- /dev/null +++ b/org.gecko.emf.exporter.ods/.project @@ -0,0 +1,23 @@ + + + org.gecko.emf.exporter.ods + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/org.gecko.emf.exporter.ods/.settings/org.eclipse.core.resources.prefs b/org.gecko.emf.exporter.ods/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..e8cd65cb --- /dev/null +++ b/org.gecko.emf.exporter.ods/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//.settings/org.eclipse.core.resources.prefs=UTF-8 +encoding//.settings/org.eclipse.jdt.core.prefs=UTF-8 +encoding//.settings/org.eclipse.jdt.ui.prefs=UTF-8 +encoding/bnd.bnd=UTF-8 diff --git a/org.gecko.emf.exporter.ods/.settings/org.eclipse.jdt.core.prefs b/org.gecko.emf.exporter.ods/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f2525a8b --- /dev/null +++ b/org.gecko.emf.exporter.ods/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,14 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/org.gecko.emf.exporter.ods/bnd.bnd b/org.gecko.emf.exporter.ods/bnd.bnd new file mode 100644 index 00000000..f7b20e01 --- /dev/null +++ b/org.gecko.emf.exporter.ods/bnd.bnd @@ -0,0 +1,14 @@ +Bundle-Version: 1.0.0.SNAPSHOT +Bundle-Name: Gecko EMF ODS Exporter +Bundle-Description: ODS (OpenDocument Spreadsheet) Exporter for EMF + +-library: enable-emf + +-buildpath: \ + org.gecko.emf.exporter,\ + fastods;version='0.8',\ + org.apache.commons.commons-text;version='1.10',\ + com.google.guava;version='31.1' + +Private-Package: \ + org.gecko.emf.exporter.ods diff --git a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java new file mode 100644 index 00000000..82fdd270 --- /dev/null +++ b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java @@ -0,0 +1,484 @@ +/** + * Copyright (c) 2012 - 2023 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.exporter.ods; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.text.StringEscapeUtils; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.gecko.emf.exporter.EMFExportException; +import org.gecko.emf.exporter.EMFExportOptions; +import org.gecko.emf.exporter.EMFExporter; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ServiceScope; + +import com.github.jferard.fastods.AnonymousOdsFileWriter; +import com.github.jferard.fastods.FastOdsException; +import com.github.jferard.fastods.OdsDocument; +import com.github.jferard.fastods.OdsFactory; +import com.github.jferard.fastods.Table; +import com.github.jferard.fastods.TableCellWalker; +import com.github.jferard.fastods.Text; +import com.github.jferard.fastods.TextBuilder; +import com.github.jferard.fastods.attribute.BorderStyle; +import com.github.jferard.fastods.attribute.CellAlign; +import com.github.jferard.fastods.attribute.SimpleColor; +import com.github.jferard.fastods.attribute.SimpleLength; +import com.github.jferard.fastods.style.TableCellStyle; +import com.github.jferard.fastods.style.TableRowStyle; +import com.google.common.base.Splitter; + +@Component(name = "EMFODSExporter", scope = ServiceScope.PROTOTYPE) +public class EMFODSExporter implements EMFExporter { + + private static final Integer MAX_CHAR_PER_LINE_DEFAULT = 30; + + // @formatter:off + private static final TableCellStyle HEADER_CELL_STYLE = TableCellStyle.builder("header-cell-style") + .backgroundColor(SimpleColor.GRAY64) + .fontWeightBold() + .build(); + // @formatter:on + + // @formatter:off + public static final TableCellStyle DEFAULT_BODY_CELL_STYLE = TableCellStyle.builder("default-body-cell-style") + .borderAll(SimpleLength.mm(0.5), SimpleColor.BLUE, BorderStyle.OUTSET) + .fontColor(SimpleColor.BLACK) + .textAlign(CellAlign.CENTER) + .fontWeightNormal() + .build(); + // @formatter:on + + // @formatter:off + public static final TableRowStyle BODY_ROW_STYLE = TableRowStyle.builder("body-row-style") + .defaultCellStyle(DEFAULT_BODY_CELL_STYLE) + .rowHeight(SimpleLength.cm(1)) + .build(); + // @formatter:on + + private static final List METADATA_TABLE_HEADERS = List.of("Name", "Type", "isMany", "isRequired", "Default value"); + + /* + * (non-Javadoc) + * @see org.gecko.emf.exporter.EMFExporter#exportResourceTo(org.eclipse.emf.ecore.resource.Resource, java.util.Locale, java.io.OutputStream, java.util.Map) + */ + @Override + public void exportResourceTo(Resource t, Locale locale, OutputStream outputStream, Map options) + throws EMFExportException { + try { + + final OdsFactory odsFactory = OdsFactory.create(java.util.logging.Logger.getLogger("EMFODSExporter"), + locale); + + final AnonymousOdsFileWriter writer = odsFactory.createWriter(); + + final OdsDocument document = writer.document(); + + final Map eObjectsTableMap = new HashMap(); + + final Set eObjectsIDs = new HashSet(); + + final Set eObjectsClasses = new HashSet(); + + final Map exportOptions = validateExportOptions(options); + + for (EObject eObject : t.getContents()) { + // @formatter:off + createTableForEObjectWithEReferences(document, + eObjectsTableMap, + eObjectsIDs, + eObjectsClasses, + exportNonContainmentEnabled(exportOptions), + exportMetadataEnabled(exportOptions), + eObject); + // @formatter:on + } + + if (exportMetadataEnabled(exportOptions)) { + exportMetadata(document, eObjectsClasses); + } + + writer.save(outputStream); + + } catch (Exception e) { + throw new EMFExportException(e); + } + } + + private void createTableForEObjectWithEReferences(final OdsDocument document, + final Map eObjectsTableMap, final Set eObjectsIDs, + final Set eObjectsClasses, boolean exportNonContainment, boolean exportMetadata, EObject eObject) + throws IOException { + createTable(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, exportNonContainment, exportMetadata, + eObject); + + eObject.eClass().getEAllReferences().stream().forEach(r -> { + createTableForEReference(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, exportNonContainment, + exportMetadata, eObject, r); + }); + } + + private void createTable(final OdsDocument document, final Map eObjectsTableMap, + final Set eObjectsIDs, final Set eObjectsClasses, boolean exportNonContainment, + boolean exportMetadata, EObject... eObjects) throws IOException { + if ((eObjects.length > 0) && (!eObjectsIDs.contains(getEObjectID(eObjects[0])))) { + EClass eClass = eObjects[0].eClass(); + + Table table = getOrAddTable(document, eObjectsTableMap, eClass, exportMetadata); + + final TableCellWalker walker = table.getWalker(); + + walker.lastRow(); + + for (EObject eObject : eObjects) { + eObjectsIDs.add(getEObjectID(eObject)); + eObjectsClasses.add(eObject.eClass()); + + createTableBody(document, walker, eObject); + + eObject.eClass().getEAllReferences().stream().forEach(r -> { + createTableForEReference(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, + exportNonContainment, exportMetadata, eObject, r); + }); + } + + // FIXME: freezing header row does not work + // document.freezeCells(table, 1, 1); + // document.freezeCells(table, 1, eObject.eClass().getFeatureCount()); + } + } + + @SuppressWarnings("unchecked") + private void createTableForEReference(final OdsDocument document, final Map eObjectsTableMap, + final Set eObjectsIDs, final Set eObjectsClasses, boolean exportNonContainment, + boolean exportMetadata, EObject eObject, EReference r) { + if (!exportNonContainment && !r.isContainment()) { + return; + } + + Object value = eObject.eGet(r); + + if (value != null) { + if (!r.isMany() && value instanceof EObject) { + try { + createTable(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, exportNonContainment, + exportMetadata, (EObject) value); + } catch (IOException e) { + e.printStackTrace(); + } + } else if (r.isMany()) { + try { + createTable(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, exportNonContainment, + exportMetadata, ((List) value).toArray(EObject[]::new)); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + private Table getOrAddTable(OdsDocument document, Map eObjectsTableMap, EClass eClass, + boolean exportMetadata) throws IOException { + String tableName = constructTableName(eClass); + + boolean tableExists = eObjectsTableMap.containsKey(tableName); + Table table; + if (tableExists) { + table = eObjectsTableMap.get(tableName); + } else { + table = document.addTable(tableName); + eObjectsTableMap.put(tableName, table); + + if (exportMetadata) { + addMetadataTable(document, eClass); + } + } + + final TableCellWalker walker = table.getWalker(); + + if (!tableExists) { + createTableHeader(walker, eClass); + } + + walker.nextRow(); + + return table; + } + + private void addMetadataTable(OdsDocument document, EClass eClass) throws IOException { + document.addTable(constructMetadataTableName(eClass)); + } + + private void createTableHeader(TableCellWalker walker, EClass eClass) throws IOException { + eClass.getEAllStructuralFeatures().forEach(eStructuralFeature -> { + + walker.setStringValue(eStructuralFeature.getName()); + walker.setStyle(HEADER_CELL_STYLE); + + walker.next(); + }); + } + + private void createTableBody(final OdsDocument document, TableCellWalker walker, EObject eObject) + throws IOException { + eObject.eClass().getEAllStructuralFeatures().forEach(eStructuralFeature -> { + + walker.setRowStyle(BODY_ROW_STYLE); + + createTableBodyCell(walker, eObject, eStructuralFeature); + + walker.next(); + }); + + walker.nextRow(); + } + + private void createTableBodyCell(TableCellWalker walker, EObject eObject, EStructuralFeature eStructuralFeature) { + if (eStructuralFeature instanceof EAttribute) { + EAttribute eAttribute = (EAttribute) eStructuralFeature; + + Object value = eObject.eGet(eAttribute); + if (value != null) { + if (!eAttribute.isMany()) { + + if (value instanceof Date) { + setDateValueCell(walker, (Date) value); + + } else if (value instanceof Number) { + setNumberValueCell(walker, (Number) value); + + } else if (value instanceof Boolean) { + setBooleanValueCell(walker, (Boolean) value); + + } else if (value instanceof byte[]) { + // TODO: clarify how byte arrays should be handled + walker.setStringValue("EAttribute: byte[]"); + + } else { + setStringValueCell(walker, EcoreUtil.convertToString(eAttribute.getEAttributeType(), value)); + } + + } else { + setMultiValueCell(walker, eAttribute, value); + } + + } else { + setVoidValueCell(walker); + } + + } else if (eStructuralFeature instanceof EReference) { + EReference eReference = (EReference) eStructuralFeature; + + setEReferenceValueCell(walker, eObject, eReference); + } + } + + private void setEReferenceValueCell(TableCellWalker walker, EObject eObject, EReference r) { + // TODO: clarify how references should be presented in such case, in addition to + // being output on separate sheets + walker.setStringValue("EReference: " + r.getName()); + } + + private void setStringValueCell(TableCellWalker walker, String value) { + if (value.length() <= MAX_CHAR_PER_LINE_DEFAULT) { + walker.setStringValue(value); + } else { + setMultilineTextCell(walker, value); + } + } + + private void setMultilineTextCell(TableCellWalker walker, String value) { + Iterable pieces = Splitter.fixedLength(30).split(value); + TextBuilder textBuilder = Text.builder(); + for (String piece : pieces) { + textBuilder = textBuilder.parContent(StringEscapeUtils.escapeXml11(piece)); + } + Text text = textBuilder.build(); + walker.setText(text); + } + + private void setDateValueCell(TableCellWalker walker, Date value) { + walker.setDateValue(value); + } + + private void setNumberValueCell(TableCellWalker walker, Number value) { + walker.setFloatValue(value.floatValue()); + } + + private void setBooleanValueCell(TableCellWalker walker, Boolean value) { + walker.setBooleanValue(value.booleanValue()); + } + + @SuppressWarnings("unchecked") + private void setMultiValueCell(TableCellWalker walker, EAttribute eAttribute, Object multiValue) { + TextBuilder textBuilder = Text.builder(); + + Collection values = (Collection) multiValue; + for (Object value : values) { + textBuilder.parContent(EcoreUtil.convertToString(eAttribute.getEAttributeType(), value)); + } + + Text text = textBuilder.build(); + walker.setText(text); + } + + private void setVoidValueCell(TableCellWalker walker) { + walker.setVoidValue(); + } + + private boolean exportNonContainmentEnabled(Map exportOptions) { + return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, Boolean.FALSE)); + } + + private boolean exportMetadataEnabled(Map exportOptions) { + return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_EXPORT_METADATA, Boolean.FALSE)); + } + + private Map validateExportOptions(Map options) { + if (options == null) { + return Collections.emptyMap(); + } else { + return Map.copyOf(options); + } + } + + private void exportMetadata(final OdsDocument document, Set eClasses) throws IOException, FastOdsException { + for (EClass eClass : eClasses) { + + String metadataTableName = constructMetadataTableName(eClass); + + Table metadataTable = document.getTable(metadataTableName); + + final TableCellWalker walker = metadataTable.getWalker(); + + createMetadataTableHeader(walker, eClass); + + walker.nextRow(); + + createMetadataTableBody(walker, eClass); + } + } + + private void createMetadataTableHeader(TableCellWalker walker, EClass eClass) throws IOException { + METADATA_TABLE_HEADERS.forEach(h -> { + walker.setStyle(HEADER_CELL_STYLE); + walker.setStringValue(h); + walker.next(); + }); + } + + private void createMetadataTableBody(TableCellWalker walker, EClass eClass) throws IOException { + eClass.getEAllStructuralFeatures().forEach(eStructuralFeature -> { + + createMetadataTableBodyCell(walker, eStructuralFeature); + + try { + walker.nextRow(); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + + private void createMetadataTableBodyCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + walker.setRowStyle(BODY_ROW_STYLE); + + // Name + setStringValueCell(walker, eStructuralFeature.getName()); + + walker.next(); + + // Type + setMetadataTypeValueCell(walker, eStructuralFeature); + + walker.next(); + + // isMany + setBooleanValueCell(walker, eStructuralFeature.isMany()); + + walker.next(); + + // isRequired + setBooleanValueCell(walker, eStructuralFeature.isRequired()); + + walker.next(); + + // Default value + setMetadataDefaultValueCell(walker, eStructuralFeature); + + walker.next(); + } + + private void setMetadataTypeValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + if (eStructuralFeature instanceof EAttribute) { + EAttribute eAttribute = (EAttribute) eStructuralFeature; + + setStringValueCell(walker, eAttribute.getEAttributeType().getName()); + + } else if (eStructuralFeature instanceof EReference) { + EReference eReference = (EReference) eStructuralFeature; + + setStringValueCell(walker, eReference.getEReferenceType().getName()); + + } else { + setVoidValueCell(walker); + } + } + + private void setMetadataDefaultValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + if (eStructuralFeature instanceof EAttribute) { + EAttribute eAttribute = (EAttribute) eStructuralFeature; + + if (eAttribute.getDefaultValue() != null) { + setStringValueCell(walker, + EcoreUtil.convertToString(eAttribute.getEAttributeType(), eAttribute.getDefaultValue())); + return; + } + } + + setVoidValueCell(walker); + } + + private int getEObjectID(EObject eObject) { + return eObject.hashCode(); + } + + private String constructTableName(EClass eClass) { + return eClass.getName(); + } + + private String constructMetadataTableName(EClass eClass) { + StringBuilder sb = new StringBuilder(100); + sb.append(constructTableName(eClass)); + sb.append(" "); + sb.append("( "); + sb.append("Metadata"); + sb.append(" )"); + return sb.toString(); + } +} diff --git a/org.gecko.emf.exporter/.classpath b/org.gecko.emf.exporter/.classpath new file mode 100644 index 00000000..66e477cd --- /dev/null +++ b/org.gecko.emf.exporter/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.gecko.emf.exporter/.gitignore b/org.gecko.emf.exporter/.gitignore new file mode 100644 index 00000000..7fdbdef7 --- /dev/null +++ b/org.gecko.emf.exporter/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/bin_test/ diff --git a/org.gecko.emf.exporter/.project b/org.gecko.emf.exporter/.project new file mode 100644 index 00000000..c8937da8 --- /dev/null +++ b/org.gecko.emf.exporter/.project @@ -0,0 +1,23 @@ + + + org.gecko.emf.exporter + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/org.gecko.emf.exporter/.settings/org.eclipse.core.resources.prefs b/org.gecko.emf.exporter/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..e8cd65cb --- /dev/null +++ b/org.gecko.emf.exporter/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//.settings/org.eclipse.core.resources.prefs=UTF-8 +encoding//.settings/org.eclipse.jdt.core.prefs=UTF-8 +encoding//.settings/org.eclipse.jdt.ui.prefs=UTF-8 +encoding/bnd.bnd=UTF-8 diff --git a/org.gecko.emf.exporter/.settings/org.eclipse.jdt.core.prefs b/org.gecko.emf.exporter/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f2525a8b --- /dev/null +++ b/org.gecko.emf.exporter/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,14 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/org.gecko.emf.exporter/bnd.bnd b/org.gecko.emf.exporter/bnd.bnd new file mode 100644 index 00000000..acdb9452 --- /dev/null +++ b/org.gecko.emf.exporter/bnd.bnd @@ -0,0 +1,22 @@ +Bundle-Version: 1.0.0.SNAPSHOT +Bundle-Name: Gecko EMF ODS Exporter +Bundle-Description: ODS (OpenDocument Spreadsheet) Exporter for EMF + +-library: enable-emf + +-buildpath: \ + osgi.annotation;version='7.0',\ + osgi.core;version='7.0',\ + fastods;version='0.8' + +# osgi.annotation;version='7.0',\ +# osgi.core;version='7.0',\ +# osgi.cmpn;version='7.0',\ +# org.eclipse.emf.common,\ +# org.eclipse.emf.ecore,\ +# org.eclipse.emf.ecore.xmi,\ +# org.gecko.emf.repository.api,\ +# org.gecko.emf.osgi.api,\ +# org.osgi.util.pushstream,\ +# org.gecko.util.pushstream,\ +# org.gecko.emf.pushstreams,\ diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java new file mode 100644 index 00000000..c72c323c --- /dev/null +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2012 - 2023 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.exporter; + +public class EMFExportException extends Exception { + + /** serialVersionUID */ + private static final long serialVersionUID = 8114199181901603984L; + + public EMFExportException(String msg) { + super(msg); + } + + public EMFExportException(Throwable cause) { + super(cause); + } +} diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java new file mode 100644 index 00000000..29caeafa --- /dev/null +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2012 - 2023 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.exporter; + +public interface EMFExportOptions { + + String OPTION_EXPORT_NONCONTAINMENT = "EXPORT_NONCONTAINMENT"; + + String OPTION_EXPORT_METADATA = "EXPORT_METADATA"; + +} diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java new file mode 100644 index 00000000..b533b433 --- /dev/null +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2012 - 2023 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.exporter; + +import java.io.OutputStream; +import java.util.Locale; +import java.util.Map; + +import org.eclipse.emf.ecore.resource.Resource; + +public interface EMFExporter { + + void exportResourceTo(Resource t, Locale locale, OutputStream outputStream, Map options) + throws EMFExportException; +} diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/package-info.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/package-info.java new file mode 100644 index 00000000..8ea3d518 --- /dev/null +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package org.gecko.emf.exporter; From eafc18e6e6453a389383dc8c3495cff80dc43613 Mon Sep 17 00:00:00 2001 From: "Michael H. Siemaszko" Date: Wed, 15 Feb 2023 19:36:49 +0100 Subject: [PATCH 2/6] ODS (OpenDocument Spreadsheet) Exporter for EMF (c.d.) - Specialized EMF ODS resource - References traceable via IDs and (optionally) links - Additional export options - Additional metadata - Documentation - Various fixes & improvements Signed-off-by: Michael H. Siemaszko --- org.gecko.emf.exporter.ods.tests/bnd.bnd | 3 +- .../emf/ods/tests/EMFODSExporterTest.java | 83 +- .../helper/EMFODSExporterTestHelper.java | 38 +- org.gecko.emf.exporter.ods.tests/test.bndrun | 3 +- .../emf/exporter/ods/EMFODSExporter.java | 897 ++++++++++++++++-- org.gecko.emf.exporter/bnd.bnd | 4 +- .../emf/exporter/EMFExportException.java | 5 + .../gecko/emf/exporter/EMFExportOptions.java | 18 + .../org/gecko/emf/exporter/EMFExporter.java | 12 +- org.gecko.emf.ods.tests/.classpath | 11 + org.gecko.emf.ods.tests/.gitignore | 2 + org.gecko.emf.ods.tests/.project | 23 + .../org.eclipse.core.resources.prefs | 3 + .../.settings/org.eclipse.jdt.core.prefs | 14 + org.gecko.emf.ods.tests/bnd.bnd | 15 + .../emf/ods/tests/EMFODSResourceTest.java | 91 ++ .../helper/EMFODSResourceTestHelper.java | 370 ++++++++ org.gecko.emf.ods.tests/test.bndrun | 54 ++ org.gecko.emf.ods/.classpath | 11 + org.gecko.emf.ods/.gitignore | 2 + org.gecko.emf.ods/.project | 23 + .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 14 + org.gecko.emf.ods/bnd.bnd | 8 + .../EMFODSResourceFactoryConfigurator.java | 88 ++ .../emf/ods/annotation/RequireEMFODS.java | 45 + .../emf/ods/annotation/package-info.java | 3 + .../emf/ods/configuration/EMFODSResource.java | 62 ++ .../configuration/EMFODSResourceFactory.java | 52 + .../emf/ods/configuration/package-info.java | 3 + .../emf/ods/constants/EMFODSConstants.java | 27 + .../gecko/emf/ods/constants/package-info.java | 3 + 32 files changed, 1857 insertions(+), 132 deletions(-) create mode 100644 org.gecko.emf.ods.tests/.classpath create mode 100644 org.gecko.emf.ods.tests/.gitignore create mode 100644 org.gecko.emf.ods.tests/.project create mode 100644 org.gecko.emf.ods.tests/.settings/org.eclipse.core.resources.prefs create mode 100644 org.gecko.emf.ods.tests/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.gecko.emf.ods.tests/bnd.bnd create mode 100644 org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java create mode 100644 org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSResourceTestHelper.java create mode 100644 org.gecko.emf.ods.tests/test.bndrun create mode 100644 org.gecko.emf.ods/.classpath create mode 100644 org.gecko.emf.ods/.gitignore create mode 100644 org.gecko.emf.ods/.project create mode 100644 org.gecko.emf.ods/.settings/org.eclipse.core.resources.prefs create mode 100644 org.gecko.emf.ods/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.gecko.emf.ods/bnd.bnd create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/EMFODSResourceFactoryConfigurator.java create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/RequireEMFODS.java create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/package-info.java create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResource.java create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResourceFactory.java create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/package-info.java create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/constants/EMFODSConstants.java create mode 100644 org.gecko.emf.ods/src/org/gecko/emf/ods/constants/package-info.java diff --git a/org.gecko.emf.exporter.ods.tests/bnd.bnd b/org.gecko.emf.exporter.ods.tests/bnd.bnd index 2e3084da..6727dd65 100644 --- a/org.gecko.emf.exporter.ods.tests/bnd.bnd +++ b/org.gecko.emf.exporter.ods.tests/bnd.bnd @@ -12,4 +12,5 @@ Bundle-Version: 1.0.0.SNAPSHOT org.eclipse.emf.ecore,\ org.gecko.emf.osgi.example.model.basic,\ org.gecko.emf.exporter;version=latest,\ - org.apache.commons.commons-text + org.apache.commons.commons-text,\ + org.gecko.emf.util.model diff --git a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java index f534ced3..8b94511f 100644 --- a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java +++ b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java @@ -12,15 +12,17 @@ package org.gecko.emf.ods.tests; import static org.assertj.core.api.Assertions.assertThat; +import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createBasicPackageResourceSet; import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createBusinessPerson; import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createFlintstonesFamily; -import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createResourceSet; +import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createRequest; import static org.gecko.emf.ods.tests.helper.EMFODSExporterTestHelper.createSimpsonFamily; import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Locale; import java.util.Map; @@ -33,6 +35,9 @@ import org.gecko.emf.osgi.example.model.basic.BasicPackage; import org.gecko.emf.osgi.example.model.basic.BusinessPerson; import org.gecko.emf.osgi.example.model.basic.Family; +import org.gecko.emf.utilities.Request; +import org.gecko.emf.utilities.UtilitiesFactory; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -45,13 +50,18 @@ import org.osgi.test.junit5.context.BundleContextExtension; import org.osgi.test.junit5.service.ServiceExtension; +/** + * EMF ODS exporter integration test. + * + * @author Michal H. Siemaszko + */ @Testable @ExtendWith(BundleContextExtension.class) @ExtendWith(ServiceExtension.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class EMFODSExporterTest { - - @Order(value=-1) + + @Order(value = -1) @Test public void testServices( @InjectService(cardinality = 1, timeout = 4000, filter = "(component.name=EMFODSExporter)") ServiceAware emfOdsExporterAware) { @@ -60,35 +70,68 @@ public void testServices( ServiceReference emfOdsExporterReference = emfOdsExporterAware.getServiceReference(); assertThat(emfOdsExporterReference).isNotNull(); } - + @Test - public void testExportResourceToOds( + public void testExportBasicPackageResourceToOds( @InjectService(cardinality = 1, timeout = 4000, filter = "(component.name=EMFODSExporter)") ServiceAware emfOdsExporterAware, - @InjectService BasicFactory bf, @InjectService BasicPackage bp) throws Exception { + @InjectService BasicFactory basicFactory, @InjectService BasicPackage basicPackage) throws Exception { assertThat(emfOdsExporterAware.getServices()).hasSize(1); EMFExporter emfOdsExporterService = emfOdsExporterAware.getService(); assertThat(emfOdsExporterService).isNotNull(); - ResourceSet resourceSet = createResourceSet(bp); - Resource xmiResource = resourceSet.createResource(URI.createURI("exporter.test")); + ResourceSet resourceSet = createBasicPackageResourceSet(basicPackage); + Resource xmiResource = resourceSet.createResource(URI.createURI("basicPackageExporter.test")); assertNotNull(xmiResource); - - Family simpsonFamily = createSimpsonFamily(bf); + + Family simpsonFamily = createSimpsonFamily(basicFactory); xmiResource.getContents().add(simpsonFamily); - - Family flintstonesFamily = createFlintstonesFamily(bf); + + Family flintstonesFamily = createFlintstonesFamily(basicFactory); xmiResource.getContents().add(flintstonesFamily); - - BusinessPerson businessPerson = createBusinessPerson(bf); + + BusinessPerson businessPerson = createBusinessPerson(basicFactory); xmiResource.getContents().add(businessPerson); - - Path filePath = Files.createTempFile("testExport", ".ods"); - + + Path filePath = Files.createTempFile("testBasicPackageExport", ".ods"); + + OutputStream fileOutputStream = Files.newOutputStream(filePath); + + // @formatter:off + emfOdsExporterService.exportResourceTo(xmiResource, fileOutputStream, + Map.of( + EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, + EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, + EMFExportOptions.OPTION_EXPORT_METADATA, true, + EMFExportOptions.OPTION_GENERATE_LINKS, true) + ); + // @formatter:on + } + + @Disabled + @Test + public void testExportUtilitiesPackageResourceToOds( + @InjectService(cardinality = 1, timeout = 4000, filter = "(component.name=EMFODSExporter)") ServiceAware emfOdsExporterAware) + throws Exception { + + assertThat(emfOdsExporterAware.getServices()).hasSize(1); + EMFExporter emfOdsExporterService = emfOdsExporterAware.getService(); + assertThat(emfOdsExporterService).isNotNull(); + + Request request = createRequest(UtilitiesFactory.eINSTANCE); + + Path filePath = Files.createTempFile("testUtilitiesPackageExport", ".ods"); + OutputStream fileOutputStream = Files.newOutputStream(filePath); - emfOdsExporterService.exportResourceTo(xmiResource, Locale.GERMANY, fileOutputStream, - Map.of(EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, - EMFExportOptions.OPTION_EXPORT_METADATA, true)); + // @formatter:off + emfOdsExporterService.exportEObjectsTo(List.of(request), fileOutputStream, + Map.of( + EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, + EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, + EMFExportOptions.OPTION_EXPORT_METADATA, true, + EMFExportOptions.OPTION_GENERATE_LINKS, true) + ); + // @formatter:on } } diff --git a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java index 57c3ceaf..a2b7194f 100644 --- a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java +++ b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSExporterTestHelper.java @@ -13,6 +13,9 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Random; @@ -34,8 +37,39 @@ import org.gecko.emf.osgi.example.model.basic.PersonContact; import org.gecko.emf.osgi.example.model.basic.Tag; import org.gecko.emf.osgi.example.model.basic.util.BasicResourceFactoryImpl; +import org.gecko.emf.utilities.Filter; +import org.gecko.emf.utilities.Request; +import org.gecko.emf.utilities.Sort; +import org.gecko.emf.utilities.SortType; +import org.gecko.emf.utilities.UtilitiesFactory; public class EMFODSExporterTestHelper { + + public static Request createRequest(UtilitiesFactory uf) { + Request request = uf.createRequest(); + + Instant now = Instant.now(); + + request.setId(UUID.randomUUID().toString()); + request.setFrom(Date.from(now)); + request.setTo(Date.from(now.plus(7, ChronoUnit.DAYS))); + + Sort sort = uf.createSort(); + sort.setIndex(0); + sort.setField("cartoon"); + sort.setType(SortType.ASCENDING); + + request.getSorting().add(sort); + + Filter filter = uf.createFilter(); + filter.setIndex(0); + filter.setField("cartoon"); + filter.getValue().add("Simpsons"); + + request.getFiltering().add(filter); + + return request; + } public static Family createSimpsonFamily(BasicFactory bf) { Family simpsonFamily = bf.createFamily(); @@ -358,14 +392,14 @@ private static String createPropertyName(String prefix, String name) { return (prefix + "_" + name); } - public static ResourceSet createResourceSet(BasicPackage bp) { + public static ResourceSet createBasicPackageResourceSet(BasicPackage bp) { ResourceSet resourceSet = new ResourceSetImpl(); resourceSet.getPackageRegistry().put(BasicPackage.eNS_URI, bp); resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("test", new BasicResourceFactoryImpl()); resourceSet.getResourceFactoryRegistry().getContentTypeToFactoryMap().put(BasicPackage.eCONTENT_TYPE, new BasicResourceFactoryImpl()); return resourceSet; - } + } private static String createUniquePrefix(int maxChars) { // @formatter:off diff --git a/org.gecko.emf.exporter.ods.tests/test.bndrun b/org.gecko.emf.exporter.ods.tests/test.bndrun index 77f6615d..9857f67b 100644 --- a/org.gecko.emf.exporter.ods.tests/test.bndrun +++ b/org.gecko.emf.exporter.ods.tests/test.bndrun @@ -43,7 +43,8 @@ org.apache.commons.commons-text;version='[1.10.0,1.10.1)',\ org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ org.eclipse.emfcloud.emfjson-jackson;version='[2.2.0,2.2.1)',\ - org.gecko.emf.json;version=snapshot + org.gecko.emf.json;version=snapshot,\ + org.gecko.emf.util.model;version=snapshot -runrequires: bnd.identity;id='org.gecko.emf.exporter.ods.tests' diff --git a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java index 82fdd270..d0303993 100644 --- a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java +++ b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java @@ -11,6 +11,8 @@ */ package org.gecko.emf.exporter.ods; +import static java.util.stream.Collectors.toList; + import java.io.IOException; import java.io.OutputStream; import java.util.Collection; @@ -21,11 +23,19 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.text.StringEscapeUtils; +import org.apache.commons.text.WordUtils; +import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; @@ -50,13 +60,18 @@ import com.github.jferard.fastods.attribute.SimpleColor; import com.github.jferard.fastods.attribute.SimpleLength; import com.github.jferard.fastods.style.TableCellStyle; +import com.github.jferard.fastods.style.TableColumnStyle; import com.github.jferard.fastods.style.TableRowStyle; -import com.google.common.base.Splitter; +/** + * Implementation of the {@link EMFExporter} to provide support for exporting EMF resources and lists of EMF objects to ODS format. + * + * @author Michal H. Siemaszko + */ @Component(name = "EMFODSExporter", scope = ServiceScope.PROTOTYPE) public class EMFODSExporter implements EMFExporter { - private static final Integer MAX_CHAR_PER_LINE_DEFAULT = 30; + private static final int MAX_CHAR_PER_LINE_DEFAULT = 30; // @formatter:off private static final TableCellStyle HEADER_CELL_STYLE = TableCellStyle.builder("header-cell-style") @@ -77,106 +92,331 @@ public class EMFODSExporter implements EMFExporter { // @formatter:off public static final TableRowStyle BODY_ROW_STYLE = TableRowStyle.builder("body-row-style") .defaultCellStyle(DEFAULT_BODY_CELL_STYLE) - .rowHeight(SimpleLength.cm(1)) + .optimalHeight() .build(); // @formatter:on + + // @formatter:off + public static final TableColumnStyle BODY_COLUMN_STYLE = TableColumnStyle.builder("body-column-style") + .optimalWidth() // see: https://github.com/jferard/fastods/wiki/Tutorial#rows-and-columns-styles (...) There's an optimal height/width in the OpenDocument specification (20.383 and 20.384) but LO does not understand it, and FastODS won't compute this optimal value from the cell contents. (...) + .build(); + // @formatter:on - private static final List METADATA_TABLE_HEADERS = List.of("Name", "Type", "isMany", "isRequired", "Default value"); + private static final List METADATA_ECLASS_TABLE_HEADERS = List.of("Name", "Type", "isMany", "isRequired", + "Default value", "Documentation"); + private static final List METADATA_EENUM_TABLE_HEADERS = List.of("Name", "Literal", "Value", + "Documentation"); + private static final String METADATA_TABLE_SUFFIX = "Metadata"; + + private static final String DOCUMENTATION_GENMODEL_SOURCE = "http://www.eclipse.org/emf/2002/GenModel"; + private static final String DOCUMENTATION_GENMODEL_DETAILS = "documentation"; + private static final String ECORE_PACKAGE_NAME = "ecore"; + /* * (non-Javadoc) - * @see org.gecko.emf.exporter.EMFExporter#exportResourceTo(org.eclipse.emf.ecore.resource.Resource, java.util.Locale, java.io.OutputStream, java.util.Map) + * @see org.gecko.emf.exporter.EMFExporter#exportResourceTo(org.eclipse.emf.ecore.resource.Resource, java.io.OutputStream, java.util.Map) */ @Override - public void exportResourceTo(Resource t, Locale locale, OutputStream outputStream, Map options) + public void exportResourceTo(Resource resource, OutputStream outputStream, Map options) throws EMFExportException { + Objects.requireNonNull(resource, "Resource is required for export!"); + try { - final OdsFactory odsFactory = OdsFactory.create(java.util.logging.Logger.getLogger("EMFODSExporter"), - locale); + exportEObjectsTo(resource.getContents(), outputStream, options); + + } catch (Exception e) { + throw new EMFExportException(e); + } + } + + /* + * (non-Javadoc) + * @see org.gecko.emf.exporter.EMFExporter#exportEObjectsTo(java.util.List, java.io.OutputStream, java.util.Map) + */ + @Override + public void exportEObjectsTo(List eObjects, OutputStream outputStream, Map options) + throws EMFExportException { + Objects.requireNonNull(eObjects, "At least one EObject is required for export!"); + Objects.requireNonNull(outputStream, "Output stream is required for export!"); + + if (!eObjects.isEmpty()) { + + try { + + final Map exportOptions = validateExportOptions(options); + + final OdsFactory odsFactory = OdsFactory.create(java.util.logging.Logger.getLogger("EMFODSExporter"), + locale(exportOptions)); + + final AnonymousOdsFileWriter writer = odsFactory.createWriter(); + + final OdsDocument document = writer.document(); + + // maps table names to instances of tables + final Map eClassesTables = new HashMap(); - final AnonymousOdsFileWriter writer = odsFactory.createWriter(); + // maps EObjects' unique identifiers (obtained from their hash codes) to instances of tables, so those can be looked up e.g. when constructing links + final Map eObjectsTables = new HashMap(); - final OdsDocument document = writer.document(); + // stores EObjects' EClasses - used e.g. to construct meta data + final Set eObjectsClasses = new HashSet(); - final Map eObjectsTableMap = new HashMap(); + // stores EEnums - used e.g. to construct meta data + final Set eObjectsEnums = new HashSet(); - final Set eObjectsIDs = new HashSet(); + // maps EObjects' unique identifiers to pseudo IDs - for those EObjects which lack id field + final Map eObjectsPseudoIDs = new HashMap(); - final Set eObjectsClasses = new HashSet(); + final List eObjectsSafeCopy = safeCopy(eObjects); - final Map exportOptions = validateExportOptions(options); + // pseudo IDs are needed before main processing starts + generatePseudoIDs(eObjectsSafeCopy, eObjectsPseudoIDs); + + // @formatter:off + createTables(document, + eClassesTables, + eObjectsClasses, + eObjectsEnums, + eObjectsPseudoIDs, + eObjectsTables, + exportNonContainmentEnabled(exportOptions), + exportMetadataEnabled(exportOptions), + freezeHeaderRowEnabled(exportOptions), + adjustColumnWidthEnabled(exportOptions), + eObjectsSafeCopy); + // @formatter:on - for (EObject eObject : t.getContents()) { // @formatter:off - createTableForEObjectWithEReferences(document, - eObjectsTableMap, - eObjectsIDs, + createTablesBodies(document, + eClassesTables, eObjectsClasses, - exportNonContainmentEnabled(exportOptions), + eObjectsEnums, + eObjectsPseudoIDs, + eObjectsTables, + exportNonContainmentEnabled(exportOptions), exportMetadataEnabled(exportOptions), - eObject); + generateLinksEnabled(exportOptions), + eObjectsSafeCopy); // @formatter:on + + if (exportMetadataEnabled(exportOptions)) { + exportMetadata(document, eObjectsClasses, eObjectsEnums); + } + + writer.save(outputStream); + + } catch (Exception e) { + throw new EMFExportException(e); } + } + } - if (exportMetadataEnabled(exportOptions)) { - exportMetadata(document, eObjectsClasses); + private void generatePseudoIDs(List eObjects, Map eObjectsPseudoIDs) { + final Set processedEObjectsIdentifiers = new HashSet(); + + generatePseudoIDs(eObjects, processedEObjectsIdentifiers, eObjectsPseudoIDs); + } + + private void generatePseudoIDs(List eObjects, Set processedEObjectsIdentifiers, + Map eObjectsPseudoIDs) { + for (EObject eObject : eObjects) { + if (isProcessed(processedEObjectsIdentifiers, eObject)) { + continue; } - writer.save(outputStream); + processedEObjectsIdentifiers.add(getEObjectIdentifier(eObject)); - } catch (Exception e) { - throw new EMFExportException(e); + generatePseudoID(eObject, eObjectsPseudoIDs); + + eObject.eClass().getEAllReferences().stream().forEach(eReference -> { + generatePseudoID(eObject, eReference, processedEObjectsIdentifiers, eObjectsPseudoIDs); + }); + } + } + + @SuppressWarnings("unchecked") + private void generatePseudoID(EObject eObject, EReference eReference, Set processedEObjectsIdentifiers, + Map eObjectsPseudoIDs) { + Object value = eObject.eGet(eReference); + if (value != null) { + if (!eReference.isMany() && value instanceof EObject) { + generatePseudoID((EObject) value, eObjectsPseudoIDs); + } else if (eReference.isMany()) { + generatePseudoIDs((List) value, processedEObjectsIdentifiers, eObjectsPseudoIDs); + } + } + } + + private void generatePseudoID(EObject eObject, Map eObjectsPseudoIDs) { + if (!hasID(eObject, eObjectsPseudoIDs)) { + eObjectsPseudoIDs.put(getEObjectIdentifier(eObject), UUID.randomUUID().toString()); + } + } + + private boolean hasID(EObject eObject, Map eObjectsPseudoIDs) { + return (hasID(eObject) || hasPseudoID(eObject, eObjectsPseudoIDs)); + } + + private boolean hasID(EObject eObject) { + return (getID(eObject) != null); + } + + private String getID(EObject eObject) { + return EcoreUtil.getID(eObject); + } + + private boolean hasPseudoID(EObject eObject, Map eObjectsPseudoIDs) { + return (eObjectsPseudoIDs.containsKey(getEObjectIdentifier(eObject))); + } + + private String getPseudoID(EObject eObject, Map eObjectsPseudoIDs) { + return eObjectsPseudoIDs.get(getEObjectIdentifier(eObject)); + } + + private void createTables(OdsDocument document, Map eClassesTables, Set eObjectsClasses, + Set eObjectsEnums, Map eObjectsPseudoIDs, Map eObjectsTables, + boolean exportNonContainment, boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, + List eObjects) throws IOException { + + final Set processedEObjectsIdentifiers = new HashSet(); + + for (EObject eObject : eObjects) { + // @formatter:off + createTableForEObjectWithEReferences(document, + eClassesTables, + processedEObjectsIdentifiers, + eObjectsClasses, + eObjectsEnums, + eObjectsPseudoIDs, + eObjectsTables, + exportNonContainment, + exportMetadata, + freezeHeaderRow, + adjustColumnWidth, + eObject); + // @formatter:on + } + } + + private void createTablesBodies(OdsDocument document, Map eClassesTables, + Set eObjectsClasses, Set eObjectsEnums, Map eObjectsPseudoIDs, + Map eObjectsTables, boolean exportNonContainment, boolean exportMetadata, + boolean generateLinks, List eObjects) throws IOException, EMFExportException { + + final Set processedEObjectsIdentifiers = new HashSet(); + + for (EObject eObject : eObjects) { + // @formatter:off + createTableBodyForEObjectWithEReferences(document, + eClassesTables, + processedEObjectsIdentifiers, + eObjectsClasses, + eObjectsEnums, + eObjectsPseudoIDs, + eObjectsTables, + exportNonContainment, + exportMetadata, + generateLinks, + eObject); + // @formatter:on } } - private void createTableForEObjectWithEReferences(final OdsDocument document, - final Map eObjectsTableMap, final Set eObjectsIDs, - final Set eObjectsClasses, boolean exportNonContainment, boolean exportMetadata, EObject eObject) + private void createTableForEObjectWithEReferences(OdsDocument document, Map eClassesTables, + Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, + Map eObjectsPseudoIDs, Map eObjectsTables, boolean exportNonContainment, + boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject) throws IOException { - createTable(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, exportNonContainment, exportMetadata, - eObject); + createTable(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, + eObjectsTables, exportNonContainment, exportMetadata, freezeHeaderRow, adjustColumnWidth, eObject); eObject.eClass().getEAllReferences().stream().forEach(r -> { - createTableForEReference(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, exportNonContainment, - exportMetadata, eObject, r); + createTableForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, + eObjectsPseudoIDs, eObjectsTables, exportNonContainment, exportMetadata, freezeHeaderRow, + adjustColumnWidth, eObject, r); }); } - - private void createTable(final OdsDocument document, final Map eObjectsTableMap, - final Set eObjectsIDs, final Set eObjectsClasses, boolean exportNonContainment, - boolean exportMetadata, EObject... eObjects) throws IOException { - if ((eObjects.length > 0) && (!eObjectsIDs.contains(getEObjectID(eObjects[0])))) { + + private void createTableBodyForEObjectWithEReferences(OdsDocument document, Map eClassesTables, + Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, + Map eObjectsPseudoIDs, Map eObjectsTables, boolean exportNonContainment, + boolean exportMetadata, boolean generateLinks, EObject eObject) throws IOException, EMFExportException { + createTableBody(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsTables, + exportNonContainment, generateLinks, eObject); + + eObject.eClass().getEAllReferences().stream().forEach(r -> { + try { + createTableBodyForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, + eObjectsTables, exportNonContainment, generateLinks, eObject, r); + } catch (EMFExportException e) { + e.printStackTrace(); + } + }); + } + + private void createTable(OdsDocument document, Map eClassesTables, Set eObjectsIdentifiers, + Set eObjectsClasses, Set eObjectsEnums, Map eObjectsPseudoIDs, + Map eObjectsTables, boolean exportNonContainment, boolean exportMetadata, + boolean freezeHeaderRow, boolean adjustColumnWidth, EObject... eObjects) throws IOException { + if ((eObjects.length > 0) && !isProcessed(eObjectsIdentifiers, eObjects[0])) { EClass eClass = eObjects[0].eClass(); - Table table = getOrAddTable(document, eObjectsTableMap, eClass, exportMetadata); + Table table = getOrAddTable(document, eClassesTables, eClass, eObjectsEnums, + hasPseudoID(eObjects[0], eObjectsPseudoIDs), exportMetadata, freezeHeaderRow, adjustColumnWidth); + + for (EObject eObject : eObjects) { + Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); + + eObjectsIdentifiers.add(eObjectIdentifier); + eObjectsClasses.add(eObject.eClass()); + eObjectsTables.put(eObjectIdentifier, table); + + eObject.eClass().getEAllReferences().stream().forEach(r -> { + createTableForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, + eObjectsEnums, eObjectsPseudoIDs, eObjectsTables, exportNonContainment, exportMetadata, + freezeHeaderRow, adjustColumnWidth, eObject, r); + }); + } + } + } + + private void createTableBody(OdsDocument document, Map eClassesTables, + Set eObjectsIdentifiers, Map eObjectsPseudoIDs, + Map eObjectsTables, boolean exportNonContainment, boolean generateLinks, + EObject... eObjects) throws IOException, EMFExportException { + if ((eObjects.length > 0) && !isProcessed(eObjectsIdentifiers, eObjects[0])) { + EClass eClass = eObjects[0].eClass(); + + Table table = getTable(eClassesTables, eClass); final TableCellWalker walker = table.getWalker(); walker.lastRow(); for (EObject eObject : eObjects) { - eObjectsIDs.add(getEObjectID(eObject)); - eObjectsClasses.add(eObject.eClass()); + eObjectsIdentifiers.add(getEObjectIdentifier(eObject)); - createTableBody(document, walker, eObject); + createTableBody(walker, eObject, eObjectsPseudoIDs, eObjectsTables, generateLinks); eObject.eClass().getEAllReferences().stream().forEach(r -> { - createTableForEReference(document, eObjectsTableMap, eObjectsIDs, eObjectsClasses, - exportNonContainment, exportMetadata, eObject, r); + try { + createTableBodyForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, + eObjectsTables, exportNonContainment, generateLinks, eObject, r); + } catch (EMFExportException e) { + e.printStackTrace(); + } }); } - - // FIXME: freezing header row does not work - // document.freezeCells(table, 1, 1); - // document.freezeCells(table, 1, eObject.eClass().getFeatureCount()); } } - + @SuppressWarnings("unchecked") - private void createTableForEReference(final OdsDocument document, final Map eObjectsTableMap, - final Set eObjectsIDs, final Set eObjectsClasses, boolean exportNonContainment, - boolean exportMetadata, EObject eObject, EReference r) { + private void createTableForEReference(OdsDocument document, Map eClassesTables, + Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, + Map eObjectsPseudoIDs, Map eObjectsTables, boolean exportNonContainment, + boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject, EReference r) { if (!exportNonContainment && !r.isContainment()) { return; } @@ -186,15 +426,17 @@ private void createTableForEReference(final OdsDocument document, final Map) value).toArray(EObject[]::new)); + createTable(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, + eObjectsPseudoIDs, eObjectsTables, exportNonContainment, exportMetadata, freezeHeaderRow, + adjustColumnWidth, ((List) value).toArray(EObject[]::new)); } catch (IOException e) { e.printStackTrace(); } @@ -202,17 +444,48 @@ private void createTableForEReference(final OdsDocument document, final Map eObjectsTableMap, EClass eClass, - boolean exportMetadata) throws IOException { - String tableName = constructTableName(eClass); + @SuppressWarnings("unchecked") + private void createTableBodyForEReference(OdsDocument document, Map eClassesTables, + Set eObjectsIdentifiers, Map eObjectsPseudoIDs, + Map eObjectsTables, boolean exportNonContainment, boolean generateLinks, EObject eObject, + EReference r) throws EMFExportException { + if (!exportNonContainment && !r.isContainment()) { + return; + } + + Object value = eObject.eGet(r); + + if (value != null) { + if (!r.isMany() && value instanceof EObject) { + try { + createTableBody(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsTables, + exportNonContainment, generateLinks, (EObject) value); + } catch (IOException e) { + e.printStackTrace(); + } + } else if (r.isMany()) { + try { + createTableBody(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsTables, + exportNonContainment, generateLinks, ((List) value).toArray(EObject[]::new)); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + private Table getOrAddTable(OdsDocument document, Map eClassesTables, EClass eClass, + Set eObjectsEnums, boolean hasPseudoID, boolean exportMetadata, boolean freezeHeaderRow, + boolean adjustColumnWidth) throws IOException { + String tableName = constructEClassTableName(eClass); - boolean tableExists = eObjectsTableMap.containsKey(tableName); + boolean tableExists = eClassesTables.containsKey(tableName); Table table; if (tableExists) { - table = eObjectsTableMap.get(tableName); + table = eClassesTables.get(tableName); } else { table = document.addTable(tableName); - eObjectsTableMap.put(tableName, table); + eClassesTables.put(tableName, table); if (exportMetadata) { addMetadataTable(document, eClass); @@ -222,7 +495,12 @@ private Table getOrAddTable(OdsDocument document, Map eObjectsTab final TableCellWalker walker = table.getWalker(); if (!tableExists) { - createTableHeader(walker, eClass); + // because com.github.jferard.fastods.TableCellWalker.getColumnCount() returns incorrect values - filed as FastODS bug (https://github.com/jferard/fastods/issues/244) + int headersCount = createTableHeader(walker, eClass, eObjectsEnums, hasPseudoID, adjustColumnWidth); + + if (freezeHeaderRow) { + freezeTableHeader(document, table, 1, headersCount); + } } walker.nextRow(); @@ -230,35 +508,153 @@ private Table getOrAddTable(OdsDocument document, Map eObjectsTab return table; } + private void freezeTableHeader(OdsDocument document, Table table, int rowCount, int colCount) { + // FIXME: does not produce expected result, i.e. freezed header row - filed as FastODS bug (https://github.com/jferard/fastods/issues/143) + document.freezeCells(table, rowCount, colCount); + } + + private Table getTable(Map eClassesTables, EClass eClass) throws EMFExportException { + String tableName = constructEClassTableName(eClass); + + if (!eClassesTables.containsKey(tableName)) { + throw new EMFExportException("Table '" + tableName + "' does not exist!"); + } + + return eClassesTables.get(tableName); + } + private void addMetadataTable(OdsDocument document, EClass eClass) throws IOException { - document.addTable(constructMetadataTableName(eClass)); + document.addTable(constructEClassMetadataTableName(eClass)); } - private void createTableHeader(TableCellWalker walker, EClass eClass) throws IOException { + private int createTableHeader(TableCellWalker walker, EClass eClass, Set eObjectsEnums, boolean hasPseudoID, + boolean adjustColumnWidth) throws IOException { + walker.setRowStyle(BODY_ROW_STYLE); + if (!adjustColumnWidth) { + walker.setColumnStyle(BODY_COLUMN_STYLE); + } + + AtomicInteger headersCount = new AtomicInteger(0); + + AtomicInteger eStructuralFeaturesCount = new AtomicInteger(eClass.getEAllStructuralFeatures().size()); + eClass.getEAllStructuralFeatures().forEach(eStructuralFeature -> { - walker.setStringValue(eStructuralFeature.getName()); - walker.setStyle(HEADER_CELL_STYLE); + if (isEcoreEEnumDataType(eStructuralFeature)) { + eObjectsEnums.add(extractEEnumDataType(eStructuralFeature)); + } - walker.next(); + createTableHeaderCell(walker, eStructuralFeature, adjustColumnWidth, headersCount.get()); + + // because com.github.jferard.fastods.TableCellWalker.getColumnCount() returns incorrect values - filed as FastODS bug (https://github.com/jferard/fastods/issues/244) + int currentHeadersCount = headersCount.incrementAndGet(); + + boolean hasNext = (currentHeadersCount < eStructuralFeaturesCount.get()); + + if (hasNext) { + walker.next(); + } }); + + if (hasPseudoID) { + walker.next(); + + createTableHeaderCell(walker, "id", adjustColumnWidth, headersCount.get(), 36); + + headersCount.getAndIncrement(); + } + + return headersCount.get(); + } + + private void createTableHeaderCell(TableCellWalker walker, EStructuralFeature eStructuralFeature, + boolean adjustColumnWidth, int colIndex) { + String tableHeaderName = constructTableHeaderName(eStructuralFeature); + + createTableHeaderCell(walker, tableHeaderName); + + if (adjustColumnWidth) { + adjustColumnWidth(walker, colIndex, tableHeaderName.length()); + } } - private void createTableBody(final OdsDocument document, TableCellWalker walker, EObject eObject) - throws IOException { + private void createTableHeaderCell(TableCellWalker walker, String tableHeaderName, boolean adjustColumnWidth, + int colIndex, int charsCount) { + createTableHeaderCell(walker, tableHeaderName); + + if (adjustColumnWidth) { + adjustColumnWidth(walker, colIndex, charsCount); + } + } + + private void adjustColumnWidth(TableCellWalker walker, int colIndex, int charsCount) { + TableColumnStyle adjustedWithColumnStyle = constructAdjustedWithColumnStyle(charsCount); + + // FIXME: neither of these produce expected result, i.e. varied column width - filed as FastODS bug (https://github.com/jferard/fastods/issues/243) + // walker.setColumnStyle(adjustedWithColumnStyle); + walker.getTable().setColumnStyle(colIndex, adjustedWithColumnStyle); + } + + private TableColumnStyle constructAdjustedWithColumnStyle(int charsCount) { + // @formatter:off + return TableColumnStyle.builder("adjusted-with-column-style") + .columnWidth(calculateColumnWidth(charsCount)) + .build(); + // @formatter:on + } + + private SimpleLength calculateColumnWidth(int charsCount) { + SimpleLength columnWidth = SimpleLength.mm(charsCount * 10); + + return columnWidth; + } + + private void createTableHeaderCell(TableCellWalker walker, String tableHeaderName) { + walker.setStringValue(tableHeaderName); + walker.setStyle(HEADER_CELL_STYLE); + } + + private String constructTableHeaderName(EStructuralFeature eStructuralFeature) { + StringBuilder sb = new StringBuilder(100); + if (eStructuralFeature instanceof EReference) { + sb.append("ref_"); + } + sb.append(eStructuralFeature.getName()); + return sb.toString(); + } + + private boolean isEcoreEEnumDataType(EStructuralFeature eStructuralFeature) { + return (eStructuralFeature instanceof EAttribute + && ((EAttribute) eStructuralFeature).getEAttributeType() instanceof EEnum); + } + + private EEnum extractEEnumDataType(EStructuralFeature eStructuralFeature) { + return ((EEnum) ((EAttribute) eStructuralFeature).getEAttributeType()); + } + + private void createTableBody(TableCellWalker walker, EObject eObject, Map eObjectsPseudoIDs, + Map eObjectsTables, boolean generateLinks) throws IOException { eObject.eClass().getEAllStructuralFeatures().forEach(eStructuralFeature -> { walker.setRowStyle(BODY_ROW_STYLE); + walker.setColumnStyle(BODY_COLUMN_STYLE); - createTableBodyCell(walker, eObject, eStructuralFeature); + createTableBodyCell(walker, eObject, eStructuralFeature, eObjectsPseudoIDs, eObjectsTables, generateLinks); walker.next(); }); + if (hasPseudoID(eObject, eObjectsPseudoIDs)) { + setStringValueCell(walker, eObjectsPseudoIDs.get(getEObjectIdentifier(eObject))); + + walker.next(); + } + walker.nextRow(); } - private void createTableBodyCell(TableCellWalker walker, EObject eObject, EStructuralFeature eStructuralFeature) { + private void createTableBodyCell(TableCellWalker walker, EObject eObject, EStructuralFeature eStructuralFeature, + Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { if (eStructuralFeature instanceof EAttribute) { EAttribute eAttribute = (EAttribute) eStructuralFeature; @@ -294,14 +690,99 @@ private void createTableBodyCell(TableCellWalker walker, EObject eObject, EStruc } else if (eStructuralFeature instanceof EReference) { EReference eReference = (EReference) eStructuralFeature; - setEReferenceValueCell(walker, eObject, eReference); + setEReferenceValueCell(walker, eObject, eReference, eObjectsPseudoIDs, eObjectsTables, generateLinks); } } - - private void setEReferenceValueCell(TableCellWalker walker, EObject eObject, EReference r) { - // TODO: clarify how references should be presented in such case, in addition to - // being output on separate sheets - walker.setStringValue("EReference: " + r.getName()); + + @SuppressWarnings("unchecked") + private void setEReferenceValueCell(TableCellWalker walker, EObject eObject, EReference r, + Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { + Object value = eObject.eGet(r); + + if (value != null) { + if (!r.isMany() && value instanceof EObject) { + setOneEReferenceValueCell(walker, (EObject) value, eObjectsPseudoIDs, eObjectsTables, generateLinks); + } else if (r.isMany()) { + setManyEReferencesValueCell(walker, ((List) value), eObjectsPseudoIDs, eObjectsTables, + generateLinks); + } + } + } + + private void setOneEReferenceValueCell(TableCellWalker walker, EObject eObject, + Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { + Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); + + if (hasID(eObject)) { + if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { + setLinkedIDEReferenceValueCell(walker, getID(eObject), eObjectsTables.get(eObjectIdentifier)); + } else { + setNonLinkedIDEReferenceValueCell(walker, getID(eObject)); + } + } else if (hasPseudoID(eObject, eObjectsPseudoIDs)) { + if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { + setLinkedIDEReferenceValueCell(walker, getPseudoID(eObject, eObjectsPseudoIDs), + eObjectsTables.get(eObjectIdentifier)); + } else { + setNonLinkedIDEReferenceValueCell(walker, getPseudoID(eObject, eObjectsPseudoIDs)); + } + } else { + setNoIDEReferenceValueCell(walker, eObject); + } + } + + private void setManyEReferencesValueCell(TableCellWalker walker, List eObjects, + Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { + TextBuilder textBuilder = Text.builder(); + + for (EObject eObject : eObjects) { + Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); + + if (hasID(eObject)) { + if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { + textBuilder = setLinkedIDEReferenceValueCell(textBuilder, getID(eObject), + eObjectsTables.get(eObjectIdentifier)); + } else { + textBuilder = setNonLinkedIDEReferenceValueCell(textBuilder, getID(eObject)); + } + } else if (hasPseudoID(eObject, eObjectsPseudoIDs)) { + if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { + textBuilder = setLinkedIDEReferenceValueCell(textBuilder, getPseudoID(eObject, eObjectsPseudoIDs), + eObjectsTables.get(eObjectIdentifier)); + } else { + textBuilder = setNonLinkedIDEReferenceValueCell(textBuilder, + getPseudoID(eObject, eObjectsPseudoIDs)); + } + } else { + setNoIDEReferenceValueCell(walker, eObject); + } + } + + Text text = textBuilder.build(); + walker.setText(text); + + // adjust row height based on number of EObjects + adjustRowHeight(walker, eObjects.size()); + } + + private void setLinkedIDEReferenceValueCell(TableCellWalker walker, String refId, Table refTable) { + walker.setText(setLinkedIDEReferenceValueCell(Text.builder(), refId, refTable).build()); + } + + private TextBuilder setLinkedIDEReferenceValueCell(TextBuilder textBuilder, String refId, Table refTable) { + return textBuilder.par().link(refId, refTable); + } + + private void setNonLinkedIDEReferenceValueCell(TableCellWalker walker, String refId) { + walker.setText(setNonLinkedIDEReferenceValueCell(Text.builder(), refId).build()); + } + + private TextBuilder setNonLinkedIDEReferenceValueCell(TextBuilder textBuilder, String refId) { + return textBuilder.parContent(refId); + } + + private void setNoIDEReferenceValueCell(TableCellWalker walker, EObject eObject) { + walker.setStringValue("EReference: " + eObject.eClass().getName()); } private void setStringValueCell(TableCellWalker walker, String value) { @@ -313,13 +794,19 @@ private void setStringValueCell(TableCellWalker walker, String value) { } private void setMultilineTextCell(TableCellWalker walker, String value) { - Iterable pieces = Splitter.fixedLength(30).split(value); + String wrapped = WordUtils.wrap(value, MAX_CHAR_PER_LINE_DEFAULT, System.lineSeparator(), false); + + String[] pieces = wrapped.split(System.lineSeparator()); + TextBuilder textBuilder = Text.builder(); for (String piece : pieces) { textBuilder = textBuilder.parContent(StringEscapeUtils.escapeXml11(piece)); } Text text = textBuilder.build(); walker.setText(text); + + // adjust row height based on number of new lines + adjustRowHeight(walker, pieces.length); } private void setDateValueCell(TableCellWalker walker, Date value) { @@ -351,6 +838,10 @@ private void setVoidValueCell(TableCellWalker walker) { walker.setVoidValue(); } + private Locale locale(Map exportOptions) { + return ((Locale) exportOptions.getOrDefault(EMFExportOptions.OPTION_LOCALE, Locale.getDefault())); + } + private boolean exportNonContainmentEnabled(Map exportOptions) { return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, Boolean.FALSE)); } @@ -359,6 +850,18 @@ private boolean exportMetadataEnabled(Map exportOptions) { return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_EXPORT_METADATA, Boolean.FALSE)); } + private boolean adjustColumnWidthEnabled(Map exportOptions) { + return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_ADJUST_COLUMN_WIDTH, Boolean.FALSE)); + } + + private boolean freezeHeaderRowEnabled(Map exportOptions) { + return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_FREEZE_HEADER_ROW, Boolean.FALSE)); + } + + private boolean generateLinksEnabled(Map exportOptions) { + return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_GENERATE_LINKS, Boolean.FALSE)); + } + private Map validateExportOptions(Map options) { if (options == null) { return Collections.emptyMap(); @@ -367,35 +870,71 @@ private Map validateExportOptions(Map options) { } } - private void exportMetadata(final OdsDocument document, Set eClasses) throws IOException, FastOdsException { + private void exportMetadata(OdsDocument document, Set eClasses, Set eEnums) + throws IOException, FastOdsException { + exportEClassesMetadata(document, eClasses); + exportEEnumsMetadata(document, eEnums); + } + + private void exportEClassesMetadata(OdsDocument document, Set eClasses) + throws IOException, FastOdsException { for (EClass eClass : eClasses) { - String metadataTableName = constructMetadataTableName(eClass); + String metadataTableName = constructEClassMetadataTableName(eClass); Table metadataTable = document.getTable(metadataTableName); final TableCellWalker walker = metadataTable.getWalker(); - createMetadataTableHeader(walker, eClass); + createEClassMetadataTableHeader(walker); walker.nextRow(); - createMetadataTableBody(walker, eClass); + createEClassMetadataTableBody(walker, eClass); } } - - private void createMetadataTableHeader(TableCellWalker walker, EClass eClass) throws IOException { - METADATA_TABLE_HEADERS.forEach(h -> { + + private void exportEEnumsMetadata(OdsDocument document, Set eEnums) throws IOException, FastOdsException { + for (EEnum eEnum : eEnums) { + + String metadataTableName = constructEEnumMetadataTableName(eEnum); + + Table metadataTable = document.addTable(metadataTableName); + + final TableCellWalker walker = metadataTable.getWalker(); + + createEEnumMetadataTableHeader(walker); + + walker.nextRow(); + + createEEnumMetadataTableBody(walker, eEnum); + } + } + + private void createEClassMetadataTableHeader(TableCellWalker walker) throws IOException { + METADATA_ECLASS_TABLE_HEADERS.forEach(h -> { + walker.setRowStyle(BODY_ROW_STYLE); + walker.setColumnStyle(BODY_COLUMN_STYLE); walker.setStyle(HEADER_CELL_STYLE); walker.setStringValue(h); walker.next(); }); } - private void createMetadataTableBody(TableCellWalker walker, EClass eClass) throws IOException { + private void createEEnumMetadataTableHeader(TableCellWalker walker) throws IOException { + METADATA_EENUM_TABLE_HEADERS.forEach(h -> { + walker.setRowStyle(BODY_ROW_STYLE); + walker.setColumnStyle(BODY_COLUMN_STYLE); + walker.setStyle(HEADER_CELL_STYLE); + walker.setStringValue(h); + walker.next(); + }); + } + + private void createEClassMetadataTableBody(TableCellWalker walker, EClass eClass) throws IOException { eClass.getEAllStructuralFeatures().forEach(eStructuralFeature -> { - createMetadataTableBodyCell(walker, eStructuralFeature); + createEClassMetadataTableBodyCell(walker, eStructuralFeature); try { walker.nextRow(); @@ -404,41 +943,109 @@ private void createMetadataTableBody(TableCellWalker walker, EClass eClass) thro } }); } - - private void createMetadataTableBodyCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + + private void createEEnumMetadataTableBody(TableCellWalker walker, EEnum eEnum) throws IOException { + eEnum.getEAnnotations(); // TODO: clarify regarding instance-level docs + + eEnum.getELiterals().forEach(eEnumLiteral -> { + + createEEnumMetadataTableBodyCell(walker, eEnumLiteral); + + try { + walker.nextRow(); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + + private void createEEnumMetadataTableBodyCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { walker.setRowStyle(BODY_ROW_STYLE); + walker.setColumnStyle(BODY_COLUMN_STYLE); // Name - setStringValueCell(walker, eStructuralFeature.getName()); + setEEnumMetadataNameValueCell(walker, eEnumLiteral); + + walker.next(); + + // Literal + setEEnumMetadataLiteralValueCell(walker, eEnumLiteral); + + walker.next(); + + // Value + setEEnumMetadataValueValueCell(walker, eEnumLiteral); + + walker.next(); + + // Documentation + setEEnumMetadataDocumentationValueCell(walker, eEnumLiteral); + + walker.next(); + } + + private void setEEnumMetadataNameValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { + setStringValueCell(walker, eEnumLiteral.getName()); + } + + private void setEEnumMetadataLiteralValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { + setStringValueCell(walker, eEnumLiteral.getLiteral()); + } + + private void setEEnumMetadataValueValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { + setNumberValueCell(walker, eEnumLiteral.getValue()); + } + + private void setEEnumMetadataDocumentationValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { + EAnnotation genModelAnnotation = eEnumLiteral.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); + + setMetadataDocumentationValueCell(walker, genModelAnnotation); + } + + private void createEClassMetadataTableBodyCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + walker.setRowStyle(BODY_ROW_STYLE); + walker.setColumnStyle(BODY_COLUMN_STYLE); + + // Name + setEClassMetadataNameValueCell(walker, eStructuralFeature); walker.next(); // Type - setMetadataTypeValueCell(walker, eStructuralFeature); + setEClassMetadataTypeValueCell(walker, eStructuralFeature); walker.next(); // isMany - setBooleanValueCell(walker, eStructuralFeature.isMany()); + setEClassMetadataIsManyValueCell(walker, eStructuralFeature); walker.next(); // isRequired - setBooleanValueCell(walker, eStructuralFeature.isRequired()); + setEClassMetadataIsRequiredValueCell(walker, eStructuralFeature); walker.next(); // Default value - setMetadataDefaultValueCell(walker, eStructuralFeature); + setEClassMetadataDefaultValueCell(walker, eStructuralFeature); walker.next(); - } - - private void setMetadataTypeValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + + // Documentation + setEClassMetadataDocumentationValueCell(walker, eStructuralFeature); + + walker.next(); + } + + private void setEClassMetadataNameValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + setStringValueCell(walker, eStructuralFeature.getName()); + } + + private void setEClassMetadataTypeValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { if (eStructuralFeature instanceof EAttribute) { EAttribute eAttribute = (EAttribute) eStructuralFeature; - setStringValueCell(walker, eAttribute.getEAttributeType().getName()); + setStringValueCell(walker, normalizeMetadataTypeEAttributeName(eAttribute.getEAttributeType())); } else if (eStructuralFeature instanceof EReference) { EReference eReference = (EReference) eStructuralFeature; @@ -450,7 +1057,32 @@ private void setMetadataTypeValueCell(TableCellWalker walker, EStructuralFeature } } - private void setMetadataDefaultValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + private String normalizeMetadataTypeEAttributeName(EDataType eAttributeType) { + if (isEcoreDataType(eAttributeType)) { + String instanceClassName = eAttributeType.getInstanceClassName(); + try { + return Class.forName(instanceClassName).getSimpleName(); + } catch (ClassNotFoundException e) { + return instanceClassName; + } + } else { + return eAttributeType.getName(); + } + } + + private boolean isEcoreDataType(EDataType eAttributeType) { + return eAttributeType.getEPackage().getName().equalsIgnoreCase(ECORE_PACKAGE_NAME); + } + + private void setEClassMetadataIsManyValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + setBooleanValueCell(walker, eStructuralFeature.isMany()); + } + + private void setEClassMetadataIsRequiredValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + setBooleanValueCell(walker, eStructuralFeature.isRequired()); + } + + private void setEClassMetadataDefaultValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { if (eStructuralFeature instanceof EAttribute) { EAttribute eAttribute = (EAttribute) eStructuralFeature; @@ -464,21 +1096,78 @@ private void setMetadataDefaultValueCell(TableCellWalker walker, EStructuralFeat setVoidValueCell(walker); } - private int getEObjectID(EObject eObject) { + private void setEClassMetadataDocumentationValueCell(TableCellWalker walker, + EStructuralFeature eStructuralFeature) { + EAnnotation genModelAnnotation = eStructuralFeature.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); + + setMetadataDocumentationValueCell(walker, genModelAnnotation); + } + + private void setMetadataDocumentationValueCell(TableCellWalker walker, EAnnotation genModelAnnotation) { + if (genModelAnnotation != null) { + Map genModelAnnotationDetails = genModelAnnotation.getDetails().map(); + + if (genModelAnnotationDetails.containsKey(DOCUMENTATION_GENMODEL_DETAILS)) { + String documentation = genModelAnnotationDetails.get(DOCUMENTATION_GENMODEL_DETAILS); + setStringValueCell(walker, documentation); + } + } + + setVoidValueCell(walker); + } + + private int getEObjectIdentifier(EObject eObject) { return eObject.hashCode(); } - private String constructTableName(EClass eClass) { + private String constructEClassTableName(EClass eClass) { return eClass.getName(); } - private String constructMetadataTableName(EClass eClass) { + private String constructEEnumTableName(EEnum eEnum) { + return eEnum.getName(); + } + + private String constructEClassMetadataTableName(EClass eClass) { + return constructMetadataTableName(constructEClassTableName(eClass)); + } + + private String constructEEnumMetadataTableName(EEnum eEnum) { + return constructMetadataTableName(constructEEnumTableName(eEnum)); + } + + private String constructMetadataTableName(String metadataTableName) { StringBuilder sb = new StringBuilder(100); - sb.append(constructTableName(eClass)); + sb.append(metadataTableName); sb.append(" "); sb.append("( "); - sb.append("Metadata"); + sb.append(METADATA_TABLE_SUFFIX); sb.append(" )"); return sb.toString(); } + + private void adjustRowHeight(TableCellWalker walker, int linesCount) { + walker.setRowStyle(constructAdjustedHeightRowStyle(linesCount)); + } + + private TableRowStyle constructAdjustedHeightRowStyle(int linesCount) { + // @formatter:off + return TableRowStyle.builder("adjusted-height-row-style") + .defaultCellStyle(DEFAULT_BODY_CELL_STYLE) + .rowHeight(calculateRowHeight(linesCount)) + .build(); + // @formatter:on + } + + private SimpleLength calculateRowHeight(int linesCount) { + return SimpleLength.mm(linesCount * 5); + } + + private boolean isProcessed(Set eObjectsIdentifiers, EObject eObject) { + return eObjectsIdentifiers.contains(getEObjectIdentifier(eObject)); + } + + private List safeCopy(List eObjects) { + return EcoreUtil.copyAll(eObjects).stream().collect(toList()); + } } diff --git a/org.gecko.emf.exporter/bnd.bnd b/org.gecko.emf.exporter/bnd.bnd index acdb9452..cd9b577d 100644 --- a/org.gecko.emf.exporter/bnd.bnd +++ b/org.gecko.emf.exporter/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Version: 1.0.0.SNAPSHOT -Bundle-Name: Gecko EMF ODS Exporter -Bundle-Description: ODS (OpenDocument Spreadsheet) Exporter for EMF +Bundle-Name: Gecko EMF Exporter +Bundle-Description: Exporter for EMF -library: enable-emf diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java index c72c323c..71383db1 100644 --- a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportException.java @@ -11,6 +11,11 @@ */ package org.gecko.emf.exporter; +/** + * Exception which may be thrown during EMF export. + * + * @author Michal H. Siemaszko + */ public class EMFExportException extends Exception { /** serialVersionUID */ diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java index 29caeafa..a59502fc 100644 --- a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java @@ -11,10 +11,28 @@ */ package org.gecko.emf.exporter; +/** + * Defines export options which can be passed via options map. + * + * @author Michal H. Siemaszko + */ public interface EMFExportOptions { + // locale to use + String OPTION_LOCALE = "LOCALE"; + + // export non-containment references, in addition to containment references (exported by default) String OPTION_EXPORT_NONCONTAINMENT = "EXPORT_NONCONTAINMENT"; + // extract and export metadata as additional sheets String OPTION_EXPORT_METADATA = "EXPORT_METADATA"; + // automatically adjust column width based on contents - disabled by default until FastODS bug is fixed + String OPTION_ADJUST_COLUMN_WIDTH = "ADJUST_COLUMN_WIDTH"; + + // freeze header row - disabled by default until bug is fixed + String OPTION_FREEZE_HEADER_ROW = "FREEZE_HEADER_ROW"; + + // generate links for references + String OPTION_GENERATE_LINKS = "GENERATE_LINKS"; } diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java index b533b433..34ebfc1e 100644 --- a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExporter.java @@ -12,13 +12,21 @@ package org.gecko.emf.exporter; import java.io.OutputStream; -import java.util.Locale; +import java.util.List; import java.util.Map; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; +/** + * Defines methods for exporting EMF resources and lists of EMF objects. + * + * @author Michal H. Siemaszko + */ public interface EMFExporter { - void exportResourceTo(Resource t, Locale locale, OutputStream outputStream, Map options) + void exportResourceTo(Resource resource, OutputStream outputStream, Map options) throws EMFExportException; + + void exportEObjectsTo(List eObjects, OutputStream outputStream, Map options) throws EMFExportException; } diff --git a/org.gecko.emf.ods.tests/.classpath b/org.gecko.emf.ods.tests/.classpath new file mode 100644 index 00000000..66e477cd --- /dev/null +++ b/org.gecko.emf.ods.tests/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.gecko.emf.ods.tests/.gitignore b/org.gecko.emf.ods.tests/.gitignore new file mode 100644 index 00000000..7fdbdef7 --- /dev/null +++ b/org.gecko.emf.ods.tests/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/bin_test/ diff --git a/org.gecko.emf.ods.tests/.project b/org.gecko.emf.ods.tests/.project new file mode 100644 index 00000000..9fc82af5 --- /dev/null +++ b/org.gecko.emf.ods.tests/.project @@ -0,0 +1,23 @@ + + + org.gecko.emf.ods.tests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/org.gecko.emf.ods.tests/.settings/org.eclipse.core.resources.prefs b/org.gecko.emf.ods.tests/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..f2c16853 --- /dev/null +++ b/org.gecko.emf.ods.tests/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding/bnd.bnd=UTF-8 +encoding/test.bndrun=UTF-8 diff --git a/org.gecko.emf.ods.tests/.settings/org.eclipse.jdt.core.prefs b/org.gecko.emf.ods.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f2525a8b --- /dev/null +++ b/org.gecko.emf.ods.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,14 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/org.gecko.emf.ods.tests/bnd.bnd b/org.gecko.emf.ods.tests/bnd.bnd new file mode 100644 index 00000000..2e3084da --- /dev/null +++ b/org.gecko.emf.ods.tests/bnd.bnd @@ -0,0 +1,15 @@ +-enable-junit5: true +-library: enable-emf + +javac.source: 11 +javac.target: 11 + +Bundle-Version: 1.0.0.SNAPSHOT + +-buildpath: \ + org.gecko.emf.osgi.component,\ + org.eclipse.emf.ecore.xmi,\ + org.eclipse.emf.ecore,\ + org.gecko.emf.osgi.example.model.basic,\ + org.gecko.emf.exporter;version=latest,\ + org.apache.commons.commons-text diff --git a/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java new file mode 100644 index 00000000..ee537f21 --- /dev/null +++ b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2012 - 2022 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.tests; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.gecko.emf.ods.tests.helper.EMFODSResourceTestHelper.createBusinessPerson; +import static org.gecko.emf.ods.tests.helper.EMFODSResourceTestHelper.createFlintstonesFamily; +import static org.gecko.emf.ods.tests.helper.EMFODSResourceTestHelper.createSimpsonFamily; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Locale; +import java.util.Map; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.gecko.emf.exporter.EMFExportOptions; +import org.gecko.emf.ods.configuration.EMFODSResource; +import org.gecko.emf.osgi.example.model.basic.BasicFactory; +import org.gecko.emf.osgi.example.model.basic.BusinessPerson; +import org.gecko.emf.osgi.example.model.basic.Family; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.osgi.test.common.annotation.InjectService; +import org.osgi.test.common.service.ServiceAware; +import org.osgi.test.junit5.context.BundleContextExtension; +import org.osgi.test.junit5.service.ServiceExtension; + +/** + * EMF ODS Resource integration test. + * + * @author Michal H. Siemaszko + */ +@ExtendWith(BundleContextExtension.class) +@ExtendWith(ServiceExtension.class) +public class EMFODSResourceTest { + + @Test + public void testSaveODS(@InjectService(timeout = 2000) ServiceAware rsAware, + @InjectService(timeout = 2000) ServiceAware bfAware) throws Exception { + + assertNotNull(rsAware); + assertThat(rsAware.getServices()).hasSize(1); + ResourceSet resourceSet = rsAware.getService(); + assertNotNull(resourceSet); + + assertNotNull(bfAware); + assertThat(bfAware.getServices()).hasSize(1); + BasicFactory factoryImpl = bfAware.getService(); + assertNotNull(factoryImpl); + + Resource resource = resourceSet.createResource(URI.createURI("basicPackageExporterTest.ods")); + assertNotNull(resource); + assertTrue(resource instanceof EMFODSResource); + + Family simpsonFamily = createSimpsonFamily(factoryImpl); + resource.getContents().add(simpsonFamily); + + Family flintstonesFamily = createFlintstonesFamily(factoryImpl); + resource.getContents().add(flintstonesFamily); + + BusinessPerson businessPerson = createBusinessPerson(factoryImpl); + resource.getContents().add(businessPerson); + + Path filePath = Files.createTempFile("testBasicPackageExport", ".ods"); + + OutputStream fileOutputStream = Files.newOutputStream(filePath); + + // @formatter:off + resource.save(fileOutputStream, + Map.of( + EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, + EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, + EMFExportOptions.OPTION_EXPORT_METADATA, true, + EMFExportOptions.OPTION_GENERATE_LINKS, true)); + // @formatter:on + } +} diff --git a/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSResourceTestHelper.java b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSResourceTestHelper.java new file mode 100644 index 00000000..18ef905d --- /dev/null +++ b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/helper/EMFODSResourceTestHelper.java @@ -0,0 +1,370 @@ +/** + * Copyright (c) 2012 - 2023 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.tests.helper; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.UUID; + +import org.apache.commons.text.RandomStringGenerator; +import org.gecko.emf.osgi.example.model.basic.Address; +import org.gecko.emf.osgi.example.model.basic.BasicFactory; +import org.gecko.emf.osgi.example.model.basic.BusinessPerson; +import org.gecko.emf.osgi.example.model.basic.ContactContextType; +import org.gecko.emf.osgi.example.model.basic.ContactType; +import org.gecko.emf.osgi.example.model.basic.EmployeeInfo; +import org.gecko.emf.osgi.example.model.basic.Family; +import org.gecko.emf.osgi.example.model.basic.GenderType; +import org.gecko.emf.osgi.example.model.basic.Person; +import org.gecko.emf.osgi.example.model.basic.PersonContact; +import org.gecko.emf.osgi.example.model.basic.Tag; + +/** + * EMF ODS Resource integration test helper. + * + * @author Michal H. Siemaszko + */ +public class EMFODSResourceTestHelper { + + public static Family createSimpsonFamily(BasicFactory bf) { + Family simpsonFamily = bf.createFamily(); + simpsonFamily.setId("Simpsons"); + + Address address = createSimpsonsAddress(bf); + + Person homerSimpson = createHomerSimpson(bf, address); + simpsonFamily.setFather(homerSimpson); + + Person margeSimpson = createMargeSimpson(bf, address); + simpsonFamily.setMother(margeSimpson); + + Person bartSimpson = createBartSimpson(bf, address); + simpsonFamily.getChildren().add(bartSimpson); + + Person lisaSimpson = createLisaSimpson(bf, address); + simpsonFamily.getChildren().add(lisaSimpson); + + Person maggieSimpson = createMaggieSimpson(bf, address); + simpsonFamily.getChildren().add(maggieSimpson); + + homerSimpson.getRelatives().add(margeSimpson); + homerSimpson.getRelatives().add(bartSimpson); + homerSimpson.getRelatives().add(lisaSimpson); + homerSimpson.getRelatives().add(maggieSimpson); + + margeSimpson.getRelatives().add(homerSimpson); + margeSimpson.getRelatives().add(bartSimpson); + margeSimpson.getRelatives().add(lisaSimpson); + margeSimpson.getRelatives().add(maggieSimpson); + + bartSimpson.getRelatives().add(homerSimpson); + bartSimpson.getRelatives().add(margeSimpson); + bartSimpson.getRelatives().add(lisaSimpson); + bartSimpson.getRelatives().add(maggieSimpson); + + lisaSimpson.getRelatives().add(homerSimpson); + lisaSimpson.getRelatives().add(margeSimpson); + lisaSimpson.getRelatives().add(bartSimpson); + lisaSimpson.getRelatives().add(maggieSimpson); + + maggieSimpson.getRelatives().add(homerSimpson); + maggieSimpson.getRelatives().add(margeSimpson); + maggieSimpson.getRelatives().add(lisaSimpson); + maggieSimpson.getRelatives().add(maggieSimpson); + + homerSimpson.getTags().add(createMultiLevelTag(bf, createUniquePrefix(10))); + + homerSimpson.setBigInt(BigInteger.TEN); + + homerSimpson.getBigDec().add(BigDecimal.ZERO); + homerSimpson.getBigDec().add(BigDecimal.ONE); + homerSimpson.getBigDec().add(BigDecimal.TEN); + + homerSimpson.setImage(createByteArr()); + + homerSimpson.getProperties().putAll(createProperties(createUniquePrefix(10))); + + return simpsonFamily; + } + + private static Address createSimpsonsAddress(BasicFactory bf) { + return createAddress(bf, "742 Evergreen Terrace", "Springfield", "97482"); + } + + private static Person createHomerSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Homer", "Simpson", GenderType.MALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createMargeSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Marge", "Simpson", GenderType.FEMALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createBartSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Bart", "Simpson", GenderType.MALE, address); + + return p; + } + + private static Person createLisaSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Lisa", "Simpson", GenderType.FEMALE, address); + + return p; + } + + private static Person createMaggieSimpson(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Maggie", "Simpson", GenderType.FEMALE, address); + + return p; + } + + public static Family createFlintstonesFamily(BasicFactory bf) { + Family flintstonesFamily = bf.createFamily(); + flintstonesFamily.setId("Flintstones"); + + Address address = createFlintstonesAddress(bf); + + Person fredFlintstone = createFredFlintstone(bf, address); + flintstonesFamily.setFather(fredFlintstone); + + Person wilmaFlintstone = createWilmaFlintstone(bf, address); + flintstonesFamily.setMother(wilmaFlintstone); + + Person pebblesFlintstone = createPebblesFlintstone(bf, address); + flintstonesFamily.getChildren().add(pebblesFlintstone); + + Person stonyFlintstone = createStonyFlintstone(bf, address); + flintstonesFamily.getChildren().add(stonyFlintstone); + + fredFlintstone.getRelatives().add(wilmaFlintstone); + fredFlintstone.getRelatives().add(pebblesFlintstone); + fredFlintstone.getRelatives().add(stonyFlintstone); + + wilmaFlintstone.getRelatives().add(fredFlintstone); + wilmaFlintstone.getRelatives().add(pebblesFlintstone); + wilmaFlintstone.getRelatives().add(stonyFlintstone); + + pebblesFlintstone.getRelatives().add(fredFlintstone); + pebblesFlintstone.getRelatives().add(wilmaFlintstone); + pebblesFlintstone.getRelatives().add(stonyFlintstone); + + stonyFlintstone.getRelatives().add(fredFlintstone); + stonyFlintstone.getRelatives().add(wilmaFlintstone); + stonyFlintstone.getRelatives().add(pebblesFlintstone); + + fredFlintstone.getTags().add(createMultiLevelTag(bf, createUniquePrefix(10))); + + fredFlintstone.setBigInt(BigInteger.TEN); + + fredFlintstone.getBigDec().add(BigDecimal.ZERO); + fredFlintstone.getBigDec().add(BigDecimal.ONE); + fredFlintstone.getBigDec().add(BigDecimal.TEN); + + fredFlintstone.setImage(createByteArr()); + + fredFlintstone.getProperties().putAll(createProperties(createUniquePrefix(10))); + + return flintstonesFamily; + } + + private static Address createFlintstonesAddress(BasicFactory bf) { + return createAddress(bf, "301 Cobblestone Way", "Bedrock", "70777"); + } + + private static Person createFredFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Fred", "Flintstone", GenderType.MALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createWilmaFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Wilma", "Flintstone", GenderType.FEMALE, address); + + p.getContact().add(createHomePhonePersonContact(bf, p)); + p.getContact().add(createHomeMobilePersonContact(bf, p)); + p.getContact().add(createHomeWhatsAppPersonContact(bf, p)); + p.getContact().add(createHomeEmailPersonContact(bf, p)); + p.getContact().add(createHomeSkypePersonContact(bf, p)); + p.getContact().add(createHomeWebAddressPersonContact(bf, p)); + + return p; + } + + private static Person createPebblesFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Pebbles", "Flintstone", GenderType.FEMALE, address); + + return p; + } + + private static Person createStonyFlintstone(BasicFactory bf, Address address) { + Person p = createPerson(bf, "Stony", "Flintstone", GenderType.MALE, address); + + return p; + } + + public static BusinessPerson createBusinessPerson(BasicFactory bf) { + BusinessPerson bp = bf.createBusinessPerson(); + + bp.setId(UUID.randomUUID().toString()); + bp.setFirstName("Thomas"); + bp.setLastName("Edison"); + bp.setGender(GenderType.MALE); + + bp.setCompanyIdCardNumber(UUID.randomUUID().toString()); + + EmployeeInfo nikolaTesla = bf.createEmployeeInfo(); + nikolaTesla.setPosition("one-time employee"); + bp.getEmployeeInfo().add(nikolaTesla); + + return bp; + } + + private static Person createPerson(BasicFactory bf, String firstName, String lastName, GenderType gender, + Address address) { + Person p = bf.createPerson(); + + p.setId(UUID.randomUUID().toString()); + p.setFirstName(firstName); + p.setLastName(lastName); + p.setGender(gender); + + p.setAddress(address); + + return p; + } + + private static Address createAddress(BasicFactory bf, String street, String city, String zip) { + Address a = bf.createAddress(); + + a.setId(UUID.randomUUID().toString()); + a.setStreet(street); + a.setCity(city); + a.setZip(zip); + + return a; + } + + private static PersonContact createHomePhonePersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.PHONE, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeMobilePersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.MOBILE, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeWhatsAppPersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.WHATSAPP, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeEmailPersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.EMAIL, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeSkypePersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.SKYPE, ContactContextType.HOME, UUID.randomUUID().toString(), p); + } + + private static PersonContact createHomeWebAddressPersonContact(BasicFactory bf, Person p) { + return createPersonContact(bf, ContactType.WEBADDRESS, ContactContextType.HOME, UUID.randomUUID().toString(), + p); + } + + private static PersonContact createPersonContact(BasicFactory bf, ContactType type, ContactContextType context, + String value, Person p) { + PersonContact pc = bf.createPersonContact(); + + pc.setContext(context); + pc.setType(type); + pc.setValue(value); + + pc.setContactPerson(p); + + return pc; + } + + private static Tag createMultiLevelTag(BasicFactory bf, String namePrefix) { + Tag t1 = createTag(bf, namePrefix, "tag_level_1", "tag_level_1_value", "tag_level_1_description"); + + t1.setTag(createTag(bf, namePrefix, "tag_level_2", "tag_level_2_value", "tag_level_2_description")); + + t1.getTags().add(createTag(bf, namePrefix, "tag_level_3", "tag_level_3_value", "tag_level_3_description")); + + return t1; + } + + private static Tag createTag(BasicFactory bf, String namePrefix, String name, String value, String description) { + Tag t = bf.createTag(); + + t.setName(namePrefix + "_" + name); + t.setValue(value); + t.setDescription(description); + + return t; + } + + private static byte[] createByteArr() { + byte[] b = new byte[20]; + new Random().nextBytes(b); + return b; + } + + private static Map createProperties(String namePrefix) { + Map props = new HashMap(); + + props.put(createPropertyName(namePrefix, "prop_1"), "prop_1_value"); + props.put(createPropertyName(namePrefix, "prop_2"), "prop_2_value"); + props.put(createPropertyName(namePrefix, "prop_3"), "prop_3_value"); + props.put(createPropertyName(namePrefix, "prop_4"), "prop_4_value"); + + return props; + } + + private static String createPropertyName(String prefix, String name) { + return (prefix + "_" + name); + } + + private static String createUniquePrefix(int maxChars) { + // @formatter:off + return new RandomStringGenerator.Builder() + .withinRange('a', 'z') + .build() + .generate(maxChars); + // @formatter:on + } +} diff --git a/org.gecko.emf.ods.tests/test.bndrun b/org.gecko.emf.ods.tests/test.bndrun new file mode 100644 index 00000000..a9388c60 --- /dev/null +++ b/org.gecko.emf.ods.tests/test.bndrun @@ -0,0 +1,54 @@ +-runfw: org.apache.felix.framework;version='[7.0.1,7.0.1]' +-runprovidedcapabilities: ${native_capability} + +-resolve.effective: active + +-runbundles.junit5: ${test.runbundles} + +-runbundles: \ + junit-jupiter-api;version='[5.8.2,5.8.3)',\ + junit-platform-commons;version='[1.8.2,1.8.3)',\ + org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.eclipse.emf.common;version='[2.23.0,2.23.1)',\ + org.eclipse.emf.ecore;version='[2.25.0,2.25.1)',\ + org.eclipse.emf.ecore.xmi;version='[2.16.0,2.16.1)',\ + org.gecko.emf.osgi.api;version='[4.1.1,4.1.2)',\ + org.gecko.emf.osgi.component;version='[4.1.1,4.1.2)',\ + org.gecko.emf.osgi.example.model.basic;version='[4.1.1,4.1.2)',\ + org.opentest4j;version='[1.2.0,1.2.1)',\ + org.osgi.util.function;version='[1.1.0,1.1.1)',\ + org.osgi.util.pushstream;version='[1.0.1,1.0.2)',\ + org.apache.felix.converter;version='[1.0.18,1.0.19)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)',\ + org.gecko.emf.collections;version=snapshot,\ + assertj-core;version='[3.22.0,3.22.1)',\ + junit-jupiter-params;version='[5.8.2,5.8.3)',\ + org.osgi.test.common;version='[1.1.0,1.1.1)',\ + org.osgi.test.junit5;version='[1.1.0,1.1.1)',\ + com.fasterxml.jackson.core.jackson-annotations;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.core.jackson-core;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.core.jackson-databind;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.dataformat.jackson-dataformat-properties;version='[2.14.1,2.14.2)',\ + com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.14.1,2.14.2)',\ + de.undercouch.bson4jackson;version='[2.13.1,2.13.2)',\ + fastods;version='[0.8.1,0.8.2)',\ + org.apache.commons.commons-text;version='[1.10.0,1.10.1)',\ + org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ + org.eclipse.emfcloud.emfjson-jackson;version='[2.2.0,2.2.1)',\ + org.gecko.emf.exporter;version=snapshot,\ + org.gecko.emf.exporter.ods;version=snapshot,\ + org.gecko.emf.json;version=snapshot,\ + org.gecko.emf.ods;version=snapshot,\ + org.gecko.emf.ods.tests;version=snapshot,\ + org.yaml.snakeyaml;version='[1.33.0,1.33.1)' + +-runrequires: bnd.identity;id='org.gecko.emf.ods.tests' + +-runee: JavaSE-11 + +-runtrace: true + +-runproperties.debug: \ + felix.log.level=4,\ + org.osgi.service.log.admin.loglevel=DEBUG diff --git a/org.gecko.emf.ods/.classpath b/org.gecko.emf.ods/.classpath new file mode 100644 index 00000000..66e477cd --- /dev/null +++ b/org.gecko.emf.ods/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.gecko.emf.ods/.gitignore b/org.gecko.emf.ods/.gitignore new file mode 100644 index 00000000..7fdbdef7 --- /dev/null +++ b/org.gecko.emf.ods/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/bin_test/ diff --git a/org.gecko.emf.ods/.project b/org.gecko.emf.ods/.project new file mode 100644 index 00000000..b41fd5ed --- /dev/null +++ b/org.gecko.emf.ods/.project @@ -0,0 +1,23 @@ + + + org.gecko.emf.ods + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/org.gecko.emf.ods/.settings/org.eclipse.core.resources.prefs b/org.gecko.emf.ods/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..1554c6f8 --- /dev/null +++ b/org.gecko.emf.ods/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/bnd.bnd=UTF-8 diff --git a/org.gecko.emf.ods/.settings/org.eclipse.jdt.core.prefs b/org.gecko.emf.ods/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f2525a8b --- /dev/null +++ b/org.gecko.emf.ods/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,14 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/org.gecko.emf.ods/bnd.bnd b/org.gecko.emf.ods/bnd.bnd new file mode 100644 index 00000000..2d0b2dc2 --- /dev/null +++ b/org.gecko.emf.ods/bnd.bnd @@ -0,0 +1,8 @@ +Bundle-Version: 1.0.0.SNAPSHOT +Bundle-Name: Gecko EMF ODS Extension +Bundle-Description: Extension to save EMF objects to ODS using FastODS + +-library: enable-emf + +-buildpath: \ + org.gecko.emf.exporter diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/EMFODSResourceFactoryConfigurator.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/EMFODSResourceFactoryConfigurator.java new file mode 100644 index 00000000..24f5952b --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/EMFODSResourceFactoryConfigurator.java @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2012 - 2022 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods; + +import org.eclipse.emf.ecore.resource.Resource.Factory.Registry; +import org.gecko.emf.exporter.EMFExporter; +import org.gecko.emf.ods.configuration.EMFODSResource; +import org.gecko.emf.ods.configuration.EMFODSResourceFactory; +import org.gecko.emf.ods.constants.EMFODSConstants; +import org.gecko.emf.osgi.ResourceFactoryConfigurator; +import org.gecko.emf.osgi.annotation.EMFResourceFactoryConfigurator; +import org.gecko.emf.osgi.annotation.provide.ProvideEMFResourceConfigurator; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * Implementation of the {@link ResourceFactoryConfigurator} to provide support for {@link EMFODSResource}. + * + * It provides the {@link EMFODSResourceFactory} for the following identifiers: + *
    + *
  • Extension: ods + *
  • contentType: application/vnd.oasis.opendocument.spreadsheet + *
+ * + * @author Michal H. Siemaszko + */ +@Component(name = "EMFODSConfigurator", immediate = true, service = ResourceFactoryConfigurator.class) +//@formatter:off +@ProvideEMFResourceConfigurator( + name = EMFODSConstants.EMFODS_CAPABILITY_NAME, + contentType = { + EMFODSConstants.EMFODS_CONTENT_TYPE + }, + fileExtension = { + EMFODSConstants.EMFODS_FILE_EXTENSION + }, + version = "1.0.0" +) +@EMFResourceFactoryConfigurator( + name = EMFODSConstants.EMFODS_CAPABILITY_NAME, + fileExtension = { + EMFODSConstants.EMFODS_FILE_EXTENSION + }, + contentType = { + EMFODSConstants.EMFODS_CONTENT_TYPE + } + ) +//@formatter:on +public class EMFODSResourceFactoryConfigurator implements ResourceFactoryConfigurator { + + @Reference(target = ("(component.name=EMFODSExporter)")) + private EMFExporter emfODSExporter; + + /* + * (non-Javadoc) + * @see de.dim.emf.osgi.ResourceFactoryConfigurator#configureResourceFactory(org.eclipse.emf.ecore.resource.Resource.Factory.Registry) + */ + @Override + public void configureResourceFactory(Registry registry) { + registry.getExtensionToFactoryMap().put(EMFODSConstants.EMFODS_FILE_EXTENSION, createODSFactory()); + + registry.getContentTypeToFactoryMap().put(EMFODSConstants.EMFODS_CONTENT_TYPE, createODSFactory()); + } + + private EMFODSResourceFactory createODSFactory() { + return new EMFODSResourceFactory(emfODSExporter); + } + + /* + * (non-Javadoc) + * @see de.dim.emf.osgi.ResourceFactoryConfigurator#unconfigureResourceFactory(org.eclipse.emf.ecore.resource.Resource.Factory.Registry) + */ + @Override + public void unconfigureResourceFactory(Registry registry) { + registry.getExtensionToFactoryMap().remove(EMFODSConstants.EMFODS_FILE_EXTENSION); + + registry.getContentTypeToFactoryMap().remove(EMFODSConstants.EMFODS_CONTENT_TYPE); + } +} diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/RequireEMFODS.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/RequireEMFODS.java new file mode 100644 index 00000000..82e359cd --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/RequireEMFODS.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2012 - 2022 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.annotation; + +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.CLASS; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.gecko.emf.ods.constants.EMFODSConstants; +import org.gecko.emf.osgi.EMFNamespaces; +import org.gecko.emf.osgi.ResourceSetConfigurator; +import org.gecko.emf.osgi.annotation.require.RequireEMF; +import org.osgi.annotation.bundle.Requirement; + +@Documented +@Retention(CLASS) +@Target({ TYPE, PACKAGE }) +@Requirement( + namespace = EMFNamespaces.EMF_CONFIGURATOR_NAMESPACE, + name = ResourceSetConfigurator.EMF_CONFIGURATOR_NAME, + filter = "(" + EMFNamespaces.EMF_CONFIGURATOR_NAME + "=" + EMFODSConstants.EMFODS_CAPABILITY_NAME + ")" + ) +@RequireEMF + +/** + * Meta annotation to generate a Require Capability for EMF ODS + * + * @author Michal H. Siemaszko + */ +public @interface RequireEMFODS { + +} diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/package-info.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/package-info.java new file mode 100644 index 00000000..6a4b3cee --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/annotation/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package org.gecko.emf.ods.annotation; diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResource.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResource.java new file mode 100644 index 00000000..4cb5aefb --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResource.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2012 - 2022 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.configuration; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collections; +import java.util.Map; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.impl.ResourceImpl; +import org.gecko.emf.exporter.EMFExportException; +import org.gecko.emf.exporter.EMFExporter; + +/** + * A Resource implementation that writes its content in ODS. + * + * @author Michal H. Siemaszko + */ +public class EMFODSResource extends ResourceImpl { + private EMFExporter emfODSExporter; + + public EMFODSResource(URI uri) { + super(uri); + } + + public EMFODSResource(URI uri, EMFExporter emfODSExporter) { + super(uri); + + this.emfODSExporter = emfODSExporter; + } + + @Override + protected void doLoad(InputStream inputStream, Map options) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + protected void doSave(OutputStream outputStream, Map options) throws IOException { + if (options == null) { + options = Collections.emptyMap(); + } + + if (emfODSExporter != null) { + try { + emfODSExporter.exportResourceTo(this, outputStream, options); + } catch (EMFExportException e) { + throw new IOException(e); + } + } + } +} diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResourceFactory.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResourceFactory.java new file mode 100644 index 00000000..d71150b1 --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/EMFODSResourceFactory.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2012 - 2022 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.configuration; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceFactoryImpl; +import org.gecko.emf.exporter.EMFExporter; + +/** + * {@link ResourceFactoryImpl} for the ODS resource. + * + * @author Michal H. Siemaszko + */ +public class EMFODSResourceFactory extends ResourceFactoryImpl { + private EMFExporter emfODSExporter; + + /** + * Creates a new instance. + */ + public EMFODSResourceFactory() { + super(); + } + + public EMFODSResourceFactory(EMFExporter emfODSExporter) { + super(); + + this.emfODSExporter = emfODSExporter; + } + + /* + * (non-Javadoc) + * @see org.eclipse.emf.ecore.resource.impl.ResourceFactoryImpl#createResource(org.eclipse.emf.common.util.URI) + */ + @Override + public Resource createResource(URI uri) { + if (emfODSExporter != null) { + return new EMFODSResource(uri, emfODSExporter); + } else { + return new EMFODSResource(uri); + } + } +} diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/package-info.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/package-info.java new file mode 100644 index 00000000..2215f704 --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/configuration/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package org.gecko.emf.ods.configuration; diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/constants/EMFODSConstants.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/constants/EMFODSConstants.java new file mode 100644 index 00000000..00b02bc1 --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/constants/EMFODSConstants.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2012 - 2022 Data In Motion and others. + * All rights reserved. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Data In Motion - initial API and implementation + */ +package org.gecko.emf.ods.constants; + +/** + * Constants used as options during load/save operations on an EMF ODS Resource. + * + * @author Michal H. Siemaszko + */ +public interface EMFODSConstants { + + /** Constant for the general Capability Namespace **/ + static final String EMFODS_CAPABILITY_NAME = "EMFODS"; + + static final String EMFODS_FILE_EXTENSION = "ods"; + + static final String EMFODS_CONTENT_TYPE = "application/vnd.oasis.opendocument.spreadsheet"; +} \ No newline at end of file diff --git a/org.gecko.emf.ods/src/org/gecko/emf/ods/constants/package-info.java b/org.gecko.emf.ods/src/org/gecko/emf/ods/constants/package-info.java new file mode 100644 index 00000000..c155e878 --- /dev/null +++ b/org.gecko.emf.ods/src/org/gecko/emf/ods/constants/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package org.gecko.emf.ods.constants; From bc56ff6c7a8095b98e3bc704c22581f79c2df8ad Mon Sep 17 00:00:00 2001 From: "Michael H. Siemaszko" Date: Sun, 12 Mar 2023 20:41:14 +0100 Subject: [PATCH 3/6] Replaced FastODS with SODS Signed-off-by: Michael H. Siemaszko --- cnf/central.mvn | 3 - org.gecko.emf.exporter.ods.tests/bnd.bnd | 3 +- .../emf/ods/tests/EMFODSExporterTest.java | 13 +- org.gecko.emf.exporter.ods.tests/test.bndrun | 9 +- org.gecko.emf.exporter.ods/bnd.bnd | 4 +- .../emf/exporter/ods/EMFODSExporter.java | 950 ++++++++---------- org.gecko.emf.exporter/bnd.bnd | 15 +- .../gecko/emf/exporter/EMFExportOptions.java | 10 +- .../emf/ods/tests/EMFODSResourceTest.java | 5 +- org.gecko.emf.ods.tests/test.bndrun | 8 +- org.gecko.emf.ods/bnd.bnd | 2 +- .../required.bndrun | 10 +- 12 files changed, 455 insertions(+), 577 deletions(-) diff --git a/cnf/central.mvn b/cnf/central.mvn index bb64092d..6fa68df7 100644 --- a/cnf/central.mvn +++ b/cnf/central.mvn @@ -150,7 +150,6 @@ org.geckoprojects.bnd:org.gecko.bnd.dimc.library:1.1.1 org.geckoprojects.bnd:org.gecko.bnd.osgitest.library:1.1.1 org.geckoprojects.bnd:org.gecko.bnd.jacoco.library:1.1.1 -#org.geckoprojects.emf:org.gecko.emf.osgi.api:4.1.1.202202162308 org.geckoprojects.emf:org.gecko.emf.osgi.bnd.library.workspace:4.1.1-SNAPSHOT com.fasterxml.jackson.core:jackson-core:2.14.1 @@ -163,8 +162,6 @@ de.undercouch:bson4jackson:2.13.1 org.yaml:snakeyaml:1.33 org.geckoprojects.emf:org.gecko.emf.osgi.example.model.basic:4.1.1-SNAPSHOT -com.github.jferard:fastods:0.8.1 - org.apache.commons:commons-text:1.10.0 org.apache.commons:commons-lang3:3.12.0 diff --git a/org.gecko.emf.exporter.ods.tests/bnd.bnd b/org.gecko.emf.exporter.ods.tests/bnd.bnd index 6727dd65..12c04331 100644 --- a/org.gecko.emf.exporter.ods.tests/bnd.bnd +++ b/org.gecko.emf.exporter.ods.tests/bnd.bnd @@ -13,4 +13,5 @@ Bundle-Version: 1.0.0.SNAPSHOT org.gecko.emf.osgi.example.model.basic,\ org.gecko.emf.exporter;version=latest,\ org.apache.commons.commons-text,\ - org.gecko.emf.util.model + org.gecko.emf.util.model,\ + com.github.miachm.sods diff --git a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java index 8b94511f..25ec87ac 100644 --- a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java +++ b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java @@ -37,7 +37,6 @@ import org.gecko.emf.osgi.example.model.basic.Family; import org.gecko.emf.utilities.Request; import org.gecko.emf.utilities.UtilitiesFactory; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -102,13 +101,14 @@ public void testExportBasicPackageResourceToOds( Map.of( EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, - EMFExportOptions.OPTION_EXPORT_METADATA, true, - EMFExportOptions.OPTION_GENERATE_LINKS, true) + EMFExportOptions.OPTION_EXPORT_METADATA, true, + EMFExportOptions.OPTION_ADJUST_COLUMN_WIDTH, true + // EMFExportOptions.OPTION_GENERATE_LINKS, true // TODO: linking is currently not supported in SODS + ) ); // @formatter:on } - @Disabled @Test public void testExportUtilitiesPackageResourceToOds( @InjectService(cardinality = 1, timeout = 4000, filter = "(component.name=EMFODSExporter)") ServiceAware emfOdsExporterAware) @@ -129,8 +129,9 @@ public void testExportUtilitiesPackageResourceToOds( Map.of( EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, - EMFExportOptions.OPTION_EXPORT_METADATA, true, - EMFExportOptions.OPTION_GENERATE_LINKS, true) + EMFExportOptions.OPTION_EXPORT_METADATA, true + // EMFExportOptions.OPTION_GENERATE_LINKS, true // TODO: linking is currently not supported in SODS + ) ); // @formatter:on } diff --git a/org.gecko.emf.exporter.ods.tests/test.bndrun b/org.gecko.emf.exporter.ods.tests/test.bndrun index 9857f67b..d034cf11 100644 --- a/org.gecko.emf.exporter.ods.tests/test.bndrun +++ b/org.gecko.emf.exporter.ods.tests/test.bndrun @@ -22,7 +22,6 @@ org.osgi.util.pushstream;version='[1.0.1,1.0.2)',\ org.apache.felix.converter;version='[1.0.18,1.0.19)',\ org.osgi.util.promise;version='[1.2.0,1.2.1)',\ - org.gecko.emf.collections;version=snapshot,\ assertj-core;version='[3.22.0,3.22.1)',\ junit-jupiter-params;version='[5.8.2,5.8.3)',\ org.osgi.test.common;version='[1.1.0,1.1.1)',\ @@ -36,15 +35,15 @@ com.fasterxml.jackson.core.jackson-databind;version='[2.14.1,2.14.2)',\ com.fasterxml.jackson.dataformat.jackson-dataformat-properties;version='[2.14.1,2.14.2)',\ com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.14.1,2.14.2)',\ - com.google.guava;version='[31.1.0,31.1.1)',\ - com.google.guava.failureaccess;version='[1.0.1,1.0.2)',\ de.undercouch.bson4jackson;version='[2.13.1,2.13.2)',\ - fastods;version='[0.8.1,0.8.2)',\ org.apache.commons.commons-text;version='[1.10.0,1.10.1)',\ org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ org.eclipse.emfcloud.emfjson-jackson;version='[2.2.0,2.2.1)',\ org.gecko.emf.json;version=snapshot,\ - org.gecko.emf.util.model;version=snapshot + org.gecko.emf.util.model;version=snapshot,\ + org.osgi.service.cm;version='[1.6.0,1.6.1)',\ + com.github.miachm.sods;version='[1.5.3,1.5.4)',\ + org.gecko.emf.bson;version=snapshot -runrequires: bnd.identity;id='org.gecko.emf.exporter.ods.tests' diff --git a/org.gecko.emf.exporter.ods/bnd.bnd b/org.gecko.emf.exporter.ods/bnd.bnd index f7b20e01..9fc5e408 100644 --- a/org.gecko.emf.exporter.ods/bnd.bnd +++ b/org.gecko.emf.exporter.ods/bnd.bnd @@ -6,9 +6,9 @@ Bundle-Description: ODS (OpenDocument Spreadsheet) Exporter for EMF -buildpath: \ org.gecko.emf.exporter,\ - fastods;version='0.8',\ org.apache.commons.commons-text;version='1.10',\ - com.google.guava;version='31.1' + com.google.guava;version='31.1',\ + com.github.miachm.sods Private-Package: \ org.gecko.emf.exporter.ods diff --git a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java index d0303993..7b8e3fdc 100644 --- a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java +++ b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java @@ -13,7 +13,6 @@ import static java.util.stream.Collectors.toList; -import java.io.IOException; import java.io.OutputStream; import java.util.Collection; import java.util.Collections; @@ -26,10 +25,7 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.commons.text.StringEscapeUtils; -import org.apache.commons.text.WordUtils; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; @@ -47,21 +43,11 @@ import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ServiceScope; -import com.github.jferard.fastods.AnonymousOdsFileWriter; -import com.github.jferard.fastods.FastOdsException; -import com.github.jferard.fastods.OdsDocument; -import com.github.jferard.fastods.OdsFactory; -import com.github.jferard.fastods.Table; -import com.github.jferard.fastods.TableCellWalker; -import com.github.jferard.fastods.Text; -import com.github.jferard.fastods.TextBuilder; -import com.github.jferard.fastods.attribute.BorderStyle; -import com.github.jferard.fastods.attribute.CellAlign; -import com.github.jferard.fastods.attribute.SimpleColor; -import com.github.jferard.fastods.attribute.SimpleLength; -import com.github.jferard.fastods.style.TableCellStyle; -import com.github.jferard.fastods.style.TableColumnStyle; -import com.github.jferard.fastods.style.TableRowStyle; +import com.github.miachm.sods.Color; +import com.github.miachm.sods.Range; +import com.github.miachm.sods.Sheet; +import com.github.miachm.sods.SpreadSheet; +import com.github.miachm.sods.Style; /** * Implementation of the {@link EMFExporter} to provide support for exporting EMF resources and lists of EMF objects to ODS format. @@ -72,47 +58,35 @@ public class EMFODSExporter implements EMFExporter { private static final int MAX_CHAR_PER_LINE_DEFAULT = 30; - - // @formatter:off - private static final TableCellStyle HEADER_CELL_STYLE = TableCellStyle.builder("header-cell-style") - .backgroundColor(SimpleColor.GRAY64) - .fontWeightBold() - .build(); - // @formatter:on - - // @formatter:off - public static final TableCellStyle DEFAULT_BODY_CELL_STYLE = TableCellStyle.builder("default-body-cell-style") - .borderAll(SimpleLength.mm(0.5), SimpleColor.BLUE, BorderStyle.OUTSET) - .fontColor(SimpleColor.BLACK) - .textAlign(CellAlign.CENTER) - .fontWeightNormal() - .build(); - // @formatter:on - - // @formatter:off - public static final TableRowStyle BODY_ROW_STYLE = TableRowStyle.builder("body-row-style") - .defaultCellStyle(DEFAULT_BODY_CELL_STYLE) - .optimalHeight() - .build(); - // @formatter:on - - // @formatter:off - public static final TableColumnStyle BODY_COLUMN_STYLE = TableColumnStyle.builder("body-column-style") - .optimalWidth() // see: https://github.com/jferard/fastods/wiki/Tutorial#rows-and-columns-styles (...) There's an optimal height/width in the OpenDocument specification (20.383 and 20.384) but LO does not understand it, and FastODS won't compute this optimal value from the cell contents. (...) - .build(); - // @formatter:on - - private static final List METADATA_ECLASS_TABLE_HEADERS = List.of("Name", "Type", "isMany", "isRequired", + + private static final Style HEADER_STYLE = new Style(); + static { + HEADER_STYLE.setBackgroundColor(new Color("#a3a3a3")); + HEADER_STYLE.setFontColor(new Color("#000000")); + HEADER_STYLE.setBold(true); + HEADER_STYLE.setTextAligment(Style.TEXT_ALIGMENT.Center); + } + + private static final Style WRAPPED_DATA_CELL_STYLE = new Style(); + static { + WRAPPED_DATA_CELL_STYLE.setWrap(true); + } + + private static final List METADATA_ECLASS_SHEET_HEADERS = List.of("Name", "Type", "isMany", "isRequired", "Default value", "Documentation"); - private static final List METADATA_EENUM_TABLE_HEADERS = List.of("Name", "Literal", "Value", + private static final List METADATA_EENUM_SHEET_HEADERS = List.of("Name", "Literal", "Value", "Documentation"); - private static final String METADATA_TABLE_SUFFIX = "Metadata"; + private static final String METADATA_SHEET_SUFFIX = "Metadata"; private static final String DOCUMENTATION_GENMODEL_SOURCE = "http://www.eclipse.org/emf/2002/GenModel"; private static final String DOCUMENTATION_GENMODEL_DETAILS = "documentation"; - + private static final String ECORE_PACKAGE_NAME = "ecore"; + private final static char CR = (char) 0x0D; + private final static char LF = (char) 0x0A; + private final static String DATA_CELL_LINE_SEPARATOR = "" + CR + LF; + /* * (non-Javadoc) * @see org.gecko.emf.exporter.EMFExporter#exportResourceTo(org.eclipse.emf.ecore.resource.Resource, java.io.OutputStream, java.util.Map) @@ -147,18 +121,14 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, final Map exportOptions = validateExportOptions(options); - final OdsFactory odsFactory = OdsFactory.create(java.util.logging.Logger.getLogger("EMFODSExporter"), - locale(exportOptions)); + SpreadSheet document = new SpreadSheet(); - final AnonymousOdsFileWriter writer = odsFactory.createWriter(); + // maps sheet names to instances of sheets + final Map eClassesSheets = new HashMap(); - final OdsDocument document = writer.document(); - - // maps table names to instances of tables - final Map eClassesTables = new HashMap(); - - // maps EObjects' unique identifiers (obtained from their hash codes) to instances of tables, so those can be looked up e.g. when constructing links - final Map eObjectsTables = new HashMap(); + // maps EObjects' unique identifiers (obtained from their hash codes) to + // instances of sheets, so those can be looked up e.g. when constructing links + final Map eObjectsSheets = new HashMap(); // stores EObjects' EClasses - used e.g. to construct meta data final Set eObjectsClasses = new HashSet(); @@ -166,7 +136,8 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, // stores EEnums - used e.g. to construct meta data final Set eObjectsEnums = new HashSet(); - // maps EObjects' unique identifiers to pseudo IDs - for those EObjects which lack id field + // maps EObjects' unique identifiers to pseudo IDs - for those EObjects which + // lack id field final Map eObjectsPseudoIDs = new HashMap(); final List eObjectsSafeCopy = safeCopy(eObjects); @@ -175,12 +146,12 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, generatePseudoIDs(eObjectsSafeCopy, eObjectsPseudoIDs); // @formatter:off - createTables(document, - eClassesTables, + createSheets(document, + eClassesSheets, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, - eObjectsTables, + eObjectsSheets, exportNonContainmentEnabled(exportOptions), exportMetadataEnabled(exportOptions), freezeHeaderRowEnabled(exportOptions), @@ -189,12 +160,12 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, // @formatter:on // @formatter:off - createTablesBodies(document, - eClassesTables, + createSheetsData(document, + eClassesSheets, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, - eObjectsTables, + eObjectsSheets, exportNonContainmentEnabled(exportOptions), exportMetadataEnabled(exportOptions), generateLinksEnabled(exportOptions), @@ -205,7 +176,7 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, exportMetadata(document, eObjectsClasses, eObjectsEnums); } - writer.save(outputStream); + document.save(outputStream); } catch (Exception e) { throw new EMFExportException(e); @@ -275,22 +246,22 @@ private String getPseudoID(EObject eObject, Map eObjectsPseudoI return eObjectsPseudoIDs.get(getEObjectIdentifier(eObject)); } - private void createTables(OdsDocument document, Map eClassesTables, Set eObjectsClasses, - Set eObjectsEnums, Map eObjectsPseudoIDs, Map eObjectsTables, + private void createSheets(SpreadSheet document, Map eClassesSheets, Set eObjectsClasses, + Set eObjectsEnums, Map eObjectsPseudoIDs, Map eObjectsSheets, boolean exportNonContainment, boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, - List eObjects) throws IOException { + List eObjects) { final Set processedEObjectsIdentifiers = new HashSet(); for (EObject eObject : eObjects) { // @formatter:off - createTableForEObjectWithEReferences(document, - eClassesTables, + createSheetForEObjectWithEReferences(document, + eClassesSheets, processedEObjectsIdentifiers, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, - eObjectsTables, + eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, @@ -300,22 +271,22 @@ private void createTables(OdsDocument document, Map eClassesTable } } - private void createTablesBodies(OdsDocument document, Map eClassesTables, - Set eObjectsClasses, Set eObjectsEnums, Map eObjectsPseudoIDs, - Map eObjectsTables, boolean exportNonContainment, boolean exportMetadata, - boolean generateLinks, List eObjects) throws IOException, EMFExportException { + private void createSheetsData(SpreadSheet document, Map eClassesSheets, Set eObjectsClasses, + Set eObjectsEnums, Map eObjectsPseudoIDs, Map eObjectsSheets, + boolean exportNonContainment, boolean exportMetadata, boolean generateLinks, List eObjects) + throws EMFExportException { final Set processedEObjectsIdentifiers = new HashSet(); for (EObject eObject : eObjects) { // @formatter:off - createTableBodyForEObjectWithEReferences(document, - eClassesTables, + createSheetDataForEObjectWithEReferences(document, + eClassesSheets, processedEObjectsIdentifiers, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, - eObjectsTables, + eObjectsSheets, exportNonContainment, exportMetadata, generateLinks, @@ -323,47 +294,46 @@ private void createTablesBodies(OdsDocument document, Map eClasse // @formatter:on } } - - private void createTableForEObjectWithEReferences(OdsDocument document, Map eClassesTables, + + private void createSheetForEObjectWithEReferences(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, - Map eObjectsPseudoIDs, Map eObjectsTables, boolean exportNonContainment, - boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject) - throws IOException { - createTable(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, - eObjectsTables, exportNonContainment, exportMetadata, freezeHeaderRow, adjustColumnWidth, eObject); + Map eObjectsPseudoIDs, Map eObjectsSheets, boolean exportNonContainment, + boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject) { + createSheet(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, + eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, adjustColumnWidth, eObject); eObject.eClass().getEAllReferences().stream().forEach(r -> { - createTableForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, - eObjectsPseudoIDs, eObjectsTables, exportNonContainment, exportMetadata, freezeHeaderRow, + createSheetForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, + eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, adjustColumnWidth, eObject, r); }); } - private void createTableBodyForEObjectWithEReferences(OdsDocument document, Map eClassesTables, + private void createSheetDataForEObjectWithEReferences(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, - Map eObjectsPseudoIDs, Map eObjectsTables, boolean exportNonContainment, - boolean exportMetadata, boolean generateLinks, EObject eObject) throws IOException, EMFExportException { - createTableBody(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsTables, + Map eObjectsPseudoIDs, Map eObjectsSheets, boolean exportNonContainment, + boolean exportMetadata, boolean generateLinks, EObject eObject) throws EMFExportException { + createSheetData(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, generateLinks, eObject); eObject.eClass().getEAllReferences().stream().forEach(r -> { try { - createTableBodyForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, - eObjectsTables, exportNonContainment, generateLinks, eObject, r); + createSheetDataForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, + eObjectsSheets, exportNonContainment, generateLinks, eObject, r); } catch (EMFExportException e) { e.printStackTrace(); } }); } - private void createTable(OdsDocument document, Map eClassesTables, Set eObjectsIdentifiers, + private void createSheet(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, Map eObjectsPseudoIDs, - Map eObjectsTables, boolean exportNonContainment, boolean exportMetadata, - boolean freezeHeaderRow, boolean adjustColumnWidth, EObject... eObjects) throws IOException { + Map eObjectsSheets, boolean exportNonContainment, boolean exportMetadata, + boolean freezeHeaderRow, boolean adjustColumnWidth, EObject... eObjects) { if ((eObjects.length > 0) && !isProcessed(eObjectsIdentifiers, eObjects[0])) { EClass eClass = eObjects[0].eClass(); - Table table = getOrAddTable(document, eClassesTables, eClass, eObjectsEnums, + Sheet sheet = getOrAddSheet(document, eClassesSheets, eClass, eObjectsEnums, hasPseudoID(eObjects[0], eObjectsPseudoIDs), exportMetadata, freezeHeaderRow, adjustColumnWidth); for (EObject eObject : eObjects) { @@ -371,39 +341,59 @@ private void createTable(OdsDocument document, Map eClassesTables eObjectsIdentifiers.add(eObjectIdentifier); eObjectsClasses.add(eObject.eClass()); - eObjectsTables.put(eObjectIdentifier, table); + eObjectsSheets.put(eObjectIdentifier, sheet); eObject.eClass().getEAllReferences().stream().forEach(r -> { - createTableForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, - eObjectsEnums, eObjectsPseudoIDs, eObjectsTables, exportNonContainment, exportMetadata, + createSheetForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, + eObjectsEnums, eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, adjustColumnWidth, eObject, r); }); } } } - private void createTableBody(OdsDocument document, Map eClassesTables, + @SuppressWarnings("unchecked") + private void createSheetForEReference(SpreadSheet document, Map eClassesSheets, + Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, + Map eObjectsPseudoIDs, Map eObjectsSheets, boolean exportNonContainment, + boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject, EReference r) { + if (!exportNonContainment && !r.isContainment()) { + return; + } + + Object value = eObject.eGet(r); + + if (value != null) { + if (!r.isMany() && value instanceof EObject) { + createSheet(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, + eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, + adjustColumnWidth, (EObject) value); + } else if (r.isMany()) { + createSheet(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, + eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, + adjustColumnWidth, ((List) value).toArray(EObject[]::new)); + } + } + } + + private void createSheetData(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Map eObjectsPseudoIDs, - Map eObjectsTables, boolean exportNonContainment, boolean generateLinks, - EObject... eObjects) throws IOException, EMFExportException { + Map eObjectsSheets, boolean exportNonContainment, boolean generateLinks, + EObject... eObjects) throws EMFExportException { if ((eObjects.length > 0) && !isProcessed(eObjectsIdentifiers, eObjects[0])) { EClass eClass = eObjects[0].eClass(); - Table table = getTable(eClassesTables, eClass); - - final TableCellWalker walker = table.getWalker(); - - walker.lastRow(); + Sheet sheet = getSheet(eClassesSheets, eClass); for (EObject eObject : eObjects) { eObjectsIdentifiers.add(getEObjectIdentifier(eObject)); - createTableBody(walker, eObject, eObjectsPseudoIDs, eObjectsTables, generateLinks); + createSheetData(sheet, eObject, eObjectsPseudoIDs, eObjectsSheets, generateLinks); eObject.eClass().getEAllReferences().stream().forEach(r -> { try { - createTableBodyForEReference(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, - eObjectsTables, exportNonContainment, generateLinks, eObject, r); + createSheetDataForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, + eObjectsSheets, exportNonContainment, generateLinks, eObject, r); } catch (EMFExportException e) { e.printStackTrace(); } @@ -413,10 +403,10 @@ private void createTableBody(OdsDocument document, Map eClassesTa } @SuppressWarnings("unchecked") - private void createTableForEReference(OdsDocument document, Map eClassesTables, - Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, - Map eObjectsPseudoIDs, Map eObjectsTables, boolean exportNonContainment, - boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject, EReference r) { + private void createSheetDataForEReference(SpreadSheet document, Map eClassesSheets, + Set eObjectsIdentifiers, Map eObjectsPseudoIDs, + Map eObjectsSheets, boolean exportNonContainment, boolean generateLinks, EObject eObject, + EReference r) throws EMFExportException { if (!exportNonContainment && !r.isContainment()) { return; } @@ -425,196 +415,150 @@ private void createTableForEReference(OdsDocument document, Map e if (value != null) { if (!r.isMany() && value instanceof EObject) { - try { - createTable(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, - eObjectsPseudoIDs, eObjectsTables, exportNonContainment, exportMetadata, freezeHeaderRow, - adjustColumnWidth, (EObject) value); - } catch (IOException e) { - e.printStackTrace(); - } + createSheetData(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsSheets, + exportNonContainment, generateLinks, (EObject) value); } else if (r.isMany()) { - try { - createTable(document, eClassesTables, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, - eObjectsPseudoIDs, eObjectsTables, exportNonContainment, exportMetadata, freezeHeaderRow, - adjustColumnWidth, ((List) value).toArray(EObject[]::new)); - } catch (IOException e) { - e.printStackTrace(); - } + createSheetData(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsSheets, + exportNonContainment, generateLinks, ((List) value).toArray(EObject[]::new)); } } } - @SuppressWarnings("unchecked") - private void createTableBodyForEReference(OdsDocument document, Map eClassesTables, - Set eObjectsIdentifiers, Map eObjectsPseudoIDs, - Map eObjectsTables, boolean exportNonContainment, boolean generateLinks, EObject eObject, - EReference r) throws EMFExportException { - if (!exportNonContainment && !r.isContainment()) { - return; - } + private void createSheetData(Sheet sheet, EObject eObject, Map eObjectsPseudoIDs, + Map eObjectsSheets, boolean generateLinks) { - Object value = eObject.eGet(r); + sheet.appendRow(); - if (value != null) { - if (!r.isMany() && value instanceof EObject) { - try { - createTableBody(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsTables, - exportNonContainment, generateLinks, (EObject) value); - } catch (IOException e) { - e.printStackTrace(); - } - } else if (r.isMany()) { - try { - createTableBody(document, eClassesTables, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsTables, - exportNonContainment, generateLinks, ((List) value).toArray(EObject[]::new)); - } catch (IOException e) { - e.printStackTrace(); - } - } + Range sheetDataRow = sheet.getRange((sheet.getMaxRows() - 1), 0, 1, sheet.getMaxColumns()); + + List eAllStructuralFeatures = eObject.eClass().getEAllStructuralFeatures(); + + int columnsCount = eAllStructuralFeatures.size(); + + for (int colIndex = 0; colIndex < columnsCount; colIndex++) { + + createSheetDataCell(sheetDataRow, colIndex, eObject, eAllStructuralFeatures.get(colIndex), + eObjectsPseudoIDs, eObjectsSheets, generateLinks); + } + + if (hasPseudoID(eObject, eObjectsPseudoIDs)) { + setStringValueCell(sheetDataRow, columnsCount, eObjectsPseudoIDs.get(getEObjectIdentifier(eObject))); } } - - private Table getOrAddTable(OdsDocument document, Map eClassesTables, EClass eClass, + + private Sheet getOrAddSheet(SpreadSheet document, Map eClassesSheets, EClass eClass, Set eObjectsEnums, boolean hasPseudoID, boolean exportMetadata, boolean freezeHeaderRow, - boolean adjustColumnWidth) throws IOException { - String tableName = constructEClassTableName(eClass); + boolean adjustColumnWidth) { + String tableName = constructEClassSheetName(eClass); - boolean tableExists = eClassesTables.containsKey(tableName); - Table table; + boolean tableExists = eClassesSheets.containsKey(tableName); + Sheet sheet; if (tableExists) { - table = eClassesTables.get(tableName); + sheet = eClassesSheets.get(tableName); } else { - table = document.addTable(tableName); - eClassesTables.put(tableName, table); + sheet = new Sheet(tableName); + document.appendSheet(sheet); + eClassesSheets.put(tableName, sheet); if (exportMetadata) { - addMetadataTable(document, eClass); + addMetadataSheet(document, eClass); } } - final TableCellWalker walker = table.getWalker(); - if (!tableExists) { - // because com.github.jferard.fastods.TableCellWalker.getColumnCount() returns incorrect values - filed as FastODS bug (https://github.com/jferard/fastods/issues/244) - int headersCount = createTableHeader(walker, eClass, eObjectsEnums, hasPseudoID, adjustColumnWidth); + createSheetHeader(sheet, eClass, eObjectsEnums, hasPseudoID, adjustColumnWidth); if (freezeHeaderRow) { - freezeTableHeader(document, table, 1, headersCount); + // TODO: freezing rows is currently not supported in SODS + // freezeTableHeader(document, sheet, 1, headersCount); } } - walker.nextRow(); - - return table; - } - - private void freezeTableHeader(OdsDocument document, Table table, int rowCount, int colCount) { - // FIXME: does not produce expected result, i.e. freezed header row - filed as FastODS bug (https://github.com/jferard/fastods/issues/143) - document.freezeCells(table, rowCount, colCount); + return sheet; } - private Table getTable(Map eClassesTables, EClass eClass) throws EMFExportException { - String tableName = constructEClassTableName(eClass); + private Sheet getSheet(Map eObjectsSheets, EClass eClass) throws EMFExportException { + String sheetName = constructEClassSheetName(eClass); - if (!eClassesTables.containsKey(tableName)) { - throw new EMFExportException("Table '" + tableName + "' does not exist!"); + if (!eObjectsSheets.containsKey(sheetName)) { + throw new EMFExportException("Sheet '" + sheetName + "' does not exist!"); } - return eClassesTables.get(tableName); + return eObjectsSheets.get(sheetName); } - private void addMetadataTable(OdsDocument document, EClass eClass) throws IOException { - document.addTable(constructEClassMetadataTableName(eClass)); - } - - private int createTableHeader(TableCellWalker walker, EClass eClass, Set eObjectsEnums, boolean hasPseudoID, - boolean adjustColumnWidth) throws IOException { - walker.setRowStyle(BODY_ROW_STYLE); - if (!adjustColumnWidth) { - walker.setColumnStyle(BODY_COLUMN_STYLE); - } - - AtomicInteger headersCount = new AtomicInteger(0); + private void createSheetHeader(Sheet sheet, EClass eClass, Set eObjectsEnums, boolean hasPseudoID, + boolean adjustColumnWidth) { - AtomicInteger eStructuralFeaturesCount = new AtomicInteger(eClass.getEAllStructuralFeatures().size()); + List eAllStructuralFeatures = eClass.getEAllStructuralFeatures(); - eClass.getEAllStructuralFeatures().forEach(eStructuralFeature -> { + int columnsCount = eAllStructuralFeatures.size(); - if (isEcoreEEnumDataType(eStructuralFeature)) { - eObjectsEnums.add(extractEEnumDataType(eStructuralFeature)); - } + sheet.appendColumns((hasPseudoID ? (columnsCount + 1) : columnsCount) - 1); // newly created sheet already has + // one column - createTableHeaderCell(walker, eStructuralFeature, adjustColumnWidth, headersCount.get()); + Range sheetHeaderRow = sheet.getRange(0, 0, 1, sheet.getMaxColumns()); // newly created sheet already has one + // row + sheetHeaderRow.setStyle(HEADER_STYLE); - // because com.github.jferard.fastods.TableCellWalker.getColumnCount() returns incorrect values - filed as FastODS bug (https://github.com/jferard/fastods/issues/244) - int currentHeadersCount = headersCount.incrementAndGet(); + for (int colIndex = 0; colIndex < columnsCount; colIndex++) { - boolean hasNext = (currentHeadersCount < eStructuralFeaturesCount.get()); + EStructuralFeature eStructuralFeature = eAllStructuralFeatures.get(colIndex); - if (hasNext) { - walker.next(); + if (isEcoreEEnumDataType(eStructuralFeature)) { + eObjectsEnums.add(extractEEnumDataType(eStructuralFeature)); } - }); - - if (hasPseudoID) { - walker.next(); - createTableHeaderCell(walker, "id", adjustColumnWidth, headersCount.get(), 36); + createSheetHeaderCell(sheetHeaderRow, eStructuralFeature, adjustColumnWidth, colIndex); + } - headersCount.getAndIncrement(); + if (hasPseudoID) { + createSheetHeaderCell(sheetHeaderRow, "id", adjustColumnWidth, columnsCount); } + } - return headersCount.get(); - } - - private void createTableHeaderCell(TableCellWalker walker, EStructuralFeature eStructuralFeature, + private void createSheetHeaderCell(Range sheetHeaderRow, EStructuralFeature eStructuralFeature, boolean adjustColumnWidth, int colIndex) { - String tableHeaderName = constructTableHeaderName(eStructuralFeature); + String tableHeaderName = constructSheetHeaderName(eStructuralFeature); + + createSheetHeaderCell(sheetHeaderRow, tableHeaderName, adjustColumnWidth, colIndex); + } - createTableHeaderCell(walker, tableHeaderName); + private void createSheetHeaderCell(Range sheetHeaderRow, String tableHeaderName, boolean adjustColumnWidth, + int colIndex) { + createSheetHeaderCell(sheetHeaderRow, colIndex, tableHeaderName); if (adjustColumnWidth) { - adjustColumnWidth(walker, colIndex, tableHeaderName.length()); + adjustColumnWidth(sheetHeaderRow.getSheet(), colIndex, tableHeaderName.length()); } } - private void createTableHeaderCell(TableCellWalker walker, String tableHeaderName, boolean adjustColumnWidth, - int colIndex, int charsCount) { - createTableHeaderCell(walker, tableHeaderName); + private void createSheetHeaderCell(Range sheetHeaderRow, int colIndex, String tableHeaderName) { + sheetHeaderRow.getCell(0, colIndex).setValue(tableHeaderName); + } - if (adjustColumnWidth) { - adjustColumnWidth(walker, colIndex, charsCount); - } + private void adjustColumnWidth(Sheet sheet, int colIndex, int charsCount) { + sheet.setColumnWidth(colIndex, calculateColumnWidth(charsCount)); } - - private void adjustColumnWidth(TableCellWalker walker, int colIndex, int charsCount) { - TableColumnStyle adjustedWithColumnStyle = constructAdjustedWithColumnStyle(charsCount); - - // FIXME: neither of these produce expected result, i.e. varied column width - filed as FastODS bug (https://github.com/jferard/fastods/issues/243) - // walker.setColumnStyle(adjustedWithColumnStyle); - walker.getTable().setColumnStyle(colIndex, adjustedWithColumnStyle); - } - - private TableColumnStyle constructAdjustedWithColumnStyle(int charsCount) { - // @formatter:off - return TableColumnStyle.builder("adjusted-with-column-style") - .columnWidth(calculateColumnWidth(charsCount)) - .build(); - // @formatter:on + + private Double calculateColumnWidth(int charsCount) { + return (Double.valueOf(charsCount) * (charsCount > 3 ? 5 : 10)); + } + + private void adjustRowHeight(Sheet sheet, int rowIndex, String value) { + sheet.setRowHeight(rowIndex, calculateRowHeight(value)); } - - private SimpleLength calculateColumnWidth(int charsCount) { - SimpleLength columnWidth = SimpleLength.mm(charsCount * 10); - return columnWidth; + private Double calculateRowHeight(String value) { + return (Double.valueOf(value.length() / MAX_CHAR_PER_LINE_DEFAULT) * 5); } - private void createTableHeaderCell(TableCellWalker walker, String tableHeaderName) { - walker.setStringValue(tableHeaderName); - walker.setStyle(HEADER_CELL_STYLE); + @Deprecated + private void freezeSheetHeaderRow(Sheet sheet, int rowCount, int colCount) { + // TODO: freezing rows is currently not supported in SODS } - private String constructTableHeaderName(EStructuralFeature eStructuralFeature) { + private String constructSheetHeaderName(EStructuralFeature eStructuralFeature) { StringBuilder sb = new StringBuilder(100); if (eStructuralFeature instanceof EReference) { sb.append("ref_"); @@ -632,29 +576,9 @@ private EEnum extractEEnumDataType(EStructuralFeature eStructuralFeature) { return ((EEnum) ((EAttribute) eStructuralFeature).getEAttributeType()); } - private void createTableBody(TableCellWalker walker, EObject eObject, Map eObjectsPseudoIDs, - Map eObjectsTables, boolean generateLinks) throws IOException { - eObject.eClass().getEAllStructuralFeatures().forEach(eStructuralFeature -> { - - walker.setRowStyle(BODY_ROW_STYLE); - walker.setColumnStyle(BODY_COLUMN_STYLE); - - createTableBodyCell(walker, eObject, eStructuralFeature, eObjectsPseudoIDs, eObjectsTables, generateLinks); - - walker.next(); - }); - - if (hasPseudoID(eObject, eObjectsPseudoIDs)) { - setStringValueCell(walker, eObjectsPseudoIDs.get(getEObjectIdentifier(eObject))); - - walker.next(); - } - - walker.nextRow(); - } - - private void createTableBodyCell(TableCellWalker walker, EObject eObject, EStructuralFeature eStructuralFeature, - Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { + private void createSheetDataCell(Range sheetDataRow, int colIndex, EObject eObject, + EStructuralFeature eStructuralFeature, Map eObjectsPseudoIDs, + Map eObjectsSheets, boolean generateLinks) { if (eStructuralFeature instanceof EAttribute) { EAttribute eAttribute = (EAttribute) eStructuralFeature; @@ -663,179 +587,150 @@ private void createTableBodyCell(TableCellWalker walker, EObject eObject, EStruc if (!eAttribute.isMany()) { if (value instanceof Date) { - setDateValueCell(walker, (Date) value); + setDateValueCell(sheetDataRow, colIndex, (Date) value); } else if (value instanceof Number) { - setNumberValueCell(walker, (Number) value); + setNumberValueCell(sheetDataRow, colIndex, (Number) value); } else if (value instanceof Boolean) { - setBooleanValueCell(walker, (Boolean) value); + setBooleanValueCell(sheetDataRow, colIndex, (Boolean) value); } else if (value instanceof byte[]) { // TODO: clarify how byte arrays should be handled - walker.setStringValue("EAttribute: byte[]"); + setStringValueCell(sheetDataRow, colIndex, "EAttribute: byte[]"); } else { - setStringValueCell(walker, EcoreUtil.convertToString(eAttribute.getEAttributeType(), value)); + setStringValueCell(sheetDataRow, colIndex, + EcoreUtil.convertToString(eAttribute.getEAttributeType(), value)); } } else { - setMultiValueCell(walker, eAttribute, value); + setMultiValueCell(sheetDataRow, colIndex, eAttribute, value); } } else { - setVoidValueCell(walker); + setVoidValueCell(sheetDataRow, colIndex); } } else if (eStructuralFeature instanceof EReference) { EReference eReference = (EReference) eStructuralFeature; - setEReferenceValueCell(walker, eObject, eReference, eObjectsPseudoIDs, eObjectsTables, generateLinks); + setEReferenceValueCell(sheetDataRow, colIndex, eObject, eReference, eObjectsPseudoIDs, eObjectsSheets, + generateLinks); } } @SuppressWarnings("unchecked") - private void setEReferenceValueCell(TableCellWalker walker, EObject eObject, EReference r, - Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { + private void setEReferenceValueCell(Range sheetDataRow, int colIndex, EObject eObject, EReference r, + Map eObjectsPseudoIDs, Map eObjectsSheets, boolean generateLinks) { Object value = eObject.eGet(r); if (value != null) { if (!r.isMany() && value instanceof EObject) { - setOneEReferenceValueCell(walker, (EObject) value, eObjectsPseudoIDs, eObjectsTables, generateLinks); - } else if (r.isMany()) { - setManyEReferencesValueCell(walker, ((List) value), eObjectsPseudoIDs, eObjectsTables, + setOneEReferenceValueCell(sheetDataRow, colIndex, (EObject) value, eObjectsPseudoIDs, eObjectsSheets, generateLinks); + } else if (r.isMany()) { + setManyEReferencesValueCell(sheetDataRow, colIndex, ((List) value), eObjectsPseudoIDs, + eObjectsSheets, generateLinks); } } } - private void setOneEReferenceValueCell(TableCellWalker walker, EObject eObject, - Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { + private void setOneEReferenceValueCell(Range sheetDataRow, int colIndex, EObject eObject, + Map eObjectsPseudoIDs, Map eObjectsSheets, boolean generateLinks) { Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); if (hasID(eObject)) { - if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { - setLinkedIDEReferenceValueCell(walker, getID(eObject), eObjectsTables.get(eObjectIdentifier)); + if (generateLinks && eObjectsSheets.containsKey(eObjectIdentifier)) { + setLinkedIDEReferenceValueCell(sheetDataRow, colIndex, getID(eObject), + eObjectsSheets.get(eObjectIdentifier)); } else { - setNonLinkedIDEReferenceValueCell(walker, getID(eObject)); + setNonLinkedIDEReferenceValueCell(sheetDataRow, colIndex, getID(eObject)); } } else if (hasPseudoID(eObject, eObjectsPseudoIDs)) { - if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { - setLinkedIDEReferenceValueCell(walker, getPseudoID(eObject, eObjectsPseudoIDs), - eObjectsTables.get(eObjectIdentifier)); + if (generateLinks && eObjectsSheets.containsKey(eObjectIdentifier)) { + setLinkedIDEReferenceValueCell(sheetDataRow, colIndex, getPseudoID(eObject, eObjectsPseudoIDs), + eObjectsSheets.get(eObjectIdentifier)); } else { - setNonLinkedIDEReferenceValueCell(walker, getPseudoID(eObject, eObjectsPseudoIDs)); + setNonLinkedIDEReferenceValueCell(sheetDataRow, colIndex, getPseudoID(eObject, eObjectsPseudoIDs)); } } else { - setNoIDEReferenceValueCell(walker, eObject); + setNoIDEReferenceValueCell(sheetDataRow, colIndex, eObject); } } - private void setManyEReferencesValueCell(TableCellWalker walker, List eObjects, - Map eObjectsPseudoIDs, Map eObjectsTables, boolean generateLinks) { - TextBuilder textBuilder = Text.builder(); + private void setManyEReferencesValueCell(Range sheetDataRow, int colIndex, List eObjects, + Map eObjectsPseudoIDs, Map eObjectsSheets, boolean generateLinks) { - for (EObject eObject : eObjects) { - Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); + StringBuilder sb = new StringBuilder(); + for (EObject eObject : eObjects) { if (hasID(eObject)) { - if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { - textBuilder = setLinkedIDEReferenceValueCell(textBuilder, getID(eObject), - eObjectsTables.get(eObjectIdentifier)); - } else { - textBuilder = setNonLinkedIDEReferenceValueCell(textBuilder, getID(eObject)); - } + sb.append(getID(eObject)); + sb.append(DATA_CELL_LINE_SEPARATOR); // TODO: this has no effect - all lines are output on same line; + // must be taken care of on SODS side } else if (hasPseudoID(eObject, eObjectsPseudoIDs)) { - if (generateLinks && eObjectsTables.containsKey(eObjectIdentifier)) { - textBuilder = setLinkedIDEReferenceValueCell(textBuilder, getPseudoID(eObject, eObjectsPseudoIDs), - eObjectsTables.get(eObjectIdentifier)); - } else { - textBuilder = setNonLinkedIDEReferenceValueCell(textBuilder, - getPseudoID(eObject, eObjectsPseudoIDs)); - } + sb.append(getPseudoID(eObject, eObjectsPseudoIDs)); + sb.append(DATA_CELL_LINE_SEPARATOR); } else { - setNoIDEReferenceValueCell(walker, eObject); + sb.append("EReference: " + eObject.eClass().getName()); + sb.append(DATA_CELL_LINE_SEPARATOR); } } - Text text = textBuilder.build(); - walker.setText(text); - - // adjust row height based on number of EObjects - adjustRowHeight(walker, eObjects.size()); - } - - private void setLinkedIDEReferenceValueCell(TableCellWalker walker, String refId, Table refTable) { - walker.setText(setLinkedIDEReferenceValueCell(Text.builder(), refId, refTable).build()); - } - - private TextBuilder setLinkedIDEReferenceValueCell(TextBuilder textBuilder, String refId, Table refTable) { - return textBuilder.par().link(refId, refTable); + setStringValueCell(sheetDataRow, colIndex, sb.toString()); } - private void setNonLinkedIDEReferenceValueCell(TableCellWalker walker, String refId) { - walker.setText(setNonLinkedIDEReferenceValueCell(Text.builder(), refId).build()); + private void setLinkedIDEReferenceValueCell(Range sheetDataRow, int colIndex, String refId, Sheet refSheet) { + setNonLinkedIDEReferenceValueCell(sheetDataRow, colIndex, refId); // FIXME: links are not supported yet in SODS } - private TextBuilder setNonLinkedIDEReferenceValueCell(TextBuilder textBuilder, String refId) { - return textBuilder.parContent(refId); + private void setNonLinkedIDEReferenceValueCell(Range sheetDataRow, int colIndex, String refId) { + setStringValueCell(sheetDataRow, colIndex, refId); } - private void setNoIDEReferenceValueCell(TableCellWalker walker, EObject eObject) { - walker.setStringValue("EReference: " + eObject.eClass().getName()); + private void setNoIDEReferenceValueCell(Range sheetDataRow, int colIndex, EObject eObject) { + setStringValueCell(sheetDataRow, colIndex, "EReference: " + eObject.eClass().getName()); } - private void setStringValueCell(TableCellWalker walker, String value) { - if (value.length() <= MAX_CHAR_PER_LINE_DEFAULT) { - walker.setStringValue(value); - } else { - setMultilineTextCell(walker, value); - } - } + private void setStringValueCell(Range sheetDataRow, int colIndex, String value) { + sheetDataRow.getCell(0, colIndex).setValue(value); - private void setMultilineTextCell(TableCellWalker walker, String value) { - String wrapped = WordUtils.wrap(value, MAX_CHAR_PER_LINE_DEFAULT, System.lineSeparator(), false); + if (value.length() > MAX_CHAR_PER_LINE_DEFAULT) { + sheetDataRow.getCell(0, colIndex).setStyle(WRAPPED_DATA_CELL_STYLE); - String[] pieces = wrapped.split(System.lineSeparator()); - - TextBuilder textBuilder = Text.builder(); - for (String piece : pieces) { - textBuilder = textBuilder.parContent(StringEscapeUtils.escapeXml11(piece)); + adjustRowHeight(sheetDataRow.getSheet(), sheetDataRow.getRow(), value); } - Text text = textBuilder.build(); - walker.setText(text); - - // adjust row height based on number of new lines - adjustRowHeight(walker, pieces.length); } - private void setDateValueCell(TableCellWalker walker, Date value) { - walker.setDateValue(value); + private void setDateValueCell(Range sheetDataRow, int colIndex, Date value) { + sheetDataRow.getCell(0, colIndex).setValue(value); } - private void setNumberValueCell(TableCellWalker walker, Number value) { - walker.setFloatValue(value.floatValue()); + private void setNumberValueCell(Range sheetDataRow, int colIndex, Number value) { + sheetDataRow.getCell(0, colIndex).setValue(value.floatValue()); } - private void setBooleanValueCell(TableCellWalker walker, Boolean value) { - walker.setBooleanValue(value.booleanValue()); + private void setBooleanValueCell(Range sheetDataRow, int colIndex, Boolean value) { + sheetDataRow.getCell(0, colIndex).setValue(value.booleanValue()); } @SuppressWarnings("unchecked") - private void setMultiValueCell(TableCellWalker walker, EAttribute eAttribute, Object multiValue) { - TextBuilder textBuilder = Text.builder(); + private void setMultiValueCell(Range sheetDataRow, int colIndex, EAttribute eAttribute, Object multiValue) { + StringBuilder sb = new StringBuilder(); Collection values = (Collection) multiValue; + for (Object value : values) { - textBuilder.parContent(EcoreUtil.convertToString(eAttribute.getEAttributeType(), value)); + sb.append(EcoreUtil.convertToString(eAttribute.getEAttributeType(), value)); + sb.append(DATA_CELL_LINE_SEPARATOR); } - Text text = textBuilder.build(); - walker.setText(text); + setStringValueCell(sheetDataRow, colIndex, sb.toString()); } - private void setVoidValueCell(TableCellWalker walker) { - walker.setVoidValue(); + private void setVoidValueCell(Range sheetDataRow, int colIndex) { + sheetDataRow.getCell(0, colIndex).clear(); } private Locale locale(Map exportOptions) { @@ -855,11 +750,15 @@ private boolean adjustColumnWidthEnabled(Map exportOptions) { } private boolean freezeHeaderRowEnabled(Map exportOptions) { - return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_FREEZE_HEADER_ROW, Boolean.FALSE)); + // TODO: freezing rows is currently not supported in SODS + // return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_FREEZE_HEADER_ROW, Boolean.FALSE)); + return false; } private boolean generateLinksEnabled(Map exportOptions) { - return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_GENERATE_LINKS, Boolean.FALSE)); + // TODO: linking is currently not supported in SODS + // return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_GENERATE_LINKS, Boolean.FALSE)); + return false; } private Map validateExportOptions(Map options) { @@ -870,190 +769,167 @@ private Map validateExportOptions(Map options) { } } - private void exportMetadata(OdsDocument document, Set eClasses, Set eEnums) - throws IOException, FastOdsException { + private void addMetadataSheet(SpreadSheet document, EClass eClass) { + document.appendSheet(new Sheet(constructEClassMetadataSheetName(eClass))); + } + + private Sheet addMetadataSheet(SpreadSheet document, EEnum eEnum) { + Sheet metadataSheet = new Sheet(constructEEnumMetadataSheetName(eEnum)); + document.appendSheet(metadataSheet); + return metadataSheet; + } + + private void exportMetadata(SpreadSheet document, Set eClasses, Set eEnums) { exportEClassesMetadata(document, eClasses); exportEEnumsMetadata(document, eEnums); } - private void exportEClassesMetadata(OdsDocument document, Set eClasses) - throws IOException, FastOdsException { + private void exportEClassesMetadata(SpreadSheet document, Set eClasses) { for (EClass eClass : eClasses) { - String metadataTableName = constructEClassMetadataTableName(eClass); + Sheet metadataSheet = document.getSheet(constructEClassMetadataSheetName(eClass)); + + createEClassMetadataSheetHeader(metadataSheet); - Table metadataTable = document.getTable(metadataTableName); + createEClassMetadataSheetData(metadataSheet, eClass); + } + } - final TableCellWalker walker = metadataTable.getWalker(); + private void exportEEnumsMetadata(SpreadSheet document, Set eEnums) { + for (EEnum eEnum : eEnums) { - createEClassMetadataTableHeader(walker); + Sheet metadataSheet = addMetadataSheet(document, eEnum); - walker.nextRow(); + createEEnumMetadataSheetHeader(metadataSheet); - createEClassMetadataTableBody(walker, eClass); + createEEnumMetadataSheetData(metadataSheet, eEnum); } } - private void exportEEnumsMetadata(OdsDocument document, Set eEnums) throws IOException, FastOdsException { - for (EEnum eEnum : eEnums) { - - String metadataTableName = constructEEnumMetadataTableName(eEnum); + private void createEClassMetadataSheetHeader(Sheet metadataSheet) { + createMetadataSheetHeader(metadataSheet, METADATA_ECLASS_SHEET_HEADERS); + } - Table metadataTable = document.addTable(metadataTableName); + private void createEEnumMetadataSheetHeader(Sheet metadataSheet) { + createMetadataSheetHeader(metadataSheet, METADATA_EENUM_SHEET_HEADERS); + } - final TableCellWalker walker = metadataTable.getWalker(); + private void createMetadataSheetHeader(Sheet metadataSheet, List headers) { + int columnsCount = headers.size(); - createEEnumMetadataTableHeader(walker); + metadataSheet.appendColumns(columnsCount - 1); - walker.nextRow(); + Range metadataSheetHeaderRow = metadataSheet.getRange(0, 0, 1, metadataSheet.getMaxColumns()); + metadataSheetHeaderRow.setStyle(HEADER_STYLE); - createEEnumMetadataTableBody(walker, eEnum); + for (int colIndex = 0; colIndex < metadataSheet.getMaxColumns(); colIndex++) { + createMetadataSheetHeaderCell(metadataSheetHeaderRow, colIndex, headers.get(colIndex)); } } - private void createEClassMetadataTableHeader(TableCellWalker walker) throws IOException { - METADATA_ECLASS_TABLE_HEADERS.forEach(h -> { - walker.setRowStyle(BODY_ROW_STYLE); - walker.setColumnStyle(BODY_COLUMN_STYLE); - walker.setStyle(HEADER_CELL_STYLE); - walker.setStringValue(h); - walker.next(); - }); + private void createMetadataSheetHeaderCell(Range metadataSheetHeaderRow, int colIndex, String headerName) { + metadataSheetHeaderRow.getCell(0, colIndex).setValue(headerName); } - private void createEEnumMetadataTableHeader(TableCellWalker walker) throws IOException { - METADATA_EENUM_TABLE_HEADERS.forEach(h -> { - walker.setRowStyle(BODY_ROW_STYLE); - walker.setColumnStyle(BODY_COLUMN_STYLE); - walker.setStyle(HEADER_CELL_STYLE); - walker.setStringValue(h); - walker.next(); - }); - } + private void createEClassMetadataSheetData(Sheet metadataSheet, EClass eClass) { + eClass.getEAnnotations(); // TODO: clarify regarding instance-level docs - private void createEClassMetadataTableBody(TableCellWalker walker, EClass eClass) throws IOException { eClass.getEAllStructuralFeatures().forEach(eStructuralFeature -> { - - createEClassMetadataTableBodyCell(walker, eStructuralFeature); - - try { - walker.nextRow(); - } catch (IOException e) { - e.printStackTrace(); - } + createEClassMetadataSheetDataRow(metadataSheet, eStructuralFeature); }); } - private void createEEnumMetadataTableBody(TableCellWalker walker, EEnum eEnum) throws IOException { + private void createEEnumMetadataSheetData(Sheet metadataSheet, EEnum eEnum) { eEnum.getEAnnotations(); // TODO: clarify regarding instance-level docs eEnum.getELiterals().forEach(eEnumLiteral -> { - - createEEnumMetadataTableBodyCell(walker, eEnumLiteral); - - try { - walker.nextRow(); - } catch (IOException e) { - e.printStackTrace(); - } + createEEnumMetadataSheetDataRow(metadataSheet, eEnumLiteral); }); } - private void createEEnumMetadataTableBodyCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { - walker.setRowStyle(BODY_ROW_STYLE); - walker.setColumnStyle(BODY_COLUMN_STYLE); - - // Name - setEEnumMetadataNameValueCell(walker, eEnumLiteral); - - walker.next(); - - // Literal - setEEnumMetadataLiteralValueCell(walker, eEnumLiteral); - - walker.next(); - - // Value - setEEnumMetadataValueValueCell(walker, eEnumLiteral); - - walker.next(); + private void createEClassMetadataSheetDataRow(Sheet metadataSheet, EStructuralFeature eStructuralFeature) { + metadataSheet.appendRow(); - // Documentation - setEEnumMetadataDocumentationValueCell(walker, eEnumLiteral); + for (int colIndex = 0; colIndex < metadataSheet.getMaxColumns(); colIndex++) { + Range metadataSheetDataRow = metadataSheet.getRange((metadataSheet.getMaxRows() - 1), 0, 1, + metadataSheet.getMaxColumns()); - walker.next(); + createEClassMetadataSheetDataCell(metadataSheetDataRow, colIndex, eStructuralFeature); + } } - private void setEEnumMetadataNameValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { - setStringValueCell(walker, eEnumLiteral.getName()); - } + private void createEEnumMetadataSheetDataRow(Sheet metadataSheet, EEnumLiteral eEnumLiteral) { + metadataSheet.appendRow(); - private void setEEnumMetadataLiteralValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { - setStringValueCell(walker, eEnumLiteral.getLiteral()); - } + for (int colIndex = 0; colIndex < metadataSheet.getMaxColumns(); colIndex++) { + Range metadataSheetDataRow = metadataSheet.getRange((metadataSheet.getMaxRows() - 1), 0, 1, + metadataSheet.getMaxColumns()); - private void setEEnumMetadataValueValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { - setNumberValueCell(walker, eEnumLiteral.getValue()); + createEEnumMetadataSheetDataCell(metadataSheetDataRow, colIndex, eEnumLiteral); + } } - private void setEEnumMetadataDocumentationValueCell(TableCellWalker walker, EEnumLiteral eEnumLiteral) { - EAnnotation genModelAnnotation = eEnumLiteral.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); - - setMetadataDocumentationValueCell(walker, genModelAnnotation); + private void createEClassMetadataSheetDataCell(Range metadataSheetDataRow, int colIndex, + EStructuralFeature eStructuralFeature) { + switch (colIndex) { + case 0: // Name + setEClassMetadataNameValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); + break; + case 1: // Type + setEClassMetadataTypeValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); + break; + case 2: // isMany + setEClassMetadataIsManyValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); + break; + case 3: // isRequired + setEClassMetadataIsRequiredValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); + break; + case 4: // Default value + setEClassMetadataDefaultValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); + break; + case 5: // Documentation + setEClassMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); + break; + } } - private void createEClassMetadataTableBodyCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { - walker.setRowStyle(BODY_ROW_STYLE); - walker.setColumnStyle(BODY_COLUMN_STYLE); - - // Name - setEClassMetadataNameValueCell(walker, eStructuralFeature); - - walker.next(); - - // Type - setEClassMetadataTypeValueCell(walker, eStructuralFeature); - - walker.next(); - - // isMany - setEClassMetadataIsManyValueCell(walker, eStructuralFeature); - - walker.next(); - - // isRequired - setEClassMetadataIsRequiredValueCell(walker, eStructuralFeature); - - walker.next(); - - // Default value - setEClassMetadataDefaultValueCell(walker, eStructuralFeature); - - walker.next(); - - // Documentation - setEClassMetadataDocumentationValueCell(walker, eStructuralFeature); - - walker.next(); + private void createEEnumMetadataSheetDataCell(Range metadataSheetDataRow, int colIndex, EEnumLiteral eEnumLiteral) { + switch (colIndex) { + case 0: // Name + setEEnumMetadataNameValueCell(metadataSheetDataRow, colIndex, eEnumLiteral); + break; + case 1: // Literal + setEEnumMetadataLiteralValueCell(metadataSheetDataRow, colIndex, eEnumLiteral); + break; + case 2: // Value + setEEnumMetadataValueValueCell(metadataSheetDataRow, colIndex, eEnumLiteral); + break; + case 3: // Documentation + setEEnumMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, eEnumLiteral); + break; + } } - private void setEClassMetadataNameValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { - setStringValueCell(walker, eStructuralFeature.getName()); + private void setEClassMetadataNameValueCell(Range metadataSheetDataRow, int colIndex, + EStructuralFeature eStructuralFeature) { + setStringValueCell(metadataSheetDataRow, colIndex, eStructuralFeature.getName()); } - private void setEClassMetadataTypeValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + private void setEClassMetadataTypeValueCell(Range metadataSheetDataRow, int colIndex, + EStructuralFeature eStructuralFeature) { if (eStructuralFeature instanceof EAttribute) { EAttribute eAttribute = (EAttribute) eStructuralFeature; - setStringValueCell(walker, normalizeMetadataTypeEAttributeName(eAttribute.getEAttributeType())); + setStringValueCell(metadataSheetDataRow, colIndex, + normalizeMetadataTypeEAttributeName(eAttribute.getEAttributeType())); } else if (eStructuralFeature instanceof EReference) { EReference eReference = (EReference) eStructuralFeature; - setStringValueCell(walker, eReference.getEReferenceType().getName()); + setStringValueCell(metadataSheetDataRow, colIndex, eReference.getEReferenceType().getName()); } else { - setVoidValueCell(walker); + setVoidValueCell(metadataSheetDataRow, colIndex); } } @@ -1074,95 +950,101 @@ private boolean isEcoreDataType(EDataType eAttributeType) { return eAttributeType.getEPackage().getName().equalsIgnoreCase(ECORE_PACKAGE_NAME); } - private void setEClassMetadataIsManyValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { - setBooleanValueCell(walker, eStructuralFeature.isMany()); + private void setEClassMetadataIsManyValueCell(Range metadataSheetDataRow, int colIndex, + EStructuralFeature eStructuralFeature) { + setBooleanValueCell(metadataSheetDataRow, colIndex, eStructuralFeature.isMany()); } - private void setEClassMetadataIsRequiredValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { - setBooleanValueCell(walker, eStructuralFeature.isRequired()); + private void setEClassMetadataIsRequiredValueCell(Range metadataSheetDataRow, int colIndex, + EStructuralFeature eStructuralFeature) { + setBooleanValueCell(metadataSheetDataRow, colIndex, eStructuralFeature.isRequired()); } - private void setEClassMetadataDefaultValueCell(TableCellWalker walker, EStructuralFeature eStructuralFeature) { + private void setEClassMetadataDefaultValueCell(Range metadataSheetDataRow, int colIndex, + EStructuralFeature eStructuralFeature) { if (eStructuralFeature instanceof EAttribute) { EAttribute eAttribute = (EAttribute) eStructuralFeature; if (eAttribute.getDefaultValue() != null) { - setStringValueCell(walker, + setStringValueCell(metadataSheetDataRow, colIndex, EcoreUtil.convertToString(eAttribute.getEAttributeType(), eAttribute.getDefaultValue())); return; } } - setVoidValueCell(walker); + setVoidValueCell(metadataSheetDataRow, colIndex); } - private void setEClassMetadataDocumentationValueCell(TableCellWalker walker, + private void setEClassMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, EStructuralFeature eStructuralFeature) { EAnnotation genModelAnnotation = eStructuralFeature.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); - setMetadataDocumentationValueCell(walker, genModelAnnotation); + setMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, genModelAnnotation); + } + + private void setEEnumMetadataNameValueCell(Range metadataSheetDataRow, int colIndex, EEnumLiteral eEnumLiteral) { + setStringValueCell(metadataSheetDataRow, colIndex, eEnumLiteral.getName()); + } + + private void setEEnumMetadataLiteralValueCell(Range metadataSheetDataRow, int colIndex, EEnumLiteral eEnumLiteral) { + setStringValueCell(metadataSheetDataRow, colIndex, eEnumLiteral.getLiteral()); } - private void setMetadataDocumentationValueCell(TableCellWalker walker, EAnnotation genModelAnnotation) { + private void setEEnumMetadataValueValueCell(Range metadataSheetDataRow, int colIndex, EEnumLiteral eEnumLiteral) { + setNumberValueCell(metadataSheetDataRow, colIndex, eEnumLiteral.getValue()); + } + + private void setEEnumMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, + EEnumLiteral eEnumLiteral) { + EAnnotation genModelAnnotation = eEnumLiteral.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); + + setMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, genModelAnnotation); + } + + private void setMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, + EAnnotation genModelAnnotation) { if (genModelAnnotation != null) { Map genModelAnnotationDetails = genModelAnnotation.getDetails().map(); if (genModelAnnotationDetails.containsKey(DOCUMENTATION_GENMODEL_DETAILS)) { String documentation = genModelAnnotationDetails.get(DOCUMENTATION_GENMODEL_DETAILS); - setStringValueCell(walker, documentation); + setStringValueCell(metadataSheetDataRow, colIndex, documentation); } } - setVoidValueCell(walker); + setVoidValueCell(metadataSheetDataRow, colIndex); } private int getEObjectIdentifier(EObject eObject) { return eObject.hashCode(); } - private String constructEClassTableName(EClass eClass) { + private String constructEClassSheetName(EClass eClass) { return eClass.getName(); } - private String constructEEnumTableName(EEnum eEnum) { + private String constructEEnumSheetName(EEnum eEnum) { return eEnum.getName(); } - private String constructEClassMetadataTableName(EClass eClass) { - return constructMetadataTableName(constructEClassTableName(eClass)); + private String constructEClassMetadataSheetName(EClass eClass) { + return constructMetadataSheetName(constructEClassSheetName(eClass)); } - private String constructEEnumMetadataTableName(EEnum eEnum) { - return constructMetadataTableName(constructEEnumTableName(eEnum)); + private String constructEEnumMetadataSheetName(EEnum eEnum) { + return constructMetadataSheetName(constructEEnumSheetName(eEnum)); } - private String constructMetadataTableName(String metadataTableName) { + private String constructMetadataSheetName(String metadataTableName) { StringBuilder sb = new StringBuilder(100); sb.append(metadataTableName); sb.append(" "); sb.append("( "); - sb.append(METADATA_TABLE_SUFFIX); + sb.append(METADATA_SHEET_SUFFIX); sb.append(" )"); return sb.toString(); } - private void adjustRowHeight(TableCellWalker walker, int linesCount) { - walker.setRowStyle(constructAdjustedHeightRowStyle(linesCount)); - } - - private TableRowStyle constructAdjustedHeightRowStyle(int linesCount) { - // @formatter:off - return TableRowStyle.builder("adjusted-height-row-style") - .defaultCellStyle(DEFAULT_BODY_CELL_STYLE) - .rowHeight(calculateRowHeight(linesCount)) - .build(); - // @formatter:on - } - - private SimpleLength calculateRowHeight(int linesCount) { - return SimpleLength.mm(linesCount * 5); - } - private boolean isProcessed(Set eObjectsIdentifiers, EObject eObject) { return eObjectsIdentifiers.contains(getEObjectIdentifier(eObject)); } diff --git a/org.gecko.emf.exporter/bnd.bnd b/org.gecko.emf.exporter/bnd.bnd index cd9b577d..4c2c11a2 100644 --- a/org.gecko.emf.exporter/bnd.bnd +++ b/org.gecko.emf.exporter/bnd.bnd @@ -6,17 +6,4 @@ Bundle-Description: Exporter for EMF -buildpath: \ osgi.annotation;version='7.0',\ - osgi.core;version='7.0',\ - fastods;version='0.8' - -# osgi.annotation;version='7.0',\ -# osgi.core;version='7.0',\ -# osgi.cmpn;version='7.0',\ -# org.eclipse.emf.common,\ -# org.eclipse.emf.ecore,\ -# org.eclipse.emf.ecore.xmi,\ -# org.gecko.emf.repository.api,\ -# org.gecko.emf.osgi.api,\ -# org.osgi.util.pushstream,\ -# org.gecko.util.pushstream,\ -# org.gecko.emf.pushstreams,\ + osgi.core;version='7.0' \ No newline at end of file diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java index a59502fc..81d2f898 100644 --- a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java @@ -27,12 +27,14 @@ public interface EMFExportOptions { // extract and export metadata as additional sheets String OPTION_EXPORT_METADATA = "EXPORT_METADATA"; - // automatically adjust column width based on contents - disabled by default until FastODS bug is fixed + // automatically adjust column width based on contents String OPTION_ADJUST_COLUMN_WIDTH = "ADJUST_COLUMN_WIDTH"; - // freeze header row - disabled by default until bug is fixed - String OPTION_FREEZE_HEADER_ROW = "FREEZE_HEADER_ROW"; + // TODO: freezing rows is currently not supported in SODS + // freeze header row +// String OPTION_FREEZE_HEADER_ROW = "FREEZE_HEADER_ROW"; + // TODO: linking is currently not supported in SODS // generate links for references - String OPTION_GENERATE_LINKS = "GENERATE_LINKS"; +// String OPTION_GENERATE_LINKS = "GENERATE_LINKS"; } diff --git a/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java index ee537f21..82ddaeae 100644 --- a/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java +++ b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java @@ -84,8 +84,9 @@ public void testSaveODS(@InjectService(timeout = 2000) ServiceAware Map.of( EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, - EMFExportOptions.OPTION_EXPORT_METADATA, true, - EMFExportOptions.OPTION_GENERATE_LINKS, true)); + EMFExportOptions.OPTION_EXPORT_METADATA, true + // EMFExportOptions.OPTION_GENERATE_LINKS, true // TODO: linking is currently not supported in SODS + )); // @formatter:on } } diff --git a/org.gecko.emf.ods.tests/test.bndrun b/org.gecko.emf.ods.tests/test.bndrun index a9388c60..ffe5a602 100644 --- a/org.gecko.emf.ods.tests/test.bndrun +++ b/org.gecko.emf.ods.tests/test.bndrun @@ -21,7 +21,6 @@ org.osgi.util.pushstream;version='[1.0.1,1.0.2)',\ org.apache.felix.converter;version='[1.0.18,1.0.19)',\ org.osgi.util.promise;version='[1.2.0,1.2.1)',\ - org.gecko.emf.collections;version=snapshot,\ assertj-core;version='[3.22.0,3.22.1)',\ junit-jupiter-params;version='[5.8.2,5.8.3)',\ org.osgi.test.common;version='[1.1.0,1.1.1)',\ @@ -32,7 +31,6 @@ com.fasterxml.jackson.dataformat.jackson-dataformat-properties;version='[2.14.1,2.14.2)',\ com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.14.1,2.14.2)',\ de.undercouch.bson4jackson;version='[2.13.1,2.13.2)',\ - fastods;version='[0.8.1,0.8.2)',\ org.apache.commons.commons-text;version='[1.10.0,1.10.1)',\ org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ org.eclipse.emfcloud.emfjson-jackson;version='[2.2.0,2.2.1)',\ @@ -41,7 +39,11 @@ org.gecko.emf.json;version=snapshot,\ org.gecko.emf.ods;version=snapshot,\ org.gecko.emf.ods.tests;version=snapshot,\ - org.yaml.snakeyaml;version='[1.33.0,1.33.1)' + org.yaml.snakeyaml;version='[1.33.0,1.33.1)',\ + com.github.miachm.sods;version='[1.5.3,1.5.4)',\ + org.gecko.emf.bson;version=snapshot,\ + org.gecko.emf.util.model;version=snapshot,\ + org.osgi.service.cm;version='[1.6.0,1.6.1)' -runrequires: bnd.identity;id='org.gecko.emf.ods.tests' diff --git a/org.gecko.emf.ods/bnd.bnd b/org.gecko.emf.ods/bnd.bnd index 2d0b2dc2..37693b99 100644 --- a/org.gecko.emf.ods/bnd.bnd +++ b/org.gecko.emf.ods/bnd.bnd @@ -1,6 +1,6 @@ Bundle-Version: 1.0.0.SNAPSHOT Bundle-Name: Gecko EMF ODS Extension -Bundle-Description: Extension to save EMF objects to ODS using FastODS +Bundle-Description: Extension to save EMF objects to ODS using SODS -library: enable-emf diff --git a/org.gecko.emf.util.bnd.library.workspace/required.bndrun b/org.gecko.emf.util.bnd.library.workspace/required.bndrun index 48a24b5e..afa0b28b 100644 --- a/org.gecko.emf.util.bnd.library.workspace/required.bndrun +++ b/org.gecko.emf.util.bnd.library.workspace/required.bndrun @@ -9,7 +9,9 @@ bnd.identity;id='org.gecko.emf.collections',\ bnd.identity;id='org.gecko.emf.json',\ bnd.identity;id='org.gecko.emf.pushstreams',\ - bnd.identity;id='org.gecko.emf.util.model' + bnd.identity;id='org.gecko.emf.util.model',\ + bnd.identity;id='org.gecko.emf.ods',\ + bnd.identity;id='org.gecko.emf.exporter.ods' -runbundles: \ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ org.eclipse.emf.ecore.xmi;version='[2.16.0,2.16.1)',\ @@ -35,7 +37,11 @@ com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.14.1,2.14.2)',\ org.eclipse.emfcloud.emfjson-jackson;version='[2.2.0,2.2.1)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - org.yaml.snakeyaml;version='[1.33.0,1.33.1)' + org.yaml.snakeyaml;version='[1.33.0,1.33.1)',\ + com.github.miachm.sods;version='[1.5.3,1.5.4)',\ + org.gecko.emf.exporter;version=snapshot,\ + org.gecko.emf.exporter.ods;version=snapshot,\ + org.gecko.emf.ods;version=snapshot -runblacklist: \ bnd.identity;id='ch.qos.logback.classic',\ bnd.identity;id='ch.qos.logback.core' \ No newline at end of file From 536669365998e4300d285b3efe236033e123a7e0 Mon Sep 17 00:00:00 2001 From: "Michael H. Siemaszko" Date: Sun, 12 Mar 2023 21:06:12 +0100 Subject: [PATCH 4/6] Replaced FastODS with SODS (c.d.) Signed-off-by: Michael H. Siemaszko --- .gitignore | 1 - .../com.github.miachm.sods-1.5.3.jar | Bin 0 -> 140894 bytes cnf/local/index.xml | 45 ++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 cnf/local/com.github.miachm.sods/com.github.miachm.sods-1.5.3.jar create mode 100644 cnf/local/index.xml diff --git a/.gitignore b/.gitignore index d0cc242a..007e314b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,4 @@ generated/ /.metadata/ /build/ cnf/release/ -cnf/local/ src-gen \ No newline at end of file diff --git a/cnf/local/com.github.miachm.sods/com.github.miachm.sods-1.5.3.jar b/cnf/local/com.github.miachm.sods/com.github.miachm.sods-1.5.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..7b8ef1089cf6324fa72c950676117f1ac080521a GIT binary patch literal 140894 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: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 literal 0 HcmV?d00001 diff --git a/cnf/local/index.xml b/cnf/local/index.xml new file mode 100644 index 00000000..47a87046 --- /dev/null +++ b/cnf/local/index.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 59e4b42e23dc0f0fe7a7e8f765ae4b86105f562b Mon Sep 17 00:00:00 2001 From: "Michael H. Siemaszko" Date: Tue, 28 Mar 2023 23:09:44 +0200 Subject: [PATCH 5/6] Links, mapping tables, and more - Added support for links after having added this new feature to SODS library - Added support for mapping tables - Various fixes & improvements Signed-off-by: Michael H. Siemaszko --- .../com.github.miachm.sods-1.5.3.jar | Bin 140894 -> 146610 bytes cnf/local/index.xml | 8 +- .../emf/ods/tests/EMFODSExporterTest.java | 11 +- org.gecko.emf.exporter.ods.tests/test.bndrun | 3 +- .../emf/exporter/ods/EMFODSExporter.java | 430 +++++++++++++----- .../gecko/emf/exporter/EMFExportOptions.java | 9 +- .../emf/ods/tests/EMFODSResourceTest.java | 6 +- org.gecko.emf.ods.tests/test.bndrun | 5 +- .../required.bndrun | 13 +- 9 files changed, 338 insertions(+), 147 deletions(-) diff --git a/cnf/local/com.github.miachm.sods/com.github.miachm.sods-1.5.3.jar b/cnf/local/com.github.miachm.sods/com.github.miachm.sods-1.5.3.jar index 7b8ef1089cf6324fa72c950676117f1ac080521a..f234d2d8cb30f426f5d2ea8861ef5256c6f06452 100644 GIT binary patch delta 101197 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 delta 95550 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

kHn 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 diff --git a/cnf/local/index.xml b/cnf/local/index.xml index 47a87046..74466bc8 100644 --- a/cnf/local/index.xml +++ b/cnf/local/index.xml @@ -1,5 +1,5 @@ - + @@ -14,7 +14,7 @@ - + @@ -25,10 +25,10 @@ - + - + diff --git a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java index 25ec87ac..e443ebd3 100644 --- a/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java +++ b/org.gecko.emf.exporter.ods.tests/src/org/gecko/emf/ods/tests/EMFODSExporterTest.java @@ -102,8 +102,9 @@ public void testExportBasicPackageResourceToOds( EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, EMFExportOptions.OPTION_EXPORT_METADATA, true, - EMFExportOptions.OPTION_ADJUST_COLUMN_WIDTH, true - // EMFExportOptions.OPTION_GENERATE_LINKS, true // TODO: linking is currently not supported in SODS + EMFExportOptions.OPTION_ADJUST_COLUMN_WIDTH, true, + EMFExportOptions.OPTION_GENERATE_LINKS, true, + EMFExportOptions.OPTION_ADD_MAPPING_TABLE, true ) ); // @formatter:on @@ -129,8 +130,10 @@ public void testExportUtilitiesPackageResourceToOds( Map.of( EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, - EMFExportOptions.OPTION_EXPORT_METADATA, true - // EMFExportOptions.OPTION_GENERATE_LINKS, true // TODO: linking is currently not supported in SODS + EMFExportOptions.OPTION_EXPORT_METADATA, true, + EMFExportOptions.OPTION_ADJUST_COLUMN_WIDTH, true, + EMFExportOptions.OPTION_GENERATE_LINKS, true, + EMFExportOptions.OPTION_ADD_MAPPING_TABLE, true ) ); // @formatter:on diff --git a/org.gecko.emf.exporter.ods.tests/test.bndrun b/org.gecko.emf.exporter.ods.tests/test.bndrun index d034cf11..5213a5c6 100644 --- a/org.gecko.emf.exporter.ods.tests/test.bndrun +++ b/org.gecko.emf.exporter.ods.tests/test.bndrun @@ -43,7 +43,8 @@ org.gecko.emf.util.model;version=snapshot,\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ com.github.miachm.sods;version='[1.5.3,1.5.4)',\ - org.gecko.emf.bson;version=snapshot + org.gecko.emf.ods;version=snapshot,\ + org.gecko.emf.pushstreams;version=snapshot -runrequires: bnd.identity;id='org.gecko.emf.exporter.ods.tests' diff --git a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java index 7b8e3fdc..5a5b7040 100644 --- a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java +++ b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java @@ -14,11 +14,13 @@ import static java.util.stream.Collectors.toList; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -26,6 +28,7 @@ import java.util.Set; import java.util.UUID; +import org.apache.commons.text.WordUtils; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; @@ -44,6 +47,7 @@ import org.osgi.service.component.annotations.ServiceScope; import com.github.miachm.sods.Color; +import com.github.miachm.sods.LinkedValue; import com.github.miachm.sods.Range; import com.github.miachm.sods.Sheet; import com.github.miachm.sods.SpreadSheet; @@ -56,7 +60,7 @@ */ @Component(name = "EMFODSExporter", scope = ServiceScope.PROTOTYPE) public class EMFODSExporter implements EMFExporter { - + private static final int MAX_CHAR_PER_LINE_DEFAULT = 30; private static final Style HEADER_STYLE = new Style(); @@ -77,15 +81,17 @@ public class EMFODSExporter implements EMFExporter { private static final List METADATA_EENUM_SHEET_HEADERS = List.of("Name", "Literal", "Value", "Documentation"); private static final String METADATA_SHEET_SUFFIX = "Metadata"; + private static final String MAPPING_TABLE_SHEET_SUFFIX = "Mapping Table"; private static final String DOCUMENTATION_GENMODEL_SOURCE = "http://www.eclipse.org/emf/2002/GenModel"; private static final String DOCUMENTATION_GENMODEL_DETAILS = "documentation"; private static final String ECORE_PACKAGE_NAME = "ecore"; - private final static char CR = (char) 0x0D; - private final static char LF = (char) 0x0A; - private final static String DATA_CELL_LINE_SEPARATOR = "" + CR + LF; + private static final String ID_COLUMN_NAME = "Id"; + private static final int ID_COLUMN_WIDTH = 18; + + private static final String REF_COLUMN_PREFIX = "ref_"; /* * (non-Javadoc) @@ -152,11 +158,8 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, eObjectsEnums, eObjectsPseudoIDs, eObjectsSheets, - exportNonContainmentEnabled(exportOptions), - exportMetadataEnabled(exportOptions), - freezeHeaderRowEnabled(exportOptions), - adjustColumnWidthEnabled(exportOptions), - eObjectsSafeCopy); + eObjectsSafeCopy, + exportOptions); // @formatter:on // @formatter:off @@ -166,10 +169,8 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, eObjectsEnums, eObjectsPseudoIDs, eObjectsSheets, - exportNonContainmentEnabled(exportOptions), - exportMetadataEnabled(exportOptions), - generateLinksEnabled(exportOptions), - eObjectsSafeCopy); + eObjectsSafeCopy, + exportOptions); // @formatter:on if (exportMetadataEnabled(exportOptions)) { @@ -248,8 +249,7 @@ private String getPseudoID(EObject eObject, Map eObjectsPseudoI private void createSheets(SpreadSheet document, Map eClassesSheets, Set eObjectsClasses, Set eObjectsEnums, Map eObjectsPseudoIDs, Map eObjectsSheets, - boolean exportNonContainment, boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, - List eObjects) { + List eObjects, Map exportOptions) { final Set processedEObjectsIdentifiers = new HashSet(); @@ -262,10 +262,7 @@ private void createSheets(SpreadSheet document, Map eClassesSheet eObjectsEnums, eObjectsPseudoIDs, eObjectsSheets, - exportNonContainment, - exportMetadata, - freezeHeaderRow, - adjustColumnWidth, + exportOptions, eObject); // @formatter:on } @@ -273,8 +270,7 @@ private void createSheets(SpreadSheet document, Map eClassesSheet private void createSheetsData(SpreadSheet document, Map eClassesSheets, Set eObjectsClasses, Set eObjectsEnums, Map eObjectsPseudoIDs, Map eObjectsSheets, - boolean exportNonContainment, boolean exportMetadata, boolean generateLinks, List eObjects) - throws EMFExportException { + List eObjects, Map exportOptions) throws EMFExportException { final Set processedEObjectsIdentifiers = new HashSet(); @@ -287,9 +283,7 @@ private void createSheetsData(SpreadSheet document, Map eClassesS eObjectsEnums, eObjectsPseudoIDs, eObjectsSheets, - exportNonContainment, - exportMetadata, - generateLinks, + exportOptions, eObject); // @formatter:on } @@ -297,29 +291,28 @@ private void createSheetsData(SpreadSheet document, Map eClassesS private void createSheetForEObjectWithEReferences(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, - Map eObjectsPseudoIDs, Map eObjectsSheets, boolean exportNonContainment, - boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject) { + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions, EObject eObject) { createSheet(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, eObjectsPseudoIDs, - eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, adjustColumnWidth, eObject); + eObjectsSheets, exportOptions, eObject); eObject.eClass().getEAllReferences().stream().forEach(r -> { createSheetForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, - eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, - adjustColumnWidth, eObject, r); + eObjectsPseudoIDs, eObjectsSheets, exportOptions, eObject, r); }); } private void createSheetDataForEObjectWithEReferences(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, - Map eObjectsPseudoIDs, Map eObjectsSheets, boolean exportNonContainment, - boolean exportMetadata, boolean generateLinks, EObject eObject) throws EMFExportException { - createSheetData(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsSheets, - exportNonContainment, generateLinks, eObject); + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions, EObject eObject) throws EMFExportException { + createSheetData(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, eObjectsSheets, exportOptions, + eObject); eObject.eClass().getEAllReferences().stream().forEach(r -> { try { createSheetDataForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, - eObjectsSheets, exportNonContainment, generateLinks, eObject, r); + eObjectsSheets, exportOptions, eObject, r); } catch (EMFExportException e) { e.printStackTrace(); } @@ -328,13 +321,12 @@ private void createSheetDataForEObjectWithEReferences(SpreadSheet document, Map< private void createSheet(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, Map eObjectsPseudoIDs, - Map eObjectsSheets, boolean exportNonContainment, boolean exportMetadata, - boolean freezeHeaderRow, boolean adjustColumnWidth, EObject... eObjects) { + Map eObjectsSheets, Map exportOptions, EObject... eObjects) { if ((eObjects.length > 0) && !isProcessed(eObjectsIdentifiers, eObjects[0])) { EClass eClass = eObjects[0].eClass(); Sheet sheet = getOrAddSheet(document, eClassesSheets, eClass, eObjectsEnums, - hasPseudoID(eObjects[0], eObjectsPseudoIDs), exportMetadata, freezeHeaderRow, adjustColumnWidth); + hasPseudoID(eObjects[0], eObjectsPseudoIDs), exportOptions); for (EObject eObject : eObjects) { Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); @@ -345,8 +337,7 @@ private void createSheet(SpreadSheet document, Map eClassesSheets eObject.eClass().getEAllReferences().stream().forEach(r -> { createSheetForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, - eObjectsEnums, eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, - freezeHeaderRow, adjustColumnWidth, eObject, r); + eObjectsEnums, eObjectsPseudoIDs, eObjectsSheets, exportOptions, eObject, r); }); } } @@ -355,9 +346,9 @@ private void createSheet(SpreadSheet document, Map eClassesSheets @SuppressWarnings("unchecked") private void createSheetForEReference(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Set eObjectsClasses, Set eObjectsEnums, - Map eObjectsPseudoIDs, Map eObjectsSheets, boolean exportNonContainment, - boolean exportMetadata, boolean freezeHeaderRow, boolean adjustColumnWidth, EObject eObject, EReference r) { - if (!exportNonContainment && !r.isContainment()) { + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions, EObject eObject, EReference r) { + if (!exportNonContainmentEnabled(exportOptions) && !r.isContainment()) { return; } @@ -366,20 +357,19 @@ private void createSheetForEReference(SpreadSheet document, Map e if (value != null) { if (!r.isMany() && value instanceof EObject) { createSheet(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, - eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, - adjustColumnWidth, (EObject) value); + eObjectsPseudoIDs, eObjectsSheets, exportOptions, (EObject) value); } else if (r.isMany()) { createSheet(document, eClassesSheets, eObjectsIdentifiers, eObjectsClasses, eObjectsEnums, - eObjectsPseudoIDs, eObjectsSheets, exportNonContainment, exportMetadata, freezeHeaderRow, - adjustColumnWidth, ((List) value).toArray(EObject[]::new)); + eObjectsPseudoIDs, eObjectsSheets, exportOptions, + ((List) value).toArray(EObject[]::new)); } } } private void createSheetData(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Map eObjectsPseudoIDs, - Map eObjectsSheets, boolean exportNonContainment, boolean generateLinks, - EObject... eObjects) throws EMFExportException { + Map eObjectsSheets, Map exportOptions, EObject... eObjects) + throws EMFExportException { if ((eObjects.length > 0) && !isProcessed(eObjectsIdentifiers, eObjects[0])) { EClass eClass = eObjects[0].eClass(); @@ -388,12 +378,12 @@ private void createSheetData(SpreadSheet document, Map eClassesSh for (EObject eObject : eObjects) { eObjectsIdentifiers.add(getEObjectIdentifier(eObject)); - createSheetData(sheet, eObject, eObjectsPseudoIDs, eObjectsSheets, generateLinks); + createSheetData(document, sheet, eObject, eObjectsPseudoIDs, eObjectsSheets, exportOptions); eObject.eClass().getEAllReferences().stream().forEach(r -> { try { createSheetDataForEReference(document, eClassesSheets, eObjectsIdentifiers, eObjectsPseudoIDs, - eObjectsSheets, exportNonContainment, generateLinks, eObject, r); + eObjectsSheets, exportOptions, eObject, r); } catch (EMFExportException e) { e.printStackTrace(); } @@ -405,9 +395,9 @@ private void createSheetData(SpreadSheet document, Map eClassesSh @SuppressWarnings("unchecked") private void createSheetDataForEReference(SpreadSheet document, Map eClassesSheets, Set eObjectsIdentifiers, Map eObjectsPseudoIDs, - Map eObjectsSheets, boolean exportNonContainment, boolean generateLinks, EObject eObject, - EReference r) throws EMFExportException { - if (!exportNonContainment && !r.isContainment()) { + Map eObjectsSheets, Map exportOptions, EObject eObject, EReference r) + throws EMFExportException { + if (!exportNonContainmentEnabled(exportOptions) && !r.isContainment()) { return; } @@ -416,16 +406,17 @@ private void createSheetDataForEReference(SpreadSheet document, Map) value).toArray(EObject[]::new)); + exportOptions, ((List) value).toArray(EObject[]::new)); } } } - private void createSheetData(Sheet sheet, EObject eObject, Map eObjectsPseudoIDs, - Map eObjectsSheets, boolean generateLinks) { + private void createSheetData(SpreadSheet document, Sheet sheet, EObject eObject, + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions) { sheet.appendRow(); @@ -437,8 +428,8 @@ private void createSheetData(Sheet sheet, EObject eObject, Map for (int colIndex = 0; colIndex < columnsCount; colIndex++) { - createSheetDataCell(sheetDataRow, colIndex, eObject, eAllStructuralFeatures.get(colIndex), - eObjectsPseudoIDs, eObjectsSheets, generateLinks); + createSheetDataCell(document, sheetDataRow, colIndex, eObject, eAllStructuralFeatures.get(colIndex), + eObjectsPseudoIDs, eObjectsSheets, exportOptions); } if (hasPseudoID(eObject, eObjectsPseudoIDs)) { @@ -447,31 +438,29 @@ private void createSheetData(Sheet sheet, EObject eObject, Map } private Sheet getOrAddSheet(SpreadSheet document, Map eClassesSheets, EClass eClass, - Set eObjectsEnums, boolean hasPseudoID, boolean exportMetadata, boolean freezeHeaderRow, - boolean adjustColumnWidth) { - String tableName = constructEClassSheetName(eClass); + Set eObjectsEnums, boolean hasPseudoID, Map exportOptions) { + String sheetName = constructEClassSheetName(eClass); + + boolean sheetExists = eClassesSheets.containsKey(sheetName); - boolean tableExists = eClassesSheets.containsKey(tableName); Sheet sheet; - if (tableExists) { - sheet = eClassesSheets.get(tableName); + if (sheetExists) { + sheet = eClassesSheets.get(sheetName); } else { - sheet = new Sheet(tableName); + sheet = new Sheet(sheetName); document.appendSheet(sheet); - eClassesSheets.put(tableName, sheet); + eClassesSheets.put(sheetName, sheet); - if (exportMetadata) { - addMetadataSheet(document, eClass); - } - } - - if (!tableExists) { - createSheetHeader(sheet, eClass, eObjectsEnums, hasPseudoID, adjustColumnWidth); + createSheetHeader(sheet, eClass, eObjectsEnums, hasPseudoID, exportOptions); - if (freezeHeaderRow) { + if (freezeHeaderRowEnabled(exportOptions)) { // TODO: freezing rows is currently not supported in SODS // freezeTableHeader(document, sheet, 1, headersCount); } + + if (exportMetadataEnabled(exportOptions)) { + addMetadataSheet(document, eClass); + } } return sheet; @@ -488,7 +477,7 @@ private Sheet getSheet(Map eObjectsSheets, EClass eClass) throws } private void createSheetHeader(Sheet sheet, EClass eClass, Set eObjectsEnums, boolean hasPseudoID, - boolean adjustColumnWidth) { + Map exportOptions) { List eAllStructuralFeatures = eClass.getEAllStructuralFeatures(); @@ -509,32 +498,42 @@ private void createSheetHeader(Sheet sheet, EClass eClass, Set eObjectsEn eObjectsEnums.add(extractEEnumDataType(eStructuralFeature)); } - createSheetHeaderCell(sheetHeaderRow, eStructuralFeature, adjustColumnWidth, colIndex); + createSheetHeaderCell(sheetHeaderRow, eStructuralFeature, exportOptions, colIndex); } if (hasPseudoID) { - createSheetHeaderCell(sheetHeaderRow, "id", adjustColumnWidth, columnsCount); + createSheetHeaderCell(sheetHeaderRow, "id", exportOptions, columnsCount); } } private void createSheetHeaderCell(Range sheetHeaderRow, EStructuralFeature eStructuralFeature, - boolean adjustColumnWidth, int colIndex) { - String tableHeaderName = constructSheetHeaderName(eStructuralFeature); + Map exportOptions, int colIndex) { + String sheetHeaderName = constructSheetHeaderName(eStructuralFeature); - createSheetHeaderCell(sheetHeaderRow, tableHeaderName, adjustColumnWidth, colIndex); + createSheetHeaderCell(sheetHeaderRow, sheetHeaderName, exportOptions, colIndex); } - private void createSheetHeaderCell(Range sheetHeaderRow, String tableHeaderName, boolean adjustColumnWidth, + private void createSheetHeaderCell(Range sheetHeaderRow, String sheetHeaderName, Map exportOptions, int colIndex) { - createSheetHeaderCell(sheetHeaderRow, colIndex, tableHeaderName); - if (adjustColumnWidth) { - adjustColumnWidth(sheetHeaderRow.getSheet(), colIndex, tableHeaderName.length()); + createSheetHeaderCell(sheetHeaderRow, colIndex, sheetHeaderName); + + if (adjustColumnWidthEnabled(exportOptions)) { + adjustColumnWidth(sheetHeaderRow.getSheet(), colIndex, adjustColumnWidthCharsCount(sheetHeaderName)); } } - private void createSheetHeaderCell(Range sheetHeaderRow, int colIndex, String tableHeaderName) { - sheetHeaderRow.getCell(0, colIndex).setValue(tableHeaderName); + private int adjustColumnWidthCharsCount(String sheetHeaderName) { + if (sheetHeaderName.equalsIgnoreCase(ID_COLUMN_NAME) || sheetHeaderName.endsWith(ID_COLUMN_NAME) + || sheetHeaderName.startsWith(REF_COLUMN_PREFIX)) { + return ID_COLUMN_WIDTH; + } else { + return sheetHeaderName.length(); + } + } + + private void createSheetHeaderCell(Range sheetHeaderRow, int colIndex, String sheetHeaderName) { + sheetHeaderRow.getCell(0, colIndex).setValue(sheetHeaderName); } private void adjustColumnWidth(Sheet sheet, int colIndex, int charsCount) { @@ -542,7 +541,7 @@ private void adjustColumnWidth(Sheet sheet, int colIndex, int charsCount) { } private Double calculateColumnWidth(int charsCount) { - return (Double.valueOf(charsCount) * (charsCount > 3 ? 5 : 10)); + return (Double.valueOf(charsCount) * (charsCount > 3 ? 5 : 7.5)); } private void adjustRowHeight(Sheet sheet, int rowIndex, String value) { @@ -561,7 +560,7 @@ private void freezeSheetHeaderRow(Sheet sheet, int rowCount, int colCount) { private String constructSheetHeaderName(EStructuralFeature eStructuralFeature) { StringBuilder sb = new StringBuilder(100); if (eStructuralFeature instanceof EReference) { - sb.append("ref_"); + sb.append(REF_COLUMN_PREFIX); } sb.append(eStructuralFeature.getName()); return sb.toString(); @@ -576,9 +575,9 @@ private EEnum extractEEnumDataType(EStructuralFeature eStructuralFeature) { return ((EEnum) ((EAttribute) eStructuralFeature).getEAttributeType()); } - private void createSheetDataCell(Range sheetDataRow, int colIndex, EObject eObject, + private void createSheetDataCell(SpreadSheet document, Range sheetDataRow, int colIndex, EObject eObject, EStructuralFeature eStructuralFeature, Map eObjectsPseudoIDs, - Map eObjectsSheets, boolean generateLinks) { + Map eObjectsSheets, Map exportOptions) { if (eStructuralFeature instanceof EAttribute) { EAttribute eAttribute = (EAttribute) eStructuralFeature; @@ -615,40 +614,178 @@ private void createSheetDataCell(Range sheetDataRow, int colIndex, EObject eObje } else if (eStructuralFeature instanceof EReference) { EReference eReference = (EReference) eStructuralFeature; - setEReferenceValueCell(sheetDataRow, colIndex, eObject, eReference, eObjectsPseudoIDs, eObjectsSheets, - generateLinks); + setEReferenceValueCell(document, sheetDataRow, colIndex, eObject, eReference, eObjectsPseudoIDs, + eObjectsSheets, exportOptions); } } @SuppressWarnings("unchecked") - private void setEReferenceValueCell(Range sheetDataRow, int colIndex, EObject eObject, EReference r, - Map eObjectsPseudoIDs, Map eObjectsSheets, boolean generateLinks) { + private void setEReferenceValueCell(SpreadSheet document, Range sheetDataRow, int colIndex, EObject eObject, + EReference r, Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions) { Object value = eObject.eGet(r); if (value != null) { - if (!r.isMany() && value instanceof EObject) { - setOneEReferenceValueCell(sheetDataRow, colIndex, (EObject) value, eObjectsPseudoIDs, eObjectsSheets, - generateLinks); - } else if (r.isMany()) { - setManyEReferencesValueCell(sheetDataRow, colIndex, ((List) value), eObjectsPseudoIDs, - eObjectsSheets, generateLinks); + if ((!r.isMany() && value instanceof EObject) || (r.isMany() && ((List) value).size() == 1)) { + setOneEReferenceValueCell(sheetDataRow, colIndex, + (!r.isMany() ? ((EObject) value) : ((List) value).get(0)), eObjectsPseudoIDs, + eObjectsSheets, exportOptions); + + } else if (r.isMany() && !((List) value).isEmpty()) { + if (addMappingTableEnabled(exportOptions)) { + createEReferencesMappingTable(document, sheetDataRow, colIndex, eObject, r, ((List) value), + eObjectsPseudoIDs, eObjectsSheets, exportOptions); + + } else { + setManyEReferencesValueCell(sheetDataRow, colIndex, ((List) value), eObjectsPseudoIDs, + eObjectsSheets, exportOptions); + } } } } + private void createEReferencesMappingTable(SpreadSheet document, Range sheetDataRow, int colIndex, + EObject fromEObject, EReference toEReference, List toEObjects, + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions) { + + Sheet mappingTableSheet = getOrAddMappingTableSheet(document, fromEObject.eClass(), toEReference.getName(), + toEReference.getEReferenceType(), exportOptions); + + setReferenceToMappingTable(mappingTableSheet, sheetDataRow, colIndex, exportOptions); + + createMappingTableSheetData(mappingTableSheet, fromEObject, toEObjects, eObjectsPseudoIDs, eObjectsSheets, + exportOptions); + } + + private void setReferenceToMappingTable(Sheet mappingTableSheet, Range sheetDataRow, int colIndex, + Map exportOptions) { + + if (generateLinksEnabled(exportOptions)) { + setLinkedIDEReferenceValueCell(sheetDataRow, colIndex, + constructMappingTableEReferenceValue(mappingTableSheet.getName()), mappingTableSheet); + } else { + setNonLinkedIDEReferenceValueCell(sheetDataRow, colIndex, + constructMappingTableEReferenceValue(mappingTableSheet.getName())); + } + } + + private String constructMappingTableEReferenceValue(String mappingTableSheetName) { + StringBuilder sb = new StringBuilder(100); + sb.append("See: "); + sb.append(mappingTableSheetName); + return sb.toString(); + } + + private void createMappingTableSheetData(Sheet mappingTableSheet, EObject fromEObject, List toEObjects, + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions) { + + for (EObject toEObject : toEObjects) { + createMappingTableSheetDataRow(mappingTableSheet, fromEObject, toEObject, eObjectsPseudoIDs, eObjectsSheets, + exportOptions); + } + } + + private void createMappingTableSheetDataRow(Sheet sheet, EObject fromEObject, EObject toEObject, + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions) { + + sheet.appendRow(); + + Range sheetDataRow = sheet.getRange((sheet.getMaxRows() - 1), 0, 1, sheet.getMaxColumns()); + + setOneEReferenceValueCell(sheetDataRow, 0, fromEObject, eObjectsPseudoIDs, eObjectsSheets, exportOptions); + + setOneEReferenceValueCell(sheetDataRow, 1, toEObject, eObjectsPseudoIDs, eObjectsSheets, exportOptions); + + } + + private String constructMappingTableSheetName(EClass fromEClass, String fromFieldName) { + StringBuilder sb = new StringBuilder(100); + sb.append(fromEClass.getName()); + sb.append("_"); + sb.append(fromFieldName); + sb.append(" "); + sb.append("( "); + sb.append(MAPPING_TABLE_SHEET_SUFFIX); + sb.append(" )"); + return sb.toString(); + } + + private Sheet getOrAddMappingTableSheet(SpreadSheet document, EClass fromEClass, String fromFieldName, + EClass toEClass, Map exportOptions) { + String mappingTableSheetName = constructMappingTableSheetName(fromEClass, fromFieldName); + + System.out.println("Mapping table sheet name: " + mappingTableSheetName); // TODO: remove this comment + + Sheet mappingTableSheet = document.getSheet(mappingTableSheetName); + if (mappingTableSheet == null) { + mappingTableSheet = new Sheet(mappingTableSheetName); + document.appendSheet(mappingTableSheet); + + createMappingTableSheetHeader(mappingTableSheet, fromEClass, toEClass, exportOptions); + } + + return mappingTableSheet; + } + + private void createMappingTableSheetHeader(Sheet sheet, EClass fromEClass, EClass toEClass, + Map exportOptions) { + + sheet.appendColumn(); // newly created sheet already has one column + + Range sheetHeaderRow = sheet.getRange(0, 0, 1, sheet.getMaxColumns()); // newly created sheet already has one + // row + + sheetHeaderRow.setStyle(HEADER_STYLE); + + createMappingTableSheetHeaderCell(sheetHeaderRow, fromEClass, exportOptions, 0); + + createMappingTableSheetHeaderCell(sheetHeaderRow, toEClass, exportOptions, 1); + } + + private void createMappingTableSheetHeaderCell(Range sheetHeaderRow, EClass eClass, + Map exportOptions, int colIndex) { + String mappingTableSheetHeaderName = constructMappingTableSheetHeaderName(eClass); + + sheetHeaderRow.getCell(0, colIndex).setValue(mappingTableSheetHeaderName); + + if (adjustColumnWidthEnabled(exportOptions)) { + adjustColumnWidth(sheetHeaderRow.getSheet(), colIndex, + adjustColumnWidthCharsCount(mappingTableSheetHeaderName)); + } + } + + private String constructMappingTableSheetHeaderName(EClass eClass) { + StringBuilder sb = new StringBuilder(100); + + EAttribute idAttribute = eClass.getEIDAttribute(); + + if (idAttribute == null || idAttribute.getName().equalsIgnoreCase(ID_COLUMN_NAME)) { + sb.append(WordUtils.uncapitalize(eClass.getName())); + sb.append(ID_COLUMN_NAME); + } else { + sb.append(idAttribute.getName()); + } + + return sb.toString(); + } + private void setOneEReferenceValueCell(Range sheetDataRow, int colIndex, EObject eObject, - Map eObjectsPseudoIDs, Map eObjectsSheets, boolean generateLinks) { + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions) { Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); if (hasID(eObject)) { - if (generateLinks && eObjectsSheets.containsKey(eObjectIdentifier)) { + if (generateLinksEnabled(exportOptions) && eObjectsSheets.containsKey(eObjectIdentifier)) { setLinkedIDEReferenceValueCell(sheetDataRow, colIndex, getID(eObject), eObjectsSheets.get(eObjectIdentifier)); } else { setNonLinkedIDEReferenceValueCell(sheetDataRow, colIndex, getID(eObject)); } } else if (hasPseudoID(eObject, eObjectsPseudoIDs)) { - if (generateLinks && eObjectsSheets.containsKey(eObjectIdentifier)) { + if (generateLinksEnabled(exportOptions) && eObjectsSheets.containsKey(eObjectIdentifier)) { setLinkedIDEReferenceValueCell(sheetDataRow, colIndex, getPseudoID(eObject, eObjectsPseudoIDs), eObjectsSheets.get(eObjectIdentifier)); } else { @@ -660,29 +797,62 @@ private void setOneEReferenceValueCell(Range sheetDataRow, int colIndex, EObject } private void setManyEReferencesValueCell(Range sheetDataRow, int colIndex, List eObjects, - Map eObjectsPseudoIDs, Map eObjectsSheets, boolean generateLinks) { + Map eObjectsPseudoIDs, Map eObjectsSheets, + Map exportOptions) { StringBuilder sb = new StringBuilder(); - for (EObject eObject : eObjects) { + List linkedValues = new ArrayList(); + + for (int i = 0; i < eObjects.size(); i++) { + EObject eObject = eObjects.get(i); + + Integer eObjectIdentifier = Integer.valueOf(getEObjectIdentifier(eObject)); + if (hasID(eObject)) { - sb.append(getID(eObject)); - sb.append(DATA_CELL_LINE_SEPARATOR); // TODO: this has no effect - all lines are output on same line; - // must be taken care of on SODS side + if (generateLinksEnabled(exportOptions) && eObjectsSheets.containsKey(eObjectIdentifier)) { + LinkedValue linkedValue = LinkedValue.builder().value(getID(eObject)) + .href(eObjectsSheets.get(eObjectIdentifier)).build(); + linkedValues.add(linkedValue); + } else { + sb.append(getID(eObject)); + } } else if (hasPseudoID(eObject, eObjectsPseudoIDs)) { - sb.append(getPseudoID(eObject, eObjectsPseudoIDs)); - sb.append(DATA_CELL_LINE_SEPARATOR); + if (generateLinksEnabled(exportOptions) && eObjectsSheets.containsKey(eObjectIdentifier)) { + LinkedValue linkedValue = LinkedValue.builder().value(getPseudoID(eObject, eObjectsPseudoIDs)) + .href(eObjectsSheets.get(eObjectIdentifier)).build(); + linkedValues.add(linkedValue); + } else { + sb.append(getPseudoID(eObject, eObjectsPseudoIDs)); + } + } else { sb.append("EReference: " + eObject.eClass().getName()); - sb.append(DATA_CELL_LINE_SEPARATOR); + } + + if (hasMoreElements(i, eObjects.size())) { + sb.append(System.lineSeparator()); } } - setStringValueCell(sheetDataRow, colIndex, sb.toString()); + if (generateLinksEnabled(exportOptions) && !linkedValues.isEmpty()) { + setCellLinkedValues(sheetDataRow, colIndex, linkedValues); + } else { + setStringValueCell(sheetDataRow, colIndex, sb.toString()); + } + } + + private void setCellLinkedValues(Range sheetDataRow, int colIndex, List linkedValues) { + sheetDataRow.getCell(0, colIndex).setLinkedValues(linkedValues); + } + + private boolean hasMoreElements(int currentIndex, int size) { + return (currentIndex + 1) < size; } private void setLinkedIDEReferenceValueCell(Range sheetDataRow, int colIndex, String refId, Sheet refSheet) { - setNonLinkedIDEReferenceValueCell(sheetDataRow, colIndex, refId); // FIXME: links are not supported yet in SODS + LinkedValue linkedValue = LinkedValue.builder().value(refId).href(refSheet).build(); + sheetDataRow.getCell(0, colIndex).addLinkedValue(linkedValue); } private void setNonLinkedIDEReferenceValueCell(Range sheetDataRow, int colIndex, String refId) { @@ -721,9 +891,16 @@ private void setMultiValueCell(Range sheetDataRow, int colIndex, EAttribute eAtt Collection values = (Collection) multiValue; - for (Object value : values) { - sb.append(EcoreUtil.convertToString(eAttribute.getEAttributeType(), value)); - sb.append(DATA_CELL_LINE_SEPARATOR); + if (!values.isEmpty()) { + Iterator valuesIt = values.iterator(); + + while (valuesIt.hasNext()) { + sb.append(EcoreUtil.convertToString(eAttribute.getEAttributeType(), valuesIt.next())); + + if (valuesIt.hasNext()) { + sb.append(System.lineSeparator()); + } + } } setStringValueCell(sheetDataRow, colIndex, sb.toString()); @@ -733,6 +910,7 @@ private void setVoidValueCell(Range sheetDataRow, int colIndex) { sheetDataRow.getCell(0, colIndex).clear(); } + @SuppressWarnings("unused") private Locale locale(Map exportOptions) { return ((Locale) exportOptions.getOrDefault(EMFExportOptions.OPTION_LOCALE, Locale.getDefault())); } @@ -749,18 +927,20 @@ private boolean adjustColumnWidthEnabled(Map exportOptions) { return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_ADJUST_COLUMN_WIDTH, Boolean.FALSE)); } + private boolean generateLinksEnabled(Map exportOptions) { + return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_GENERATE_LINKS, Boolean.FALSE)); + } + + private boolean addMappingTableEnabled(Map exportOptions) { + return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_ADD_MAPPING_TABLE, Boolean.FALSE)); + } + private boolean freezeHeaderRowEnabled(Map exportOptions) { // TODO: freezing rows is currently not supported in SODS // return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_FREEZE_HEADER_ROW, Boolean.FALSE)); return false; } - private boolean generateLinksEnabled(Map exportOptions) { - // TODO: linking is currently not supported in SODS - // return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_GENERATE_LINKS, Boolean.FALSE)); - return false; - } - private Map validateExportOptions(Map options) { if (options == null) { return Collections.emptyMap(); @@ -1035,9 +1215,9 @@ private String constructEEnumMetadataSheetName(EEnum eEnum) { return constructMetadataSheetName(constructEEnumSheetName(eEnum)); } - private String constructMetadataSheetName(String metadataTableName) { + private String constructMetadataSheetName(String metadataSheetName) { StringBuilder sb = new StringBuilder(100); - sb.append(metadataTableName); + sb.append(metadataSheetName); sb.append(" "); sb.append("( "); sb.append(METADATA_SHEET_SUFFIX); diff --git a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java index 81d2f898..18a4754b 100644 --- a/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java +++ b/org.gecko.emf.exporter/src/org/gecko/emf/exporter/EMFExportOptions.java @@ -30,11 +30,14 @@ public interface EMFExportOptions { // automatically adjust column width based on contents String OPTION_ADJUST_COLUMN_WIDTH = "ADJUST_COLUMN_WIDTH"; + // generate links for references + String OPTION_GENERATE_LINKS = "GENERATE_LINKS"; + + // generate mapping table + String OPTION_ADD_MAPPING_TABLE = "ADD_MAPPING_TABLE"; + // TODO: freezing rows is currently not supported in SODS // freeze header row // String OPTION_FREEZE_HEADER_ROW = "FREEZE_HEADER_ROW"; - // TODO: linking is currently not supported in SODS - // generate links for references -// String OPTION_GENERATE_LINKS = "GENERATE_LINKS"; } diff --git a/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java index 82ddaeae..081e68f8 100644 --- a/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java +++ b/org.gecko.emf.ods.tests/src/org/gecko/emf/ods/tests/EMFODSResourceTest.java @@ -84,8 +84,10 @@ public void testSaveODS(@InjectService(timeout = 2000) ServiceAware Map.of( EMFExportOptions.OPTION_LOCALE, Locale.GERMANY, EMFExportOptions.OPTION_EXPORT_NONCONTAINMENT, true, - EMFExportOptions.OPTION_EXPORT_METADATA, true - // EMFExportOptions.OPTION_GENERATE_LINKS, true // TODO: linking is currently not supported in SODS + EMFExportOptions.OPTION_EXPORT_METADATA, true, + EMFExportOptions.OPTION_ADJUST_COLUMN_WIDTH, true, + EMFExportOptions.OPTION_GENERATE_LINKS, true, + EMFExportOptions.OPTION_ADD_MAPPING_TABLE, true )); // @formatter:on } diff --git a/org.gecko.emf.ods.tests/test.bndrun b/org.gecko.emf.ods.tests/test.bndrun index ffe5a602..82abedc2 100644 --- a/org.gecko.emf.ods.tests/test.bndrun +++ b/org.gecko.emf.ods.tests/test.bndrun @@ -41,9 +41,8 @@ org.gecko.emf.ods.tests;version=snapshot,\ org.yaml.snakeyaml;version='[1.33.0,1.33.1)',\ com.github.miachm.sods;version='[1.5.3,1.5.4)',\ - org.gecko.emf.bson;version=snapshot,\ - org.gecko.emf.util.model;version=snapshot,\ - org.osgi.service.cm;version='[1.6.0,1.6.1)' + org.osgi.service.cm;version='[1.6.0,1.6.1)',\ + org.gecko.emf.pushstreams;version=snapshot -runrequires: bnd.identity;id='org.gecko.emf.ods.tests' diff --git a/org.gecko.emf.util.bnd.library.workspace/required.bndrun b/org.gecko.emf.util.bnd.library.workspace/required.bndrun index afa0b28b..18bc6adc 100644 --- a/org.gecko.emf.util.bnd.library.workspace/required.bndrun +++ b/org.gecko.emf.util.bnd.library.workspace/required.bndrun @@ -1,7 +1,6 @@ -runfw: org.apache.felix.framework -runee: JavaSE-11 - #example #org.bndtools.template;filter:='(collect=example)' -runrequires: \ @@ -12,6 +11,11 @@ bnd.identity;id='org.gecko.emf.util.model',\ bnd.identity;id='org.gecko.emf.ods',\ bnd.identity;id='org.gecko.emf.exporter.ods' + +-runblacklist: \ + bnd.identity;id='ch.qos.logback.classic',\ + bnd.identity;id='ch.qos.logback.core' + -runbundles: \ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ org.eclipse.emf.ecore.xmi;version='[2.16.0,2.16.1)',\ @@ -41,7 +45,6 @@ com.github.miachm.sods;version='[1.5.3,1.5.4)',\ org.gecko.emf.exporter;version=snapshot,\ org.gecko.emf.exporter.ods;version=snapshot,\ - org.gecko.emf.ods;version=snapshot --runblacklist: \ - bnd.identity;id='ch.qos.logback.classic',\ - bnd.identity;id='ch.qos.logback.core' \ No newline at end of file + org.gecko.emf.ods;version=snapshot,\ + org.apache.commons.commons-text;version='[1.10.0,1.10.1)',\ + org.apache.commons.lang3;version='[3.12.0,3.12.1)' From fb6a1fc67524154ee11aac275ae0fccedad27987 Mon Sep 17 00:00:00 2001 From: "Michael H. Siemaszko" Date: Tue, 18 Apr 2023 23:37:23 +0200 Subject: [PATCH 6/6] Metadata documentation improvements Signed-off-by: Michael H. Siemaszko --- org.gecko.emf.exporter.ods.tests/test.bndrun | 4 +- .../emf/exporter/ods/EMFODSExporter.java | 126 ++++++++++++++---- 2 files changed, 99 insertions(+), 31 deletions(-) diff --git a/org.gecko.emf.exporter.ods.tests/test.bndrun b/org.gecko.emf.exporter.ods.tests/test.bndrun index 5213a5c6..29ef1b41 100644 --- a/org.gecko.emf.exporter.ods.tests/test.bndrun +++ b/org.gecko.emf.exporter.ods.tests/test.bndrun @@ -43,8 +43,8 @@ org.gecko.emf.util.model;version=snapshot,\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ com.github.miachm.sods;version='[1.5.3,1.5.4)',\ - org.gecko.emf.ods;version=snapshot,\ - org.gecko.emf.pushstreams;version=snapshot + org.gecko.emf.pushstreams;version=snapshot,\ + com.fasterxml.jackson.datatype.jackson-datatype-jsr310;version='[2.14.1,2.14.2)' -runrequires: bnd.identity;id='org.gecko.emf.exporter.ods.tests' diff --git a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java index 5a5b7040..aa14b2b4 100644 --- a/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java +++ b/org.gecko.emf.exporter.ods/src/org/gecko/emf/exporter/ods/EMFODSExporter.java @@ -80,6 +80,8 @@ public class EMFODSExporter implements EMFExporter { "Default value", "Documentation"); private static final List METADATA_EENUM_SHEET_HEADERS = List.of("Name", "Literal", "Value", "Documentation"); + private static final String METADATA_DOCUMENTATION_HEADER = "Documentation"; + private static final String METADATA_SHEET_SUFFIX = "Metadata"; private static final String MAPPING_TABLE_SHEET_SUFFIX = "Mapping Table"; @@ -174,7 +176,7 @@ public void exportEObjectsTo(List eObjects, OutputStream outputStream, // @formatter:on if (exportMetadataEnabled(exportOptions)) { - exportMetadata(document, eObjectsClasses, eObjectsEnums); + exportMetadata(document, eObjectsClasses, eObjectsEnums, exportOptions); } document.save(outputStream); @@ -537,7 +539,9 @@ private void createSheetHeaderCell(Range sheetHeaderRow, int colIndex, String sh } private void adjustColumnWidth(Sheet sheet, int colIndex, int charsCount) { - sheet.setColumnWidth(colIndex, calculateColumnWidth(charsCount)); + if (sheet.getColumnWidth(colIndex) == null) { + sheet.setColumnWidth(colIndex, calculateColumnWidth(charsCount)); + } } private Double calculateColumnWidth(int charsCount) { @@ -552,7 +556,8 @@ private Double calculateRowHeight(String value) { return (Double.valueOf(value.length() / MAX_CHAR_PER_LINE_DEFAULT) * 5); } - @Deprecated + + @SuppressWarnings("unused") private void freezeSheetHeaderRow(Sheet sheet, int rowCount, int colCount) { // TODO: freezing rows is currently not supported in SODS } @@ -937,7 +942,9 @@ private boolean addMappingTableEnabled(Map exportOptions) { private boolean freezeHeaderRowEnabled(Map exportOptions) { // TODO: freezing rows is currently not supported in SODS - // return ((boolean) exportOptions.getOrDefault(EMFExportOptions.OPTION_FREEZE_HEADER_ROW, Boolean.FALSE)); + // return ((boolean) + // exportOptions.getOrDefault(EMFExportOptions.OPTION_FREEZE_HEADER_ROW, + // Boolean.FALSE)); return false; } @@ -959,56 +966,113 @@ private Sheet addMetadataSheet(SpreadSheet document, EEnum eEnum) { return metadataSheet; } - private void exportMetadata(SpreadSheet document, Set eClasses, Set eEnums) { - exportEClassesMetadata(document, eClasses); - exportEEnumsMetadata(document, eEnums); + private void exportMetadata(SpreadSheet document, Set eClasses, Set eEnums, + Map exportOptions) { + exportEClassesMetadata(document, eClasses, exportOptions); + exportEEnumsMetadata(document, eEnums, exportOptions); } - private void exportEClassesMetadata(SpreadSheet document, Set eClasses) { + private void exportEClassesMetadata(SpreadSheet document, Set eClasses, Map exportOptions) { for (EClass eClass : eClasses) { - Sheet metadataSheet = document.getSheet(constructEClassMetadataSheetName(eClass)); - createEClassMetadataSheetHeader(metadataSheet); + maybeSetEClassMetadataDocumentation(metadataSheet, eClass, exportOptions); + + createEClassMetadataSheetHeader(metadataSheet, exportOptions); createEClassMetadataSheetData(metadataSheet, eClass); } } - private void exportEEnumsMetadata(SpreadSheet document, Set eEnums) { + private void exportEEnumsMetadata(SpreadSheet document, Set eEnums, Map exportOptions) { for (EEnum eEnum : eEnums) { - Sheet metadataSheet = addMetadataSheet(document, eEnum); - createEEnumMetadataSheetHeader(metadataSheet); + maybeSetEEnumMetadataDocumentationValueCell(metadataSheet, eEnum, exportOptions); + + createEEnumMetadataSheetHeader(metadataSheet, exportOptions); createEEnumMetadataSheetData(metadataSheet, eEnum); } } - private void createEClassMetadataSheetHeader(Sheet metadataSheet) { - createMetadataSheetHeader(metadataSheet, METADATA_ECLASS_SHEET_HEADERS); + private void maybeSetEClassMetadataDocumentation(Sheet metadataSheet, EClass eClass, + Map exportOptions) { + EAnnotation genModelAnnotation = eClass.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); + if (genModelAnnotation != null) { + setTypeLevelMetadataDocumentation(metadataSheet, genModelAnnotation, exportOptions); + } } - private void createEEnumMetadataSheetHeader(Sheet metadataSheet) { - createMetadataSheetHeader(metadataSheet, METADATA_EENUM_SHEET_HEADERS); + private void setEClassMetadataDocumentationValueCell(Range metadataSheetDataRow, + Map exportOptions) { + metadataSheetDataRow.getCell(0, 0).setValue(METADATA_DOCUMENTATION_HEADER); + metadataSheetDataRow.getCell(0, 0).setStyle(HEADER_STYLE); + + if (adjustColumnWidthEnabled(exportOptions)) { + adjustColumnWidth(metadataSheetDataRow.getSheet(), 0, + adjustColumnWidthCharsCount(METADATA_DOCUMENTATION_HEADER)); + } } - private void createMetadataSheetHeader(Sheet metadataSheet, List headers) { + private void maybeSetEEnumMetadataDocumentationValueCell(Sheet metadataSheet, EEnum eEnum, + Map exportOptions) { + EAnnotation genModelAnnotation = eEnum.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); + if (genModelAnnotation != null) { + setTypeLevelMetadataDocumentation(metadataSheet, genModelAnnotation, exportOptions); + } + } + + private void setTypeLevelMetadataDocumentation(Sheet metadataSheet, EAnnotation genModelAnnotation, + Map exportOptions) { + Map genModelAnnotationDetails = genModelAnnotation.getDetails().map(); + + if (genModelAnnotationDetails.containsKey(DOCUMENTATION_GENMODEL_DETAILS)) { + + metadataSheet.appendColumn(); + + Range metadataSheetDocumentationRow = metadataSheet.getRange((metadataSheet.getMaxRows() - 1), 0, 1, 2); + + setEClassMetadataDocumentationValueCell(metadataSheetDocumentationRow, exportOptions); + + setMetadataDocumentationValueCell(metadataSheetDocumentationRow, 1, + genModelAnnotationDetails.get(DOCUMENTATION_GENMODEL_DETAILS)); + + metadataSheet.appendRow(); + } + } + + private void createEClassMetadataSheetHeader(Sheet metadataSheet, Map exportOptions) { + createMetadataSheetHeader(metadataSheet, METADATA_ECLASS_SHEET_HEADERS, exportOptions); + } + + private void createEEnumMetadataSheetHeader(Sheet metadataSheet, Map exportOptions) { + createMetadataSheetHeader(metadataSheet, METADATA_EENUM_SHEET_HEADERS, exportOptions); + } + + private void createMetadataSheetHeader(Sheet metadataSheet, List headers, + Map exportOptions) { int columnsCount = headers.size(); - metadataSheet.appendColumns(columnsCount - 1); + metadataSheet.appendColumns(columnsCount - metadataSheet.getMaxColumns()); + + Range metadataSheetHeaderRow = metadataSheet.getRange((metadataSheet.getMaxRows() - 1), 0, 1, + metadataSheet.getMaxColumns()); - Range metadataSheetHeaderRow = metadataSheet.getRange(0, 0, 1, metadataSheet.getMaxColumns()); metadataSheetHeaderRow.setStyle(HEADER_STYLE); for (int colIndex = 0; colIndex < metadataSheet.getMaxColumns(); colIndex++) { - createMetadataSheetHeaderCell(metadataSheetHeaderRow, colIndex, headers.get(colIndex)); + createMetadataSheetHeaderCell(metadataSheetHeaderRow, colIndex, headers.get(colIndex), exportOptions); } } - private void createMetadataSheetHeaderCell(Range metadataSheetHeaderRow, int colIndex, String headerName) { + private void createMetadataSheetHeaderCell(Range metadataSheetHeaderRow, int colIndex, String headerName, + Map exportOptions) { metadataSheetHeaderRow.getCell(0, colIndex).setValue(headerName); + + if (adjustColumnWidthEnabled(exportOptions)) { + adjustColumnWidth(metadataSheetHeaderRow.getSheet(), colIndex, adjustColumnWidthCharsCount(headerName)); + } } private void createEClassMetadataSheetData(Sheet metadataSheet, EClass eClass) { @@ -1068,7 +1132,7 @@ private void createEClassMetadataSheetDataCell(Range metadataSheetDataRow, int c setEClassMetadataDefaultValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); break; case 5: // Documentation - setEClassMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); + setEStructuralFeatureMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, eStructuralFeature); break; } } @@ -1085,7 +1149,7 @@ private void createEEnumMetadataSheetDataCell(Range metadataSheetDataRow, int co setEEnumMetadataValueValueCell(metadataSheetDataRow, colIndex, eEnumLiteral); break; case 3: // Documentation - setEEnumMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, eEnumLiteral); + setEEnumLiteralMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, eEnumLiteral); break; } } @@ -1155,7 +1219,7 @@ private void setEClassMetadataDefaultValueCell(Range metadataSheetDataRow, int c setVoidValueCell(metadataSheetDataRow, colIndex); } - private void setEClassMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, + private void setEStructuralFeatureMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, EStructuralFeature eStructuralFeature) { EAnnotation genModelAnnotation = eStructuralFeature.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); @@ -1174,7 +1238,7 @@ private void setEEnumMetadataValueValueCell(Range metadataSheetDataRow, int colI setNumberValueCell(metadataSheetDataRow, colIndex, eEnumLiteral.getValue()); } - private void setEEnumMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, + private void setEEnumLiteralMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, EEnumLiteral eEnumLiteral) { EAnnotation genModelAnnotation = eEnumLiteral.getEAnnotation(DOCUMENTATION_GENMODEL_SOURCE); @@ -1187,12 +1251,16 @@ private void setMetadataDocumentationValueCell(Range metadataSheetDataRow, int c Map genModelAnnotationDetails = genModelAnnotation.getDetails().map(); if (genModelAnnotationDetails.containsKey(DOCUMENTATION_GENMODEL_DETAILS)) { - String documentation = genModelAnnotationDetails.get(DOCUMENTATION_GENMODEL_DETAILS); - setStringValueCell(metadataSheetDataRow, colIndex, documentation); + setMetadataDocumentationValueCell(metadataSheetDataRow, colIndex, + genModelAnnotationDetails.get(DOCUMENTATION_GENMODEL_DETAILS)); } + } else { + setVoidValueCell(metadataSheetDataRow, colIndex); } + } - setVoidValueCell(metadataSheetDataRow, colIndex); + private void setMetadataDocumentationValueCell(Range metadataSheetDataRow, int colIndex, String documentation) { + setStringValueCell(metadataSheetDataRow, colIndex, documentation); } private int getEObjectIdentifier(EObject eObject) {