Skip to content

Commit

Permalink
2104 Ditto structure generation (#2109)
Browse files Browse the repository at this point in the history
* Fixed URL building for generators. Fixes #2104

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>

* Move Ditto structure creation into EclipseDittoGenerator and add request parameter. Fixes #2104

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>

* Rename dittoStructure to dittoThingStructure. Fixes #2104

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>

* Fix imports of generated classes. Fixes #2104

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>

* Fix whitespaces to get tests passing again. Fixes #2104

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>

* adapt request parameter in unit test. Fixes #2104

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>

* Change request header for Ditto Generator

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>

* Add thingJson parameter to readme. Fixes #2104

Signed-off-by: kolotu <kevin.olotu@bosch-si.com>
  • Loading branch information
kolotu authored and aedelmann committed Nov 27, 2019
1 parent c9814fd commit c8d183e
Show file tree
Hide file tree
Showing 12 changed files with 322 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.vorto</groupId>
<artifactId>generator-eclipseditto</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.vorto</groupId>
<artifactId>hono</artifactId>
Expand Down Expand Up @@ -59,4 +65,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.eclipse.vorto.core.api.model.datatype.PrimitiveType
import org.eclipse.vorto.core.api.model.informationmodel.InformationModel
import org.eclipse.vorto.plugin.generator.InvocationContext
import org.eclipse.vorto.plugin.generator.utils.IFileTemplate
import org.eclipse.vorto.codegen.ditto.schema.tasks.template.DittoThingStructureTemplate

class ProvisioningAPIRequestTemplate implements IFileTemplate<InformationModel> {

Expand Down Expand Up @@ -36,39 +37,7 @@ class ProvisioningAPIRequestTemplate implements IFileTemplate<InformationModel>
]
}
},
"things": {
"thing": {
"attributes": {
"thingName": "«model.displayname»",
"definition": "«model.namespace»:«model.name»:«model.version»"
},
"features": {
«FOR fbProperty : model.properties SEPARATOR ","»
"«fbProperty.name»" : {
"definition": [
"«fbProperty.type.namespace»:«fbProperty.type.name»:«fbProperty.type.version»"
],
"properties": {
«IF fbProperty.type.functionblock.status !== null && !fbProperty.type.functionblock.status.properties.isEmpty»
"status": {
«FOR statusProperty : fbProperty.type.functionblock.status.properties SEPARATOR ","»
"«statusProperty.name»" : «IF statusProperty.type instanceof PrimitivePropertyType»«getJsonPrimitive(statusProperty.type as PrimitivePropertyType)»«ELSEIF statusProperty.type instanceof ObjectPropertyType»«getJsonObjectType(statusProperty.type as ObjectPropertyType)»«ELSE»«getJsonDictionaryType(statusProperty.type as DictionaryPropertyType)»«ENDIF»
«ENDFOR»
}«IF fbProperty.type.functionblock.configuration !== null && !fbProperty.type.functionblock.configuration.properties.isEmpty»,«ENDIF»
«ENDIF»
«IF fbProperty.type.functionblock.configuration !== null && !fbProperty.type.functionblock.configuration.properties.isEmpty»
"configuration": {
«FOR configProperty : fbProperty.type.functionblock.configuration.properties SEPARATOR ","»
"«configProperty.name»" : «IF configProperty.type instanceof PrimitivePropertyType»«getJsonPrimitive(configProperty.type as PrimitivePropertyType)»«ELSEIF configProperty.type instanceof ObjectPropertyType»«getJsonObjectType(configProperty.type as ObjectPropertyType)»«ELSE»«getJsonDictionaryType(configProperty.type as DictionaryPropertyType)»«ENDIF»
«ENDFOR»
}
«ENDIF»
}
}
«ENDFOR»
}
}
}
«new DittoThingStructureTemplate().getContent(model, context)»
}
'''
}
Expand Down Expand Up @@ -128,4 +97,4 @@ class ProvisioningAPIRequestTemplate implements IFileTemplate<InformationModel>
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ProvisionDeviceScriptTemplateTest {
im.withFunctionBlock(fbm, "cpuTemperature", null, false);

var generated = template.getContent(im.build, InvocationContext.simpleInvocationContext());
System.out.println(generated);
System.out.println("testCreateScriptWithSingleFb: generated:" + cleaned(generated));
Assert.assertEquals(cleaned(expectedTemplate1), cleaned(generated));
}

Expand Down Expand Up @@ -108,12 +108,12 @@ class ProvisionDeviceScriptTemplateTest {
im.withFunctionBlock(fbm, "outdoorTemperature", null, false)

var generated = template.getContent(im.build, InvocationContext.simpleInvocationContext());
System.out.println(generated);
System.out.println("testCreateScriptWithMultipleFbs: generated:" + cleaned(generated));
Assert.assertEquals(cleaned(expectedTemplate2), cleaned(generated));
}

def cleaned(String text) {
return StringUtils.normalizeSpace(text.replaceAll("\\\\r\\\\n", "\\\\n"))
return StringUtils.deleteWhitespace(StringUtils.normalizeSpace(text.replaceAll("\\\\r\\\\n", "\\\\n")))
}

def String getExpectedTemplate2() {
Expand Down
8 changes: 8 additions & 0 deletions generators/generator-eclipseditto/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,11 @@ after JSON Schema was generated by this generator.
The following curl commands show, how you can invoke the Eclipse Ditto Generator

curl -GET http://vorto.eclipse.org/api/v1/generators/eclipseditto/models/com.ipso.smartobjects.Load_Control:1.1.0

## Thing JSON Option

The request parameter target=thingJson will generate the Ditto Thing JSON instead. This JSON can be sent to Ditto to create a thing.
For usage refer to the [Eclipse Ditto HTTP API documentation](https://www.eclipse.org/ditto/http-api-doc.html).

## Example Usage
curl -GET http://vorto.eclipse.org/api/v1/generators/eclipseditto/models/com.ipso.smartobjects.Load_Control:1.1.0?target=thingJson
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,64 @@
package org.eclipse.vorto.codegen.ditto;

import org.eclipse.vorto.codegen.ditto.schema.SchemaValidatorTask;
import org.eclipse.vorto.codegen.ditto.schema.tasks.template.JsonObjectWrappedDittoThingStructureTemplate;
import org.eclipse.vorto.core.api.model.informationmodel.InformationModel;
import org.eclipse.vorto.plugin.generator.GeneratorException;
import org.eclipse.vorto.plugin.generator.GeneratorPluginInfo;
import org.eclipse.vorto.plugin.generator.ICodeGenerator;
import org.eclipse.vorto.plugin.generator.IGenerationResult;
import org.eclipse.vorto.plugin.generator.InvocationContext;
import org.eclipse.vorto.plugin.generator.config.ConfigTemplateBuilder;
import org.eclipse.vorto.plugin.generator.config.ConfigTemplateBuilder.ChoiceItem;
import org.eclipse.vorto.plugin.generator.utils.ChainedCodeGeneratorTask;
import org.eclipse.vorto.plugin.generator.utils.GenerationResultBuilder;
import org.eclipse.vorto.plugin.generator.utils.GenerationResultZip;
import org.eclipse.vorto.plugin.generator.utils.GeneratorTaskFromFileTemplate;
import org.eclipse.vorto.plugin.generator.utils.SingleGenerationResult;


/**
* Vorto Generator which generates JSON Schema files for Eclipse Ditto in order to validate whether
* properties (state) and message payloads (operations, events) are in expeceted JSON format.
*/
public final class EclipseDittoGenerator implements ICodeGenerator {

private static final String KEY = "eclipseditto";
private static final JsonObjectWrappedDittoThingStructureTemplate REQUEST_TEMPLATE = new JsonObjectWrappedDittoThingStructureTemplate();
private static final String GENERATOR_KEY = "eclipseditto";
private static final String THING_JSON = "thingJson";

@Override
public IGenerationResult generate(InformationModel infomodel, InvocationContext invocationContext) throws GeneratorException {
String target = invocationContext.getConfigurationProperties().getOrDefault("target", "");
if (THING_JSON.equalsIgnoreCase(target)) {
SingleGenerationResult output = new SingleGenerationResult("application/json");
new GeneratorTaskFromFileTemplate<>(REQUEST_TEMPLATE).generate(infomodel, invocationContext, output);
return output;
}

GenerationResultZip zipOutputter = new GenerationResultZip(infomodel,KEY );

ChainedCodeGeneratorTask<InformationModel> generator =
new ChainedCodeGeneratorTask<InformationModel>();
GenerationResultZip zipOutput = new GenerationResultZip(infomodel, GENERATOR_KEY);
ChainedCodeGeneratorTask<InformationModel> generator = new ChainedCodeGeneratorTask<>();
generator.addTask(new SchemaValidatorTask());
generator.generate(infomodel, invocationContext, zipOutputter);

GenerationResultBuilder result = GenerationResultBuilder.from(zipOutputter);
generator.generate(infomodel, invocationContext, zipOutput);
GenerationResultBuilder result = GenerationResultBuilder.from(zipOutput);
return result.build();
}

@Override
public GeneratorPluginInfo getMeta() {
return GeneratorPluginInfo.Builder(KEY)
return GeneratorPluginInfo.Builder(GENERATOR_KEY)
.withConfigurationTemplate(ConfigTemplateBuilder.builder().withChoiceConfigurationItem(
"target", "Output format",
ChoiceItem.of("Ditto Thing JSON", THING_JSON),
ChoiceItem.of("JSON Schema", ""))
.build())
.withVendor("Eclipse Ditto Team")
.withName("Eclipse Ditto")
.withDescription("Creates JSON schema files in order to validate Things managed by Eclipse Ditto.")
.withDocumentationUrl("https://www.eclipse.org/ditto")
.withDescription("Creates JSON schema files in order to validate Things managed by Eclipse "
+ "Ditto. With the Ditto Thing JSON Option, the generator creates a Thing JSON, "
+ "which can be send to Ditto to create a Thing.")
.withDocumentationUrl(
"https://github.com/eclipse/vorto/blob/master/generators/generator-eclipseditto/Readme.md")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*******************************************************************************
* Copyright (c) 2019 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.codegen.ditto.schema.tasks.template

import org.eclipse.vorto.core.api.model.datatype.DictionaryPropertyType
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.PrimitivePropertyType
import org.eclipse.vorto.core.api.model.datatype.PrimitiveType
import org.eclipse.vorto.core.api.model.informationmodel.InformationModel
import org.eclipse.vorto.plugin.generator.InvocationContext
import org.eclipse.vorto.plugin.generator.utils.IFileTemplate

class DittoThingStructureTemplate implements IFileTemplate<InformationModel> {

override getFileName(InformationModel context) {
return "dittoStructure.json";
}

override getPath(InformationModel context) {
return null;
}

override getContent(InformationModel model, InvocationContext context) {
'''
"things": {
"thing": {
"attributes": {
"thingName": "«model.displayname»",
"definition": "«model.namespace»:«model.name»:«model.version»"
},
"features": {
«FOR fbProperty : model.properties SEPARATOR ","»
"«fbProperty.name»" : {
"definition": [
"«fbProperty.type.namespace»:«fbProperty.type.name»:«fbProperty.type.version»"
],
"properties": {
«IF fbProperty.type.functionblock.status !== null && !fbProperty.type.functionblock.status.properties.isEmpty»
"status": {
«FOR statusProperty : fbProperty.type.functionblock.status.properties SEPARATOR ","»
"«statusProperty.name»" : «IF statusProperty.type instanceof PrimitivePropertyType»«getJsonPrimitive(statusProperty.type as PrimitivePropertyType)»«ELSEIF statusProperty.type instanceof ObjectPropertyType»«getJsonObjectType(statusProperty.type as ObjectPropertyType)»«ELSE»«getJsonDictionaryType(statusProperty.type as DictionaryPropertyType)»«ENDIF»
«ENDFOR»
}«IF fbProperty.type.functionblock.configuration !== null && !fbProperty.type.functionblock.configuration.properties.isEmpty»,«ENDIF»
«ENDIF»
«IF fbProperty.type.functionblock.configuration !== null && !fbProperty.type.functionblock.configuration.properties.isEmpty»
"configuration": {
«FOR configProperty : fbProperty.type.functionblock.configuration.properties SEPARATOR ","»
"«configProperty.name»" : «IF configProperty.type instanceof PrimitivePropertyType»«getJsonPrimitive(configProperty.type as PrimitivePropertyType)»«ELSEIF configProperty.type instanceof ObjectPropertyType»«getJsonObjectType(configProperty.type as ObjectPropertyType)»«ELSE»«getJsonDictionaryType(configProperty.type as DictionaryPropertyType)»«ENDIF»
«ENDFOR»
}
«ENDIF»
}
}
«ENDFOR»
}
}
}
'''
}

def getJsonDictionaryType(DictionaryPropertyType propertyType) {
'''
{
"key" : "value"
}
'''
}

def String getJsonObjectType(ObjectPropertyType propertyType) {
if (propertyType.type instanceof org.eclipse.vorto.core.api.model.datatype.Enum) {
var literals = (propertyType.type as org.eclipse.vorto.core.api.model.datatype.Enum).enums;
if (literals.empty) {
return "\"\""
} else {
return "\"" + literals.get(0).name + "\"";
}
} else {
return getEntityJson(propertyType.type as Entity).toString();
}
}

def getEntityJson(Entity entity) {
'''
{
«FOR property : entity.properties SEPARATOR ","»
"«property.name»" : «IF property.type instanceof PrimitivePropertyType»«getJsonPrimitive(property.type as PrimitivePropertyType)»«ELSE»«getJsonObjectType(property.type as ObjectPropertyType)»«ENDIF»
«ENDFOR»
}
'''
}

def getJsonPrimitive(PrimitivePropertyType propertyType) {
if (propertyType.type === PrimitiveType.BASE64_BINARY) {
return "\"\""
} else if (propertyType.type === PrimitiveType.BOOLEAN) {
return false
} else if (propertyType.type === PrimitiveType.BYTE) {
return "\"\""
} else if (propertyType.type === PrimitiveType.DATETIME) {
return "\"2019-04-01T18:25:43-00:00\""
} else if (propertyType.type === PrimitiveType.DOUBLE) {
return 0.0
} else if (propertyType.type === PrimitiveType.FLOAT) {
return 0.0
} else if (propertyType.type === PrimitiveType.INT) {
return 0
} else if (propertyType.type === PrimitiveType.LONG) {
return 0
} else if (propertyType.type === PrimitiveType.SHORT) {
return 0
} else {
return "\"\""
}
}

}
Loading

0 comments on commit c8d183e

Please sign in to comment.