# HG changeset patch # User Simon Tooke # Date 1504891477 14400 # Node ID 5100a9b678f4db20601e6dabaf4b72700c0e0c5e # Parent 85d12e67675d50809d39f3e7089c5ff579265d74 Initial Schema related services This patch adds initial support for schema validation and exposition services. I am down as a reviewer since the initial code is from neugens, modified by me before this first commit. Reviewed-by: neugens, stooke Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-August/024759.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024823.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024918.html diff -r 85d12e67675d -r 5100a9b678f4 common/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/pom.xml Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,57 @@ + + + + 4.0.0 + + + com.redhat.thermostat + thermostat-base + 1.99.12-SNAPSHOT + + + base-common + pom + + Thermostat Base Common + + + type-system + + + diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/pom.xml Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,116 @@ + + + 4.0.0 + + + com.redhat.thermostat + base-common + 1.99.12-SNAPSHOT + + + com.redhat.thermostat.lang.schema + thermostat-lang-schema + 1.99.12-SNAPSHOT + bundle + + + 1.7 + + + 4.3.1 + 4.3.1 + 4.3.1.201210102024 + osgi.cmpn + 4.2.0 + 1.8.2 + 1.9.12 + + 2.2.2 + 4.10 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 3.6.1 + + true + 128m + 1024m + ${thermostat.java.version} + ${thermostat.java.version} + + + + + org.apache.felix + maven-bundle-plugin + true + + + com.redhat.thermostat.lang.schema + Red Hat, Inc. + + com.redhat.thermostat.lang.schema, + com.redhat.thermostat.lang.schema.models, + com.redhat.thermostat.lang.schema.annotations + + + + com.redhat.thermostat.lang.schema.internal, + + + <_nouses>true + + + + + + + + + org.apache.felix + org.apache.felix.scr + ${felix.scr.version} + + + org.apache.felix + org.apache.felix.framework + ${felix.framework.version} + + + org.apache.felix + org.apache.felix.scr.annotations + ${felix.scr.annotations.version} + + + com.google.code.gson + gson + ${gson.version} + + + + junit + junit + ${junit.version} + test + + + + diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema; + +/** + * Serialisation service for Java types into JSON. + */ +public interface JSONService { + /** + * Serialise the object in input to JSON. + */ + String serialiase(Object target); +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema; + +public interface SchemaBuilder { + /** + * Returns the Schema for the given class. + */ + String getSchema(Class target); + + /** + * Registers a type in the schema + */ + void registerType(Class target); + +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,24 @@ +package com.redhat.thermostat.lang.schema; + +/** + */ +public class SchemaValidationException extends RuntimeException { + public SchemaValidationException() { + } + + public SchemaValidationException(String message) { + super(message); + } + + public SchemaValidationException(String message, Throwable cause) { + super(message, cause); + } + + public SchemaValidationException(Throwable cause) { + super(cause); + } + + public SchemaValidationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Define the maximum value allowed for the variable it is applied to.
+ * If {@link #exclusive()} is true, the maximum value must be strictly lower + * than the value specified by this annotation. The default number returned + * by {@link #value()} is {@link Long#MAX_VALUE}. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Maximum { + long value() default Long.MAX_VALUE; + boolean exclusive() default false; +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Define the minimum value allowed for the variable it is applied to.
+ * If {@link #exclusive()} is true, the minimum value must be strictly greater + * than the value specified by this annotation. The default number returned + * by {@link #value()} is {@link Long#MIN_VALUE}. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Minimum { + long value() default Long.MIN_VALUE; + boolean exclusive() default false; +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Schema { + String name() default ""; + String description() default ""; + boolean required() default false; +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Type { + String name() default ""; + String description() default ""; +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,123 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.internal; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import com.redhat.thermostat.lang.schema.*; + +import com.redhat.thermostat.lang.schema.annotations.Schema; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; + +import java.io.IOException; + +@Component +@Service(JSONService.class) +public class JSONServiceImpl implements JSONService { + + private GsonBuilder builder; + + public JSONServiceImpl() { + this(false); + } + + public JSONServiceImpl(boolean prettyPrinting) { + + + builder = new GsonBuilder(); + if (prettyPrinting) { + builder.setPrettyPrinting(); + } + + AutoAdapter autoAdapter = new AutoAdapter(); + + builder.registerTypeAdapter(boolean.class, autoAdapter); + builder.registerTypeAdapter(byte.class, autoAdapter); + builder.registerTypeAdapter(short.class, autoAdapter); + builder.registerTypeAdapter(int.class, autoAdapter); + builder.registerTypeAdapter(long.class, autoAdapter); + builder.registerTypeAdapter(double.class, autoAdapter); + builder.registerTypeAdapter(float.class, autoAdapter); + + builder.registerTypeAdapter(Boolean.class, autoAdapter); + builder.registerTypeAdapter(Byte.class, autoAdapter); + builder.registerTypeAdapter(Short.class, autoAdapter); + builder.registerTypeAdapter(Integer.class, autoAdapter); + builder.registerTypeAdapter(Long.class, autoAdapter); + builder.registerTypeAdapter(Double.class, autoAdapter); + builder.registerTypeAdapter(Float.class, autoAdapter); + + builder.addSerializationExclusionStrategy(new AutoExclusionStategy()); + + } + + @Override + public String serialiase(Object target) { + // TODO - consider registering this class with the schema registry + return builder.create().toJson(target); + } + + private class AutoAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, Object value) throws IOException { + out.value("" + value); + } + + @Override + public Object read(JsonReader in) throws IOException { + throw new UnsupportedOperationException("read() not yet implemented"); + } + } + + public class AutoExclusionStategy implements ExclusionStrategy { + + public boolean shouldSkipClass(Class arg0) { + return false; + } + + public boolean shouldSkipField(FieldAttributes field) { + return (field.getAnnotation(Schema.class) == null); + } + } +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,277 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.internal; + +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import com.redhat.thermostat.lang.schema.*; + +import com.redhat.thermostat.lang.schema.annotations.Maximum; +import com.redhat.thermostat.lang.schema.annotations.Minimum; +import com.redhat.thermostat.lang.schema.annotations.Schema; +import com.redhat.thermostat.lang.schema.annotations.Type; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; + +import java.io.IOException; +import java.lang.reflect.Field; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; + +@Component +@Service(SchemaBuilder.class) +public class SchemaBuilderImpl implements SchemaBuilder { + + private class FieldProperties { + String name = ""; + String description = ""; + String type = ""; + String parentType = ""; + + boolean hasMin; + long boundsMin; + boolean exclusiveMin; + + boolean hasMax; + long boundsMax; + boolean exclusiveMax; + + @Override + public String toString() { + return "FieldProperties {" + + "name='" + name + '\'' + + ", description='" + description + '\'' + + ", type='" + type + '\'' + + '}'; + } + } + + private class SchemaDefinition { + FieldProperties field = new FieldProperties(); + Set properties = new TreeSet<>(new Comparator() { + @Override + public int compare(FieldProperties o1, FieldProperties o2) { + return o1.toString().compareTo(o2.toString()); + } + }); + Set required = new TreeSet<>(); + } + + private GsonBuilder schemaBuilder; + + private Map schemas; + private Map definitions; + + public SchemaBuilderImpl() { + this(true); + } + + public SchemaBuilderImpl(boolean prettyPrinting) { + definitions = new ConcurrentHashMap<>(); + schemas = new HashMap<>(); + + schemaBuilder = new GsonBuilder(); + schemaBuilder.registerTypeAdapter(Class.class, new SchemaSerializer()); + + if (prettyPrinting) { + schemaBuilder.setPrettyPrinting(); + } + } + + private void checkTypeAndRegister(Class target) { + + if (schemas.containsKey(target.getName())) { + return; + } + + if (!target.isAnnotationPresent(Type.class)) { + throw new IllegalArgumentException("Unrecognised Type: must be annotated with " + Type.class); + } + + SchemaDefinition definition = new SchemaDefinition(); + + definition.field.name = target.getSimpleName(); + Type annotation = (Type) target.getAnnotation(Type.class); + if (!annotation.name().isEmpty()) { + definition.field.name = annotation.name(); + } + + definition.field.description = annotation.description(); + if (!target.getSuperclass().equals(Object.class)) { + definition.field.parentType = target.getSuperclass().getSimpleName(); + } + + // let's see the rest of the schema + for (Field field : target.getDeclaredFields()) { + if (field.isAnnotationPresent(Schema.class)) { + + Schema schema = field.getAnnotation(Schema.class); + + FieldProperties fieldProperties = new FieldProperties(); + fieldProperties.name = field.getName(); + if (!schema.name().isEmpty()) { + fieldProperties.name = schema.name(); + } + + fieldProperties.description = schema.description(); + fieldProperties.type = field.getType().getSimpleName(); + + if (field.isAnnotationPresent(Minimum.class)) { + fieldProperties.hasMin = true; + + Minimum range = field.getAnnotation(Minimum.class); + fieldProperties.boundsMin = range.value(); + fieldProperties.exclusiveMin = range.exclusive(); + } + + if (field.isAnnotationPresent(Maximum.class)) { + fieldProperties.hasMax = true; + + Maximum range = field.getAnnotation(Maximum.class); + fieldProperties.boundsMax = range.value(); + fieldProperties.exclusiveMax = range.exclusive(); + } + + if (fieldProperties.hasMax && fieldProperties.hasMin && + fieldProperties.boundsMin > fieldProperties.boundsMax) + { + // perhaps a better error message? + throw new SchemaValidationException("maximum and minimum bounds are incompatible: " + + "min: " + fieldProperties.boundsMin + ", " + + "max: " + fieldProperties.boundsMax); + } + + definition.properties.add(fieldProperties); + if (schema.required()) { + definition.required.add(fieldProperties.name); + } + } + } + + definitions.put(target.getName(), definition); + + String schema = schemaBuilder.create().toJson(target); + schemas.put(target.getName(), schema); + } + + @Override + public void registerType(Class target) { + checkTypeAndRegister(target); + } + + @Override + public String getSchema(Class target) { + checkTypeAndRegister(target); + + return schemas.get(target.getName()); + } + + private class SchemaSerializer extends TypeAdapter { + + @Override + public void write(JsonWriter out, Object target) throws IOException { + + SchemaDefinition definition = definitions.get(((Class) target).getName()); + + out.beginObject(); + + out.name("$schema").value("http://json-schema.org/draft-04/schema#"); + out.name("title").value(definition.field.name); + out.name("description").value(definition.field.description); + out.name("type").value("object"); + if (!definition.field.parentType.isEmpty()) { + out.name("extends").value(definition.field.parentType); + } + + if (!definition.properties.isEmpty()) { + out.name("properties"); + out.beginObject(); + + for (FieldProperties property : definition.properties) { + + out.name(property.name); + + out.beginObject(); + out.name("description").value(property.description); + out.name("type").value(property.type); + + if (property.hasMin) { + out.name("minimum").value(property.boundsMin); + if (property.exclusiveMin) { + out.name("exclusiveMinimum").value(true); + } + } + + if (property.hasMax) { + out.name("maximum").value(property.boundsMax); + if (property.exclusiveMax) { + out.name("exclusiveMaximum").value(true); + } + } + + out.endObject(); + } + out.endObject(); + } + + if (!definition.required.isEmpty()) { + out.name("required"); + out.beginArray(); + for (String required : definition.required) { + out.value(required); + } + out.endArray(); + } + + out.endObject(); + } + + @Override + public Object read(JsonReader in) throws IOException { + throw new UnsupportedOperationException("NIY"); + } + } + +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.models; + +import com.redhat.thermostat.lang.schema.annotations.Schema; +import com.redhat.thermostat.lang.schema.annotations.Type; + +import java.util.Objects; +import java.util.UUID; + +/** + * A Type that represents an identifier. + */ +@Type(description = "The representation of a ID") +public class Id { + @Schema(description = "The ID", required = true) + private String id; + + public Id() { + id = UUID.randomUUID().toString(); + } + + public Id(String id) { + this.id = Objects.requireNonNull(id); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Id other = (Id) o; + return Objects.equals(this.id, other.get()); + } + + public String get() { + return id; + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.models; + +import com.redhat.thermostat.lang.schema.annotations.Schema; +import com.redhat.thermostat.lang.schema.annotations.Type; + +/** + */ +@Type(description = "The representation of a Pid") +public class Pid { + @Schema(description = "The Pid", required = true) + private int pid; + + public Pid(int pid) { + this.pid = pid; + } + + public int get() { + return pid; + } + + @Override + public String toString() { + return Integer.toString(pid); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Pid pid1 = (Pid) o; + + return pid == pid1.pid; + } + + @Override + public int hashCode() { + return pid; + } +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.models; + +import com.redhat.thermostat.lang.schema.annotations.Type; + +/** + */ +@Type(description = "Define the basic running states for a process") +public class ProcessState { + +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.models; + +import com.redhat.thermostat.lang.schema.annotations.Minimum; +import com.redhat.thermostat.lang.schema.annotations.Schema; +import com.redhat.thermostat.lang.schema.annotations.Type; + +/** + * A Type representing the number of milliseconds elapsed since the Unix Epoch. + */ +@Type(description = "A Type representing the number of milliseconds elapsed since the Unix Epoch") +public class Timestamp { + @Schema(description = "The number of milliseconds elapsed since the Unix Epoch", required = true) + @Minimum(0) + private long timestamp; + + public Timestamp(long timestamp) { + this.timestamp = timestamp; + } + + public long get() { + return timestamp; + } + + @Override + public String toString() { + return "" + timestamp; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Timestamp)) return false; + + Timestamp timestamp1 = (Timestamp) o; + + return timestamp == timestamp1.timestamp; + } + + @Override + public int hashCode() { + return (int) (timestamp ^ (timestamp >>> 32)); + } +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,203 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.internal; + +import com.redhat.thermostat.lang.schema.annotations.Schema; +import com.redhat.thermostat.lang.schema.annotations.Type; +import com.redhat.thermostat.lang.schema.models.Timestamp; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + */ +public class JSONServiceTest { + + @Type(description = "Some Object for testing out") + public class SomeMoreComplexType { + @Schema(description = "Some Long", required = true) + private long aLong; + + @Schema(description = "Some String", required = true) + private String aString; + + public SomeMoreComplexType(long aLong, String aString) { + this.aLong = aLong; + this.aString = aString; + + } + + public long getALong() { + return aLong; + } + + public String getAString() { + return aString; + } + } + + @Type(description = "Some Object for testing out") + public class SomeMoreComplexType2 { + @Schema(description = "Some Long", required = true) + private long aLong; + + // not part of the schema, won't be serialised! + private String aString; + + public SomeMoreComplexType2(long aLong, String aString) { + this.aLong = aLong; + this.aString = aString; + + } + + public long getALong() { + return aLong; + } + + public String getAString() { + return aString; + } + } + + @Type(description = "Something more complex perhaps?") + public class CompoundType { + @Schema(description = "Some Long", required = true) + private long aLong; + + @Schema + private SomeMoreComplexType complexType; + + public CompoundType(long aLong, SomeMoreComplexType complexType) { + this.aLong = aLong; + this.complexType = complexType; + + } + + public long getALong() { + return aLong; + } + + public SomeMoreComplexType getComplexType() { + return complexType; + } + } + + @Type(description = "Something more complex perhaps?") + public class CompoundTypeMissingSchema { + @Schema(description = "Some Long", required = true) + private long aLong; + + // won't be serialised + private SomeMoreComplexType complexType; + + public CompoundTypeMissingSchema(long aLong, SomeMoreComplexType complexType) { + this.aLong = aLong; + this.complexType = complexType; + + } + + public long getALong() { + return aLong; + } + + public SomeMoreComplexType getComplexType() { + return complexType; + } + } + + @Type(description = "An extended type that should inherit its schema") + public class ExtendedType extends CompoundType { + + @Schema(description = "Some other long from derived class", required = true) + private long anotherLong; + + public ExtendedType(long aLong, long anotherLong, SomeMoreComplexType complexType) { + super(aLong, complexType); + this.anotherLong = anotherLong; + } + } + + private JSONServiceImpl service; + + @Before + public void setUp() { + service = new JSONServiceImpl(false); + } + + @Test + public void testSimpleType() { + Timestamp timestamp = new Timestamp(123456L); + assertEquals("{\"timestamp\":\"123456\"}", service.serialiase(timestamp)); + } + + @Test + public void testComplexType() { + SomeMoreComplexType type = new SomeMoreComplexType(42, "test"); + assertEquals("{\"aLong\":\"42\",\"aString\":\"test\"}", + service.serialiase(type)); + } + + @Test + public void testComplexType2() { + SomeMoreComplexType2 type = new SomeMoreComplexType2(42, "test"); + assertEquals("{\"aLong\":\"42\"}", + service.serialiase(type)); + } + + @Test + public void testCompoundType() { + CompoundType type = new CompoundType(42, new SomeMoreComplexType(10, "test")); + assertEquals("{\"aLong\":\"42\",\"complexType\":{\"aLong\":\"10\",\"aString\":\"test\"}}", + service.serialiase(type)); + } + + @Test + public void testCompoundTypeMissingSchema() { + CompoundTypeMissingSchema type = new CompoundTypeMissingSchema(42, new SomeMoreComplexType(10, "test")); + assertEquals("{\"aLong\":\"42\"}", + service.serialiase(type)); + } + + @Test + public void testExtendedType() { + ExtendedType type = new ExtendedType(50, 42, new SomeMoreComplexType(10, "test")); + assertEquals("{\"anotherLong\":\"42\",\"aLong\":\"50\",\"complexType\":{\"aLong\":\"10\",\"aString\":\"test\"}}", + service.serialiase(type)); + } +} diff -r 85d12e67675d -r 5100a9b678f4 common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,253 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.lang.schema.internal; + +import com.redhat.thermostat.lang.schema.SchemaBuilder; +import com.redhat.thermostat.lang.schema.SchemaValidationException; + +import com.redhat.thermostat.lang.schema.annotations.Maximum; +import com.redhat.thermostat.lang.schema.annotations.Minimum; +import com.redhat.thermostat.lang.schema.annotations.Schema; +import com.redhat.thermostat.lang.schema.annotations.Type; +import com.redhat.thermostat.lang.schema.models.Timestamp; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + */ +public class SchemaBuilderTest { + + @Type(description = "Some Object for testing out") + public class SomeMoreComplexType { + @Schema(description = "Some Long", required = true) + private long aLong; + + @Schema(description = "Some String", required = true) + private String aString; + + public SomeMoreComplexType(long aLong, String aString) { + this.aLong = aLong; + this.aString = aString; + + } + + public long getALong() { + return aLong; + } + + public String getAString() { + return aString; + } + } + + @Type(description = "Some Object for testing out") + public class SomeMoreComplexType2 { + @Schema(description = "Some Long", required = true) + private long aLong; + + // not part of the schema, won't be serialised! + private String aString; + + public SomeMoreComplexType2(long aLong, String aString) { + this.aLong = aLong; + this.aString = aString; + + } + + public long getALong() { + return aLong; + } + + public String getAString() { + return aString; + } + } + + @Type(description = "Something more complex perhaps?") + public class CompoundType { + @Schema(description = "Some Long", required = true) + private long aLong; + + @Schema + private SomeMoreComplexType complexType; + + public CompoundType(long aLong, SomeMoreComplexType complexType) { + this.aLong = aLong; + this.complexType = complexType; + + } + + public long getALong() { + return aLong; + } + + public SomeMoreComplexType getComplexType() { + return complexType; + } + } + + @Type(description = "Something more complex perhaps?") + public class CompoundTypeMissingSchema { + @Schema(description = "Some Long", required = true) + private long aLong; + + // won't be serialised + private SomeMoreComplexType complexType; + + public CompoundTypeMissingSchema(long aLong, SomeMoreComplexType complexType) { + this.aLong = aLong; + this.complexType = complexType; + } + + public long getALong() { + return aLong; + } + + public SomeMoreComplexType getComplexType() { + return complexType; + } + } + + @Type(description = "An extended type that should inherit its schema") + public class ExtendedType extends CompoundType { + + @Schema(description = "Some other long from derived class", required = true) + private long anotherLong; + + public ExtendedType(long aLong, long anotherLong, SomeMoreComplexType complexType) { + super(aLong, complexType); + this.anotherLong = anotherLong; + } + } + + private SchemaBuilder service; + + @Before + public void setUp() { + service = new SchemaBuilderImpl(false); + } + + @Test(expected = java.lang.IllegalArgumentException.class) + public void testNoTypeAnnotation() { + String test = "primitive type"; + service.getSchema(test.getClass()); + } + + @Test + public void testSimpleTypeSchema() { + assertEquals("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"Timestamp\",\"description\":\"A Type representing the number of milliseconds elapsed since the Unix Epoch\",\"type\":\"object\",\"properties\":{\"timestamp\":{\"description\":\"The number of milliseconds elapsed since the Unix Epoch\",\"type\":\"long\",\"minimum\":0}},\"required\":[\"timestamp\"]}", + service.getSchema(Timestamp.class)); + } + + @Test + public void testComplexTypeSchema() { + assertEquals("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"SomeMoreComplexType\",\"description\":\"Some Object for testing out\",\"type\":\"object\",\"properties\":{\"aLong\":{\"description\":\"Some Long\",\"type\":\"long\"},\"aString\":{\"description\":\"Some String\",\"type\":\"String\"}},\"required\":[\"aLong\",\"aString\"]}", + service.getSchema(SomeMoreComplexType.class)); + } + + + @Test + public void testComplexType2Schema() { + assertEquals("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"SomeMoreComplexType2\",\"description\":\"Some Object for testing out\",\"type\":\"object\",\"properties\":{\"aLong\":{\"description\":\"Some Long\",\"type\":\"long\"}},\"required\":[\"aLong\"]}", + service.getSchema(SomeMoreComplexType2.class)); + } + + @Test + public void testCompoundTypeSchema() { + assertEquals("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"CompoundType\",\"description\":\"Something more complex perhaps?\",\"type\":\"object\",\"properties\":{\"aLong\":{\"description\":\"Some Long\",\"type\":\"long\"},\"complexType\":{\"description\":\"\",\"type\":\"SomeMoreComplexType\"}},\"required\":[\"aLong\"]}", + service.getSchema(CompoundType.class)); + } + + @Test + public void testCompoundTypeMissingSchemaSchema() { + assertEquals("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"CompoundTypeMissingSchema\",\"description\":\"Something more complex perhaps?\",\"type\":\"object\",\"properties\":{\"aLong\":{\"description\":\"Some Long\",\"type\":\"long\"}},\"required\":[\"aLong\"]}", + service.getSchema(CompoundTypeMissingSchema.class)); + } + + + @Test + public void testExtendedTypeSchema() { + assertEquals("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"ExtendedType\",\"description\":\"An extended type that should inherit its schema\",\"type\":\"object\",\"extends\":\"CompoundType\",\"properties\":{\"anotherLong\":{\"description\":\"Some other long from derived class\",\"type\":\"long\"}},\"required\":[\"anotherLong\"]}", + service.getSchema(ExtendedType.class)); + } + + @Type(description = "Some Type for testing out") + public class ATypeWithConstraints { + @Schema(description = "Some Long", required = true) + @Minimum(2) + @Maximum(value = 5, exclusive = true) + private long aLong; + + public ATypeWithConstraints(long aLong) { + this.aLong = aLong; + } + + public long getALong() { + return aLong; + } + } + + @Test + public void testTypeWithConstraintsSchema() { + assertEquals("{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"title\":\"ATypeWithConstraints\",\"description\":\"Some Type for testing out\",\"type\":\"object\",\"properties\":{\"aLong\":{\"description\":\"Some Long\",\"type\":\"long\",\"minimum\":2,\"maximum\":5,\"exclusiveMaximum\":true}},\"required\":[\"aLong\"]}", + service.getSchema(ATypeWithConstraints.class)); + } + + @Type(description = "Some Type for testing out") + public class ATypeWithBadConstraints { + @Schema(description = "Some Long", required = true) + @Minimum(5) + @Maximum(value = 1, exclusive = true) + private long aLong; + + public ATypeWithBadConstraints(long aLong) { + this.aLong = aLong; + } + + public long getALong() { + return aLong; + } + } + + @Test(expected = SchemaValidationException.class) + public void testTypeWithBadConstraintsSchema() { + service.getSchema(ATypeWithBadConstraints.class); + } +} diff -r 85d12e67675d -r 5100a9b678f4 pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pom.xml Fri Sep 08 13:24:37 2017 -0400 @@ -0,0 +1,94 @@ + + + + 4.0.0 + + com.redhat.thermostat + thermostat-base + 1.99.12-SNAPSHOT + pom + + Thermostat Base + ${thermostat.url} + + + ${project.basedir} + yyyy-MM-dd + ${maven.build.timestamp} + thermostat@icedtea.classpath.org + http://icedtea.classpath.org/thermostat/ + http://icedtea.classpath.org/bugzilla/enter_bug.cgi?product=Thermostat + http://icedtea.classpath.org/wiki/Thermostat/UserGuide + UTF-8 + target + 1.7 + ${java.home} + + 4.10 + 1.9.5 + 2.6.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + 3.6.1 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + + + + + + common + + diff -r 85d12e67675d -r 5100a9b678f4 thermostat-ng.sh --- a/thermostat-ng.sh Thu Aug 31 15:20:47 2017 +0200 +++ b/thermostat-ng.sh Fri Sep 08 13:24:37 2017 -0400 @@ -193,6 +193,10 @@ mvn clean verify } +mvn_install() { + mvn clean verify install +} + npm_build() { # setup environment variables export NODE_ENV=testing @@ -225,6 +229,12 @@ fi } +build_support_libs() { + for i in "${SUPPORT_LIBS_ROOTS[@]}" + do + build "$i" mvn_install + done +} build_agent() { build "$AGENT_ROOT" mvn_build @@ -291,6 +301,7 @@ AGENT_ROOT="${TOP_DIR}/agent" WEB_CLIENT_ROOT="${TOP_DIR}/web-client" GATEWAY_URL="$(get_gateway_url)" +SUPPORT_LIBS_ROOTS="${TOP_DIR}/common" DO_BUILD=${BUILD:-true} RUN_DATA_DIR="$TOP_DIR/data" @@ -307,6 +318,7 @@ WEB_GATEWAY=true WEB_CLIENT=true AGENT=true +SUPPORT_LIBS=true HELP_STRING="\nUSAGE: $0 [BUILD_OPTION] -a @@ -325,12 +337,14 @@ WEB_GATEWAY=true WEB_CLIENT=true AGENT=true + SUPPORT_LIBS=true } mark_nothing_to_be_built() { WEB_GATEWAY=false WEB_CLIENT=false AGENT=false + SUPPORT_LIBS=false } # Check whether the component passed as the first argument of this function exists. @@ -399,6 +413,9 @@ } build_all_requested_components() { + if [ "$SUPPORT_LIBS" = "true" ]; then + build_support_libs + fi if [ "$WEB_GATEWAY" = "true" ]; then build_web_gateway; ensure_web_client_present_in_gateway fi