Skip to content

Commit

Permalink
Add support for keySchema and entrySchema in properties definitions f…
Browse files Browse the repository at this point in the history
…or YAML
  • Loading branch information
Vogel612 committed Jul 20, 2020
1 parent 5bf2489 commit a134b11
Show file tree
Hide file tree
Showing 27 changed files with 640 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,6 @@ export class PropertiesDefinitionComponent implements OnInit {
this.resourceApiData.propertiesDefinition.element = null;
this.resourceApiData.propertiesDefinition.type = null;

if (this.resourceApiData.propertiesDefinition) {
this.resourceApiData.propertiesDefinition = new PropertiesDefinition();
}
this.resourceApiData.propertiesDefinition.element = null;
this.resourceApiData.propertiesDefinition.type = null;

if (!this.resourceApiData.winerysPropertiesDefinition) {
this.resourceApiData.winerysPropertiesDefinition = new WinerysPropertiesDefinition();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import { Component, Input } from '@angular/core';
import { InstanceService } from '../../../instance.service';
import { YamlPropertyConstraint } from '../properties/yamlProperty';
import { YamlPropertyConstraint } from '../../propertiesDefinition/yaml/yamlProperty';

@Component({
selector: 'winery-yaml-constraints',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,20 @@
<td>Description</td>
<td>Required</td>
<td>Default</td>
<td>Status</td>
<!-- <td>Actions</td>-->
</tr>
</thead>
<tbody>
<ng-template ngFor let-prop [ngForOf]="properties">
<tr>
<td>{{ prop.name }}</td>
<td>{{ prop.type }}</td>
<td>{{ prop.type }}{{ prop.humanSchema }}</td>
<td>{{ prop.description}}</td>
<td>{{ prop.required }}</td>
<td>{{ prop.defaultValue }}</td>
<td>{{ prop.status }}</td>
</tr>
<tr *ngIf="prop.constraints.length" class="constraints-row">
<td>Constraints:</td>
<td colspan="5">
<td colspan="4">
<winery-yaml-constraints [constraints]="prop.constraints"></winery-yaml-constraints>
</td>
</tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class YamlPropertiesService {

constructor(private http: HttpClient,
private sharedData: InstanceService) {
this.path = backendBaseURL + this.sharedData.path + '/properties/';
this.path = this.sharedData.path + '/properties/';
}

public getProperties(): Observable<YamlProperty[]> {
Expand All @@ -37,21 +37,33 @@ export class YamlPropertiesService {
if (res.headers.get('Content-Type') === 'application/json') {
// fake some null-coalescing
if (res.body === null) { return []; }
return JSON.parse(res.body);
return JSON.parse(res.body)
.map((def: YamlProperty) => {
// FIXME we want to be a bit smarter about converting these to human-readable types.
// (especially since nesting is an option)
if (def.entrySchema || def.keySchema) {
if (def.type === 'list') {
def.humanSchema = ` of ${def.entrySchema.type}`;
} else if (def.type === 'map') {
def.humanSchema = ` from ${(def.keySchema || {type: 'string'}).type} to ${def.entrySchema.type}`;
}
} else { def.humanSchema = ''; }
return def;
});
} else {
// log an error
return [];
}
}));
}

public saveProperties(properties: any): Observable<HttpResponse<string>> {
public saveProperties(properties: YamlProperty[]): Observable<HttpResponse<string>> {
const headers = new HttpHeaders();
headers.set('Content-Type', 'application/json');
return this.http
.put(
this.path,
properties,
properties.map(p => { delete(p.humanSchema); return p; }),
{ headers: headers, observe: 'response', responseType: 'text' }
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@
*******************************************************************************/
import { QName } from '../../../../model/qName';
import { KeyValueItem } from '../../../../model/keyValueItem';
import { SchemaDefinition } from '../../../../../../../topologymodeler/src/app/models/ttopology-template';
import { YamlWellKnown } from '../../../../../../../topologymodeler/src/app/properties/property-constraints';

export class YamlProperty {
name: String;
type: QName;
description: String;
name: string;
type: QName | YamlWellKnown;
description: string;
required: boolean;
defaultValue: any;
status: string;
constraints: YamlPropertyConstraint[];
keySchema: SchemaDefinition;
entrySchema: SchemaDefinition;
humanSchema: string;
}

export class YamlPropertyConstraint implements KeyValueItem {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*******************************************************************************/

package org.eclipse.winery.model.jsonsupport;

import java.io.IOException;
import java.util.List;

import org.eclipse.winery.model.tosca.TEntityTemplate;
import org.eclipse.winery.model.tosca.TEntityType;
import org.eclipse.winery.model.tosca.extensions.kvproperties.WinerysPropertiesDefinition;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class PropertiesDefinitionDeserializer extends StdDeserializer<TEntityType.PropertiesDefinition> {

public PropertiesDefinitionDeserializer() {
super(TEntityType.PropertiesDefinition.class);
}

@Override
public TEntityType.PropertiesDefinition deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
// read as ObjectNode to enable removing empty properties
ObjectNode node = parser.getCodec().readTree(parser);
final JavaType targetType;
if (node.hasNonNull("propertyDefinitionKVList")) {
// deserialize as WinerysPropertiesDefinition
targetType = context.constructType(WinerysPropertiesDefinition.class);
} else if (node.hasNonNull("element")) {
targetType = context.constructType(TEntityType.XmlElementDefinition.class);
// remove unused properties to avoid tripping up the Json Parsing
node.remove("type");
node.remove("properties");
} else if (node.hasNonNull("type")) {
targetType = context.constructType(TEntityType.XmlTypeDefinition.class);
// remove unused properties to avoid tripping up the Json Parsing
node.remove("element");
node.remove("properties");
} else if (node.hasNonNull("properties")) {
targetType = context.constructType(TEntityType.YamlPropertiesDefinition.class);
// remove unused properties to avoid tripping up the Json Parsing
node.remove("type");
node.remove("element");
} else {
// this throws an exception
context.reportMappingException("Could not determine EntityType.PropertiesDefinition implementation from properties", node.fieldNames());
return null;
}
JsonDeserializer<Object> deserializer = context.findNonContextualValueDeserializer(targetType);
// create a new JsonParser for the delegate deserializer to account for consumed input in original parser.
JsonParser objectParser = node.traverse();
// advance the parser by one token because the parser initialized by node.traverse() stays at "before start"
objectParser.nextToken();
return (TEntityType.PropertiesDefinition) deserializer.deserialize(objectParser, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.QName;

import org.eclipse.winery.model.jsonsupport.PropertiesDefinitionDeserializer;
import org.eclipse.winery.model.tosca.extensions.kvproperties.AttributeDefinitionList;
import org.eclipse.winery.model.tosca.extensions.kvproperties.ConstraintClauseKVList;
import org.eclipse.winery.model.tosca.extensions.kvproperties.WinerysPropertiesDefinition;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.github.adr.embedded.ADR;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
Expand Down Expand Up @@ -300,6 +305,11 @@ public static class YamlPropertyDefinition {
@XmlElement
private ConstraintClauseKVList constraints;

@XmlElement(name = "entry_schema")
private TSchema entrySchema;
@XmlElement(name = "key_schema")
private TSchema keySchema;

public YamlPropertyDefinition() {
// added for xml serialization!
}
Expand All @@ -312,6 +322,8 @@ private YamlPropertyDefinition(Builder builder) {
this.defaultValue = builder.defaultValue;
this.status = builder.status;
this.constraints = builder.constraints;
this.keySchema = builder.keySchema;
this.entrySchema = builder.entrySchema;
}

@XmlEnum(String.class)
Expand All @@ -330,9 +342,6 @@ public static Status getStatus(String status) {
.orElse(null);
}
}
// FIXME introduce this
// @XmlAttribute(name = "entry_schema")
// private TEntrySchema entrySchema;

public static class Builder {
private String name;
Expand All @@ -342,6 +351,8 @@ public static class Builder {
private Object defaultValue;
private YamlPropertyDefinition.Status status;
private ConstraintClauseKVList constraints;
private TSchema entrySchema;
private TSchema keySchema;

public Builder(String name) {
this.name = name;
Expand Down Expand Up @@ -381,7 +392,17 @@ public Builder setConstraints(ConstraintClauseKVList constraints) {
this.constraints = constraints;
return this;
}


public Builder setEntrySchema(TSchema entrySchema) {
this.entrySchema = entrySchema;
return this;
}

public Builder setKeySchema(TSchema keySchema) {
this.keySchema = keySchema;
return this;
}

public YamlPropertyDefinition build() {
return new YamlPropertyDefinition(this);
}
Expand All @@ -395,19 +416,21 @@ public void setName(String name) {
this.name = name;
}

@NonNull
public QName getType() {
return type;
}

public void setType(QName type) {
public void setType(@NonNull QName type) {
this.type = type;
}

@Nullable
public String getDescription() {
return description;
}

public void setDescription(String description) {
public void setDescription(@Nullable String description) {
this.description = description;
}

Expand All @@ -419,11 +442,12 @@ public void setRequired(Boolean required) {
this.required = required;
}

@Nullable
public Object getDefaultValue() {
return defaultValue;
}

public void setDefaultValue(Object defaultValue) {
public void setDefaultValue(@Nullable Object defaultValue) {
this.defaultValue = defaultValue;
}

Expand All @@ -435,13 +459,32 @@ public void setStatus(Status status) {
this.status = status;
}

@Nullable
public ConstraintClauseKVList getConstraints() {
return constraints;
}

public void setConstraints(ConstraintClauseKVList constraints) {
public void setConstraints(@Nullable ConstraintClauseKVList constraints) {
this.constraints = constraints;
}

@Nullable
public TSchema getEntrySchema() {
return entrySchema;
}

public void setEntrySchema(@Nullable TSchema entrySchema) {
this.entrySchema = entrySchema;
}

@Nullable
public TSchema getKeySchema() {
return keySchema;
}

public void setKeySchema(@Nullable TSchema keySchema) {
this.keySchema = keySchema;
}
}

/**
Expand All @@ -457,11 +500,20 @@ public void setConstraints(ConstraintClauseKVList constraints) {
XmlElementDefinition.class,
XmlTypeDefinition.class
})
@JsonSubTypes({
@JsonSubTypes.Type(YamlPropertiesDefinition.class),
@JsonSubTypes.Type(WinerysPropertiesDefinition.class),
@JsonSubTypes.Type(XmlElementDefinition.class),
@JsonSubTypes.Type(XmlTypeDefinition.class),
})
@JsonDeserialize(using = PropertiesDefinitionDeserializer.class)
public abstract static class PropertiesDefinition { }

@NonNullByDefault
@XmlRootElement(name = "PropertiesDefinition")
@JsonDeserialize(as = YamlPropertiesDefinition.class)
public static class YamlPropertiesDefinition extends PropertiesDefinition {
@JsonProperty("properties")
private List<YamlPropertyDefinition> properties = new ArrayList<>();

public List<YamlPropertyDefinition> getProperties() {
Expand All @@ -479,7 +531,9 @@ public void setProperties(List<YamlPropertyDefinition> properties) {
* see {@link XmlTypeDefinition}.
*/
@XmlRootElement(name = "PropertiesDefinition")
@JsonDeserialize(as = XmlElementDefinition.class)
public static class XmlElementDefinition extends PropertiesDefinition {
@JsonProperty
private QName element;

// required for jaxb
Expand All @@ -504,7 +558,9 @@ public void setElement(QName element) {
* the other option is a type reference.
*/
@XmlRootElement(name = "PropertiesDefinition")
@JsonDeserialize(as = XmlTypeDefinition.class)
public static class XmlTypeDefinition extends PropertiesDefinition {
@JsonProperty
private QName type;

// required for JAXB
Expand Down
Loading

0 comments on commit a134b11

Please sign in to comment.