Skip to content

Commit

Permalink
Fixes #982 (#1192)
Browse files Browse the repository at this point in the history
* Added support for model inheritance in code generators

* added support for datatypes
  • Loading branch information
aedelmann authored Nov 27, 2018
1 parent e74a33f commit 26756b8
Show file tree
Hide file tree
Showing 11 changed files with 366 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/**
* Copyright (c) 2015-2018 Bosch Software Innovations GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Bosch Software Innovations GmbH - Please refer to git log
*/
package org.eclipse.vorto.core.api.model;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.vorto.core.api.model.datatype.Entity;
import org.eclipse.vorto.core.api.model.datatype.ObjectPropertyType;
import org.eclipse.vorto.core.api.model.datatype.Property;
import org.eclipse.vorto.core.api.model.functionblock.Configuration;
import org.eclipse.vorto.core.api.model.functionblock.FunctionBlock;
import org.eclipse.vorto.core.api.model.functionblock.FunctionblockFactory;
import org.eclipse.vorto.core.api.model.functionblock.FunctionblockModel;
import org.eclipse.vorto.core.api.model.functionblock.Operation;
import org.eclipse.vorto.core.api.model.functionblock.Status;
import org.eclipse.vorto.core.api.model.informationmodel.FunctionblockProperty;
import org.eclipse.vorto.core.api.model.informationmodel.InformationModel;
import org.eclipse.vorto.core.api.model.model.ModelFactory;
import org.eclipse.vorto.core.api.model.model.ModelIdFactory;
import org.eclipse.vorto.core.api.model.model.ModelReference;

public class ModelConversionUtils {

public static FunctionblockModel convertToFlatHierarchy(FunctionblockModel fbm) {
FunctionBlock fb = fbm.getFunctionblock();

// Consolidate all properties
List<Property> properties = getFlatProperties(fbm);

// remove super type reference
if (fbm.getSuperType() != null) {
removeSuperTypeModelReference(fbm);
}
properties.stream().filter(p -> p.getType() instanceof ObjectPropertyType).forEach(p -> createReference(fbm, (ObjectPropertyType)p.getType()));

Status status = FunctionblockFactory.eINSTANCE.createStatus();
status.getProperties().addAll(properties.stream().filter(p -> p.eContainer() instanceof Status).collect(Collectors.toList()));

fb.setStatus(status);

Configuration configuration = FunctionblockFactory.eINSTANCE.createConfiguration();
configuration.getProperties().addAll(properties.stream().filter(p -> p.eContainer() instanceof Configuration).collect(Collectors.toList()));
fb.setConfiguration(configuration);


// Consolidate all operations
List<Operation> operations = getFlatOperations(fbm);
fb.getOperations().clear();
fb.getOperations().addAll(operations);


return fbm;
}

private static void removeSuperTypeModelReference(FunctionblockModel fbm) {
Iterator<ModelReference> iter = fbm.getReferences().iterator();
while (iter.hasNext()) {
ModelReference reference = iter.next();
ModelReference superTypeReference = ModelIdFactory.newInstance(fbm.getSuperType()).asModelReference();
if (EcoreUtil.equals(superTypeReference, reference)) {
iter.remove();
}
}

}

private static void createReference(FunctionblockModel fbm, ObjectPropertyType type) {
ModelReference reference = ModelFactory.eINSTANCE.createModelReference();
reference.setImportedNamespace(type.getType().getNamespace()+"."+type.getType().getName());
reference.setVersion(type.getType().getVersion());
fbm.getReferences().add(reference);
}

private static List<Operation> getFlatOperations(FunctionblockModel fbm) {
List<Operation> operations = new ArrayList<Operation>();
TreeIterator<EObject> iter = fbm.eAllContents();
while (iter.hasNext()) {
EObject obj = iter.next();
if (obj instanceof Operation) {
operations.add((Operation)obj);
}
}
if (fbm.getSuperType() != null) {
operations.addAll(getFlatOperations(fbm.getSuperType()));
}
return operations;
}

public static InformationModel convertToFlatHierarchy(InformationModel infomodel) {
for (FunctionblockProperty fbProperty : infomodel.getProperties()) {
FunctionblockModel fbm = fbProperty.getType();
fbProperty.setType(convertToFlatHierarchy(fbm));

// merge any extended properties from information model to the FB properties
if (fbProperty.getExtendedFunctionBlock() != null && fbProperty.getExtendedFunctionBlock().getStatus() != null) {
for (Property extendedProperty : fbProperty.getExtendedFunctionBlock().getStatus().getProperties()) {
Optional<Property> baseProperty = fbm.getFunctionblock().getStatus().getProperties().stream().filter(p -> p.getName().equals(extendedProperty.getName())).findFirst();
if (baseProperty.isPresent()) {
baseProperty.get().setConstraintRule(extendedProperty.getConstraintRule());
}
}
}
}

return infomodel;
}

private static List<Property> getFlatProperties(FunctionblockModel fbm) {
List<Property> properties = new ArrayList<Property>();
TreeIterator<EObject> iter = fbm.eAllContents();
while (iter.hasNext()) {
EObject obj = iter.next();
if (obj instanceof Property) {
Property property = (Property)obj;
properties.add(property);

if (property.getType() instanceof ObjectPropertyType) {
ObjectPropertyType objectType = (ObjectPropertyType)property.getType();
if (objectType.getType() instanceof Entity) { // only flatten entities
Entity entity = (Entity)((ObjectPropertyType)property.getType()).getType();
List<Property> entityProperties = getFlatProperties(entity);
entity.getProperties().addAll(entityProperties);
if (entity.getSuperType() != null) {
removeSuperTypeModelReference(entity);
}
entity.getProperties().stream().filter(p -> p.getType() instanceof ObjectPropertyType).forEach(p -> createReference(entity,(ObjectPropertyType)p.getType()));

}
}
}
}
if (fbm.getSuperType() != null) {
properties.addAll(getFlatProperties(fbm.getSuperType()));
}
return properties;
}

private static void removeSuperTypeModelReference(Entity entity) {
Iterator<ModelReference> iter = entity.getReferences().iterator();
while (iter.hasNext()) {
ModelReference reference = iter.next();
ModelReference superTypeReference = ModelIdFactory.newInstance(entity.getSuperType()).asModelReference();
if (EcoreUtil.equals(superTypeReference, reference)) {
iter.remove();
}
}

}

private static void createReference(Entity entity, ObjectPropertyType type) {
ModelReference reference = ModelFactory.eINSTANCE.createModelReference();
reference.setImportedNamespace(type.getType().getNamespace()+"."+type.getType().getName());
reference.setVersion(type.getType().getVersion());
entity.getReferences().add(reference);
}

private static List<Property> getFlatProperties(Entity entity) {
List<Property> properties = new ArrayList<Property>();
TreeIterator<EObject> iter = entity.eAllContents();
while (iter.hasNext()) {
EObject obj = iter.next();
if (obj instanceof Property) {
Property property = (Property)obj;
properties.add(property);
}
}
if (entity.getSuperType() != null) {
properties.addAll(getFlatProperties(entity.getSuperType()));
}
return properties;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.eclipse.vorto.codegen.spi.repository.GeneratorRepository;
import org.eclipse.vorto.codegen.spi.utils.GatewayUtils;
import org.eclipse.vorto.codegen.utils.Utils;
import org.eclipse.vorto.core.api.model.ModelConversionUtils;
import org.eclipse.vorto.core.api.model.datatype.impl.DatatypePackageImpl;
import org.eclipse.vorto.core.api.model.functionblock.FunctionblockModel;
import org.eclipse.vorto.core.api.model.functionblock.impl.FunctionblockPackageImpl;
Expand Down Expand Up @@ -130,7 +131,7 @@ public IGenerationResult generate(String key, Map<String, String> parameters, Op

private IGenerationResult generate(IVortoCodeGenerator generator, InformationModel model, InvocationContext invocationContext) {
try {
return generator.generate(model, invocationContext, null);
return generator.generate(ModelConversionUtils.convertToFlatHierarchy(model), invocationContext, null);
} catch(Exception e) {
LOGGER.error(String.format("Exception on generating [%s.%s:%s] for key[%s]",
model.getNamespace(), model.getName(), model.getVersion(), generator.getServiceKey()), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,19 @@ public abstract class AbstractRepositoryController extends ResponseEntityExcepti

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason = "Model not found.") // 404
@ExceptionHandler(ModelNotFoundException.class)
public void NotFound(final ModelNotFoundException ex){
public void notFound(final ModelNotFoundException ex){
// do logging
}

@ResponseStatus(value=HttpStatus.CONFLICT, reason = "Model already exists.") // 409
@ExceptionHandler(ModelAlreadyExistsException.class)
public void ModelExists(final ModelAlreadyExistsException ex){
public void modelExists(final ModelAlreadyExistsException ex){
// do logging
}

@ResponseStatus(value=HttpStatus.BAD_REQUEST, reason = "Wrong Input") // 405
@ExceptionHandler(IllegalArgumentException.class)
public void WrongInput(final IllegalArgumentException ex){
public void wrongInput(final IllegalArgumentException ex){
// do logging
}

Expand All @@ -81,7 +81,7 @@ public void unAuthorized(final NotAuthorizedException ex){

@ResponseStatus(value=HttpStatus.BAD_REQUEST, reason = "Error during generation.")
@ExceptionHandler(GenerationException.class)
public void GeneratorProblem(final GenerationException ex){
public void generatorProblem(final GenerationException ex){
// do logging
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

import org.eclipse.vorto.core.api.model.ModelConversionUtils;
import org.eclipse.vorto.core.api.model.datatype.Entity;
import org.eclipse.vorto.core.api.model.datatype.ObjectPropertyType;
import org.eclipse.vorto.core.api.model.datatype.Property;
import org.eclipse.vorto.core.api.model.functionblock.FunctionblockModel;
import org.eclipse.vorto.core.api.model.informationmodel.InformationModel;
import org.eclipse.vorto.core.api.model.mapping.MappingModel;
Expand Down Expand Up @@ -97,4 +100,68 @@ public void testReadMultipleZipFiles() {

assertEquals(10,workspace.get().size());
}

@Test
public void testFlatInheritanceFB() {
IModelWorkspace workspace = IModelWorkspace.newReader()
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SomeFb.fbmodel"),ModelType.Functionblock)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SuperFb.fbmodel"),ModelType.Functionblock)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SuperSuperFb.fbmodel"),ModelType.Functionblock)
.read();

FunctionblockModel fbm = ModelConversionUtils.convertToFlatHierarchy((FunctionblockModel)workspace.get().get(0));
assertEquals("SomeFb",fbm.getName());
assertEquals(4,fbm.getFunctionblock().getStatus().getProperties().size());
assertEquals(3,fbm.getFunctionblock().getConfiguration().getProperties().size());
assertEquals(2,fbm.getFunctionblock().getOperations().size());
}

@Test
public void testFlatInheritanceIM() {
IModelWorkspace workspace = IModelWorkspace.newReader()
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/TestModel.infomodel"),ModelType.InformationModel)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SomeFb.fbmodel"),ModelType.Functionblock)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SuperFb.fbmodel"),ModelType.Functionblock)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SuperSuperFb.fbmodel"),ModelType.Functionblock)
.read();

InformationModel infomodel = ModelConversionUtils.convertToFlatHierarchy((InformationModel)workspace.get().get(0));
assertEquals("TestModel",infomodel.getName());

assertEquals(4,infomodel.getProperties().get(0).getType().getFunctionblock().getStatus().getProperties().size());
assertEquals(3,infomodel.getProperties().get(0).getType().getFunctionblock().getConfiguration().getProperties().size());
assertEquals(2,infomodel.getProperties().get(0).getType().getFunctionblock().getOperations().size());

Property statusProperty = infomodel.getProperties().get(0).getType().getFunctionblock().getStatus().getProperties().stream().filter(p -> p.getName().equals("statusProp")).findFirst().get();

assertEquals(2,statusProperty.getConstraintRule().getConstraints().size());
}

@Test
public void testFlatInheritanceFBwithDatatypes() {
IModelWorkspace workspace = IModelWorkspace.newReader()
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/Brightness.type"),ModelType.Datatype)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/Light.type"),ModelType.Datatype)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/ColorLight.type"),ModelType.Datatype)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/TestModel.infomodel"),ModelType.InformationModel)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SomeFb.fbmodel"),ModelType.Functionblock)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SuperFb.fbmodel"),ModelType.Functionblock)
.addFile(getClass().getClassLoader().getResourceAsStream("dsls/SuperSuperFb.fbmodel"),ModelType.Functionblock)
.read();

InformationModel infomodel = ModelConversionUtils.convertToFlatHierarchy((InformationModel)workspace.get().get(3));
assertEquals("TestModel",infomodel.getName());

Property colorLightProperty = infomodel.getProperties().get(0).getType().getFunctionblock().getStatus().getProperties().stream().filter(p -> p.getName().equals("light")).findFirst().get();
assertNotNull(colorLightProperty);

ObjectPropertyType type = (ObjectPropertyType)colorLightProperty.getType();
Entity colorLight = (Entity)type.getType();
assertEquals(2,colorLight.getProperties().size());
assertEquals(1,colorLight.getReferences().size());

assertEquals(1,infomodel.getProperties().get(0).getType().getReferences().size());
assertEquals("iot.ColorLight",infomodel.getProperties().get(0).getType().getReferences().get(0).getImportedNamespace());
}

}
6 changes: 6 additions & 0 deletions utilities/dsl-reader/src/test/resources/dsls/Brightness.type
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace iot
version 0.0.1

enum Brightness {
HIGH,LOW
}
8 changes: 8 additions & 0 deletions utilities/dsl-reader/src/test/resources/dsls/ColorLight.type
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace iot
version 0.0.1

using iot.Light;0.0.1

entity ColorLight extends Light {
mandatory color as string
}
8 changes: 8 additions & 0 deletions utilities/dsl-reader/src/test/resources/dsls/Light.type
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace iot
version 0.0.1

using iot.Brightness;0.0.1

entity Light {
mandatory brightness as Brightness
}
18 changes: 18 additions & 0 deletions utilities/dsl-reader/src/test/resources/dsls/SomeFb.fbmodel
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace iot
version 0.0.1
displayname "SomeFb"
description ""

using iot.SuperFb;0.0.1

functionblock SomeFb extends SuperFb {

configuration {
mandatory configProp as string
}

status {
mandatory statusProp as string
}

}
22 changes: 22 additions & 0 deletions utilities/dsl-reader/src/test/resources/dsls/SuperFb.fbmodel
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace iot
version 0.0.1
displayname "SuperFb"
description ""

using iot.SuperSuperFb;0.0.1

functionblock SuperFb extends SuperSuperFb {

configuration {
mandatory superConfigProp as string
}

status {
mandatory superStatusProp as string
}

operations {
superOp()
}

}
Loading

0 comments on commit 26756b8

Please sign in to comment.