# HG changeset patch # User Simon Tooke # Date 1506710880 14400 # Node ID dd0992bd51aa208c769a1de0a5ec11afe79c7c7e # Parent e7a2adb465d1a12d0fa3d5c09f138b7d6bf82446 Add Maven Central upload, refactor lang-schema and json libs to thermostat-common library - merge common-json and common-lang-schema packages into thermostat- common. - add targets to generate Javadoc and source jars, and modify sources to remove some Javadoc warnings. - add targets to sign and deploy thermostat-common to Maven Central. Reviewed-by: sgehwolf, neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/025214.html diff -r e7a2adb465d1 -r dd0992bd51aa common/json/pom.xml --- a/common/json/pom.xml Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ - - - - 4.0.0 - - - com.redhat.thermostat - base-common - 1.99.12-SNAPSHOT - - - base-common-json - jar - - Thermostat Common JSON / YAML Libraries - - - - com.google.code.gson - gson - 2.6.2 - - - junit - junit - 4.12 - - - com.redhat.thermostat.lang.schema - thermostat-lang-schema - 1.99.12-SNAPSHOT - - - - \ No newline at end of file diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/json/JsonUtil.java --- a/common/json/src/main/java/com/redhat/thermostat/common/json/JsonUtil.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * 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.common.json; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import java.util.Map; -import java.util.NoSuchElementException; - -/** - * misc GSON utility classes - */ -public class JsonUtil { - - static String capitalize(final String s) { - return s.substring(0, 1).toUpperCase() + s.substring(1); - } - - /** - * access a nested JSON object via a path string - * "foo.bar.2.fred" is equivalent to - * root.getAsJsonObject().get("foo").getAsJsonObject().get("bar").getAsJsonArray().get(2).getAsJsonObject().get("fred") - * - * @param root object to access - * @param path path into object - * @return element within root - */ - public static JsonElement fetch(final JsonElement root, final String path) { - String[] pathelements = path.split("[.]"); - // NOTE - it would be nice to parse foo[N] to foo.N to allow normal subscripting - return fetch(root, pathelements, 0); - } - - /** - * access a nexted JSON object via a path string - * "foo.bar.2.fred" is equivalent to - * root.getAsJsonObject().get("foo").getAsJsonObject().get("bar").getAsJsonArray().get(2).getAsJsonObject().get("fred") - * - * @param root object to access - * @param path path into object - * @param delimiter delimiter regex for path antries (default '.') - * @return element within root - */ - public static JsonElement fetch(final JsonElement root, final String path, final String delimiter) { - String[] pathelements = path.split(delimiter); - return fetch(root, pathelements, 0); - } - - private static JsonElement fetch(final JsonElement e, final String[] pathelements, int idx) { - if (idx == pathelements.length) { - // we've fallen off the end of the input path - now it's time to return the current object. - return e; - } else if (idx > pathelements.length) { - throw new IndexOutOfBoundsException("Internal error in JsonUtil.fetch() - index = " + idx); - } else { - if (e.isJsonObject()) { - JsonObject obj = e.getAsJsonObject(); - JsonElement next = obj.get(pathelements[idx]); - if (next == null) { - throw new NoSuchElementException(pathelements[idx]); - } else { - return fetch(next, pathelements, idx + 1); - } - } else if (e.isJsonArray()) { - JsonArray arr = e.getAsJsonArray(); - int n = Integer.parseInt(pathelements[idx]); - if (arr.size() <= n) { - throw new ArrayIndexOutOfBoundsException(n); - } else { - return fetch(arr.get(n), pathelements, idx + 1); - } - } else { - throw new NoSuchElementException(pathelements[idx]); - } - } - } - - /** - * perform a deep copy of a JsonElement - * - * @param jsonElement element to copy - * @return deep copy of the element tree - */ - // why isn't JsonElement.deepCopy() public? - public static JsonElement deepCopy(JsonElement jsonElement) { - if (jsonElement.isJsonPrimitive() || jsonElement.isJsonNull()) { - return jsonElement; // these are immutables anyway - } else if (jsonElement.isJsonObject()) { - return deepCopy(jsonElement.getAsJsonObject()); - } else if (jsonElement.isJsonArray()) { - return deepCopy(jsonElement.getAsJsonArray()); - } else { - throw new UnsupportedOperationException("Unsupported element: " + jsonElement); - } - } - - private static JsonObject deepCopy(JsonObject jsonObject) { - JsonObject result = new JsonObject(); - for (Map.Entry entry : jsonObject.entrySet()) { - result.add(entry.getKey(), deepCopy(entry.getValue())); - } - return result; - } - - private static JsonArray deepCopy(JsonArray jsonArray) { - JsonArray result = new JsonArray(); - for (JsonElement e : jsonArray) { - result.add(deepCopy(e)); - } - return result; - } -} - diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/json/models/ApiDef.java --- a/common/json/src/main/java/com/redhat/thermostat/common/json/models/ApiDef.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * 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.common.json.models; - -import com.google.gson.JsonObject; -import com.google.gson.annotations.SerializedName; - -import java.util.List; -import java.util.Map; - -/** - * Java representation of a Swagger-defined web API endpoint - */ -public class ApiDef { - - String path; - String description; - JsonObject root; - List parameters; - MethodDef get; - MethodDef put; - MethodDef post; - MethodDef delete; - - public static class MethodDef { - List parameters; - String description; - Map responses; - - public String getDescription() { - return this.description; - } - } - - static class ResponseDef { - String description; - JsonObject schema; - } - - static class ParameterDef { - enum In { query, path, body }; - enum Type { integer, string, bool }; - String name; - String description; - In in; - Type type; - boolean required; - @SerializedName("default") - String deflt; - } - - public void setPath(String path) { - this.path = path; - } - - public MethodDef getGETAPI() { - return get; - } - - public MethodDef getPOSTAPI() { - return post; - } - - public MethodDef getDELETEAPI() { - return delete; - } - - public MethodDef getPUTAPI() { - return put; - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/json/models/SchemaDef.java --- a/common/json/src/main/java/com/redhat/thermostat/common/json/models/SchemaDef.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -/* - * 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.common.json.models; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.annotations.SerializedName; - -import com.redhat.thermostat.common.yaml.JsonToYaml; -import com.redhat.thermostat.lang.schema.annotations.Schema; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Partiual Java representation of a JSON Schema (see json-schema.org) - */ -public class SchemaDef implements SchemaType { - - private static final Gson gson; - private static final int DEFAULT_MAXDEPTH = 1; - - static { - final boolean ENABLE_PRETTY_PRINT = false; - if (ENABLE_PRETTY_PRINT) { - GsonBuilder gbuilder = new GsonBuilder(); - gbuilder.setPrettyPrinting(); - gson = gbuilder.create(); - } else { - gson = new Gson(); - } - } - - @SerializedName("$schema") - private String schema; - @SerializedName("$id") - private String id; - private String title; - private String description; - private Map properties; - private List required; - - /** standard JSON schema properties that are not yet implemented: - private int multipleOf; - private long maximum; - private long exclusiveMaximum; - private long minimum; - private long exclusiveMinimum; - private int maxLength; - private int minLength; - private String pattern; - private int maxItems; - private int minItems; - private boolean uniqueItems; - private int maxProperties; - private int minProperties; - (and more, see json-schema.org) - ***/ - - // for GSon - public SchemaDef() {} - - public SchemaDef(Object target) { - this(target.getClass(), DEFAULT_MAXDEPTH); - } - - public SchemaDef(Object target, int maxDepth) { - this(target.getClass(), maxDepth); - } - - public SchemaDef(Class target) { - this(target, true, DEFAULT_MAXDEPTH); - } - - public SchemaDef(Class target, int maxDepth) { - this(target, true, maxDepth); - } - - private SchemaDef(Class target, boolean rootLevel, int maxDepth) { - if (rootLevel) { - schema = "http://json-schema.org/draft-04/schema#"; - } - Field[] fields = target.getDeclaredFields(); - if (fields.length > 0) { - properties = new HashMap<>(fields.length); - required = new ArrayList<>(); - for (Field field : fields) { - final boolean isTransient = Modifier.isTransient(field.getModifiers()); - if (!isTransient) { - String fname = field.getAnnotation(SerializedName.class) != null ? field.getAnnotation(SerializedName.class).value() : field.getName(); - Schema schema = field.getAnnotation(Schema.class); - String descr = null; - if (schema != null) { - if (!schema.name().isEmpty()) { - fname = schema.name(); - } - descr = schema.description(); - if (schema.required()) { - required.add(fname); - } - } - if (field.getType().isPrimitive()) { - String tt = field.getType().getSimpleName(); - properties.put(fname, new SimpleType(tt, descr)); - } else if (maxDepth > 1){ - properties.put(fname, new SchemaDef(field.getType(), false, maxDepth - 1)); - } else { - properties.put(fname, new SimpleType(field.getType().getSimpleName(), descr)); - } - } - } - if (required.isEmpty()) { - required = null; - } - } - } - - public Map getProperties() { - return this.properties; - } - - public List getRequired() { - return this.required; - } - - public JsonObject toJsonObject() { - JsonElement el = gson.toJsonTree(this); - return el.isJsonObject() ? el.getAsJsonObject() : null; - } - - public String toString() { - return gson.toJson(this); - } - - @Override - public TypeClass getTypeClass() { - return TypeClass.OBJECT; - } - - public static class SimpleType implements SchemaType { - transient TypeClass type; - @SerializedName("type") - String typeStr; - String description; - SimpleType(String tname, String descr) { - if ("string".equals(tname)) { - type = TypeClass.STRING; - } else if ("int".equals(tname) || "float".equals(tname) || "double".equals(tname) || "long".equals(tname) || "number".equals(tname)) { - type = TypeClass.NUMBER; - } else if ("Integer".equals(tname) || "Float".equals(tname) || "Double".equals(tname) || "Long".equals(tname)) { - type = TypeClass.NUMBER; - } else if ("boolean".equals(tname) || "Boolean".equals(tname)) { - type = TypeClass.BOOLEAN; - } else { - type = TypeClass.OBJECT; - } - this.typeStr = type == TypeClass.OBJECT ? tname : type.toString(); - this.description = descr; - } - @Override - public TypeClass getTypeClass() { - return type; - } - public String getTypeName() { - return type == TypeClass.OBJECT ? typeStr : type.toString(); - } - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/json/models/SchemaType.java --- a/common/json/src/main/java/com/redhat/thermostat/common/json/models/SchemaType.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * 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.common.json.models; - -/** - * the type of a JSON schema element - */ -public interface SchemaType { - TypeClass getTypeClass(); - - enum TypeClass { - - OBJECT("object"), - ARRAY("array"), - NUMBER("number"), - STRING("string"), - BOOLEAN("boolean"), - NULL("null"); - - private final String typeString; - - private TypeClass(String s) { - typeString = s; - } - - @Override - public String toString() { - return typeString; - } - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/json/models/SwaggerDef.java --- a/common/json/src/main/java/com/redhat/thermostat/common/json/models/SwaggerDef.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * 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.common.json.models; - -import java.util.List; -import java.util.Map; - -/** - * Java representation of a Swagger file - */ -public class SwaggerDef { - - String swagger; - InfoDef info; - List consumes; - List produces; - String basePath; - Map paths; - - static class InfoDef { - String version; - String title; - LicenseDef license; - } - - static class LicenseDef { - String name; - String url; - } - - static class SwaggerSchema extends SchemaDef { - private String type; - } - - public String getBasePath() { - return basePath; - } - - public Map getPaths() { - return paths; - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/yaml/JsonToYaml.java --- a/common/json/src/main/java/com/redhat/thermostat/common/yaml/JsonToYaml.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * 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.common.yaml; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Map; - -/** - * convert JSON object to YAML string - */ -public class JsonToYaml { - - private Writer out; - private int indent = 2; - - public void setIndentation(int i) { - this.indent = i; - } - - String jsonToYamlString(JsonObject root) throws IOException { - this.out = new StringWriter(); - jsonToYaml(root, out); - return out.toString(); - } - - public void jsonToYaml(JsonObject root, Writer out) throws IOException { - this.out = out; - jsonToYaml(root, 0); - } - - private void dispatch(JsonElement el, int currentIndent) throws IOException { - if (el.isJsonPrimitive()) { - final JsonPrimitive pr = el.getAsJsonPrimitive(); - if (pr.isBoolean() || pr.isNumber()) { - out.append(el.getAsString()).append('\n'); - } else { - out.append("'").append(el.getAsString()).append("'\n"); - } - } else if (el.isJsonArray()) { - out.append('\n'); - jsonToYaml(el.getAsJsonArray(), currentIndent); - } else if (el.isJsonObject()) { - out.append('\n'); - jsonToYaml(el.getAsJsonObject(), currentIndent); - } else { - throw new UnsupportedOperationException("Unsupported element: " + el); - } - } - - private void jsonToYaml(JsonObject obj, int currentIndent) throws IOException { - final int newindent = currentIndent + indent; - for (final Map.Entry entry : obj.entrySet()) { - doIndent(currentIndent); - out.append(entry.getKey()).append(": "); - dispatch(entry.getValue(), newindent); - } - } - - private void jsonToYaml(JsonArray array, int currentIndent) throws IOException { - for (final JsonElement el : array) { - doIndent(currentIndent); - out.append("- "); - if (el.isJsonArray()) { - jsonToYaml(el.getAsJsonArray(), 0); - } else if (el.isJsonObject()) { - jsonToYaml(el.getAsJsonObject(), 0); - } else { - dispatch(el, 0); - } - } - } - - private void doIndent(int currentIndent) throws IOException { - for (int i = 0; i < currentIndent; i++) - out.append(' '); - } -} - diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/yaml/RefResolver.java --- a/common/json/src/main/java/com/redhat/thermostat/common/yaml/RefResolver.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * 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.common.yaml; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.redhat.thermostat.common.json.JsonUtil; - -import java.io.IOException; -import java.util.Map; - -/** - * Given a JSON object (created from a Swagger YAML or JSON file), resolve all $ref paths - * TODO: currently doesn't test for circular references - */ -public class RefResolver { - - public static JsonObject resolvePath(JsonObject defsroot, JsonObject current, String path) throws IOException { - String[] pathElements = path.split("/"); - for (String pe : pathElements) { - if ("#".equals(pe)) { - current = defsroot; - } else if (current.has(pe)) { - current = current.getAsJsonObject(pe); - } else { - throw new IOException("unresolvable reference '" + pe + "' in path '" + path + "'"); - } - } - return current; - } - - private static final String REF_MEMBER = "$ref"; - - public static JsonElement resolveRefs(JsonObject defsRoot, JsonElement objToResolve) throws IOException { - - if (objToResolve.isJsonObject()) { - final JsonObject obj = objToResolve.getAsJsonObject(); - for (Map.Entry entry : obj.entrySet()) { - if (REF_MEMBER.equals(entry.getKey())) { - String ref = entry.getValue().getAsString(); - obj.remove(REF_MEMBER); - JsonObject refObject = resolvePath(defsRoot, obj, ref); - resolveRefs(defsRoot, refObject); - // hoist all members of refObject to contents - for (Map.Entry refentry : refObject.entrySet()) { - obj.add(refentry.getKey(), JsonUtil.deepCopy(refentry.getValue())); - } - } else { - resolveRefs(defsRoot, entry.getValue()); - } - } - } else if (objToResolve.isJsonArray()) { - final JsonArray contents = objToResolve.getAsJsonArray(); - for (int i = 0; i < contents.size(); i++) { - JsonElement el = contents.get(i); - if (el.isJsonObject()) { - contents.set(i, resolveRefs(defsRoot, el.getAsJsonObject())); - } - } - } - return objToResolve; - } - -} \ No newline at end of file diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/main/java/com/redhat/thermostat/common/yaml/YamlToJson.java --- a/common/json/src/main/java/com/redhat/thermostat/common/yaml/YamlToJson.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,309 +0,0 @@ -/* - * 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.common.yaml; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Stack; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Utility class to read YAML files and convert to GSON objects - * - * Limitations: - * Only enough code to read Swagger YAML is implemented - * $ref only works within the same document, not across the network - */ -public class YamlToJson { - - public YamlToJson() { - } - - public JsonObject yamlToJsonObject(final File fn) throws IOException { - try (final Reader in = new FileReader(fn)) { - return yamlToJsonObject(in); - } - } - - public JsonObject yamlToJsonObject(final String yaml) throws IOException { - try (final Reader in = new StringReader(yaml)) { - return yamlToJsonObject(in); - } - } - - public JsonObject yamlToJsonObject(final Reader in) throws IOException { - try (final PushableReader pr = new PushableReader(in instanceof BufferedReader ? (BufferedReader)in : new BufferedReader(in));) { - final JsonObject obj = new JsonObject(); - yamlToJson(pr, obj, 0); - pr.close(); - return obj; - } - } - - private void yamlToJson(PushableReader in, JsonElement parent, int currentIndent) throws IOException { - for (String s = in.readLine(); s != null; s = in.readLine()) { - YamlLine line = new YamlLine(s); - if (line.indent == 0 && line.value == null && line.name == null) { - // blsnk or unparseable line - continue; - } - if (line.indent < currentIndent) { - in.push(s); - return; - } - final JsonElement child; - if (line.hasColon) { - if (line.value != null && !line.value.isEmpty()) { - if (">-".equals(line.value)) { - //the next few lines are the value for the current line - child = makeUnquotedPrimitive(absorb(in, currentIndent)); - } else { - JsonElement ce = makeUnquotedPrimitive(line.value); - if (parent.isJsonArray()) { - JsonObject childobj = new JsonObject(); - childobj.add(makeUnquotedString(line.name), ce); - child = childobj; - } else { - child = ce; - } - } - } else { - // no value specified; this could be the start of an object or array - final String next = in.readLine(); - boolean isArray = false; - if (next != null) { - YamlLine nextLine = new YamlLine(next); - isArray = nextLine.hasDashPrefix; - in.push(next); - } - child = isArray ? new JsonArray() : new JsonObject(); - yamlToJson(in, child, line.indent); - } - } - else { - child = (line.value != null) ? makeUnquotedPrimitive(line.value) : new JsonPrimitive(""); - } - if (parent.isJsonArray()) { - if (line.hasDashPrefix) { - JsonArray parray = parent.getAsJsonArray(); - parray.add(child); - } else { - System.err.println("Array member must begin with dash: " + s); - } - } else if (parent.isJsonObject()) { - JsonObject pobject = parent.getAsJsonObject(); - pobject.add(makeUnquotedString(line.name), child); - } else { - System.err.println("Error: parent is neither object nor array"); - } - currentIndent = line.indent; - } - } - - private static String makeUnquotedString(final String s) { - String ret = s; - if (s.length() >= 2) { - if ((s.charAt(0) == '\'') && (s.charAt(s.length() - 1) == '\'') - || (s.charAt(0) == '"') && (s.charAt(s.length() - 1) == '"')) { - ret = s.substring(1, s.length() - 1); - } - } - return ret; - } - - private static JsonPrimitive makeUnquotedPrimitive(final String s) { - final String uqString = makeUnquotedString(s); - // anything quoted will return a string, otherwise try to parse - if (uqString.length() == s.length()) { - if ("true".equals(uqString)) - return new JsonPrimitive(true); - else if ("false".equals(uqString)) - return new JsonPrimitive(false); - else if ("null".equals(uqString)) - return null; - else { - // test for number - final char c0 = uqString.charAt(0); - if (Character.isDigit(c0) || c0 == '+' || c0 == '-') { - try { - return new JsonPrimitive(new Long(uqString)); - } catch (NumberFormatException ignored) { - ; // fall through to return String - } - - } - } - } - return new JsonPrimitive(uqString); - } - - private static String absorb(PushableReader in, int currentIndent) throws IOException { - // append lines until the indentation is the same as the currentIndent - StringBuilder a = new StringBuilder(); - for (String s = in.readLine(); s != null; s = in.readLine()) { - int wsCount; - for (wsCount = 0; wsCount < s.length(); wsCount++) { - if (!Character.isWhitespace(s.charAt(wsCount))) { - break; - } - } - if (wsCount > currentIndent) { - a.append(a.length() == 0 ? s.trim() : ' ' + s.trim()); - } else { - in.push(s); - break; - } - } - return a.toString(); - } - - /** - * YamlLine - parse a single line of YAML file - */ - static class YamlLine { - int indent; - String name; - String value; - boolean hasColon; - boolean hasDashPrefix; - - private static final String regexpr = "^([\\s]*)([-]?[\\s]*)([^:]+)([:]?)(.*)$"; - private static final Pattern p = Pattern.compile(regexpr); - - YamlLine(String line) throws IOException { - Matcher m = p.matcher(line); - if (m.matches()) { - final String s1 = m.group(1); // leading whitespace - final String s2 = m.group(2); // optional '-' indicating array element - final String s3 = m.group(3); // key - final String s4 = m.group(4); // ':' - final String s5 = m.group(5).trim(); // value or optional '>-' - hasColon = !(s4 == null || s4.isEmpty()); - hasDashPrefix = !(s2 == null || s2.isEmpty()); - indent = s1.length() + (hasDashPrefix ? s2.length() : 0); - if (hasColon) { - name = s3.trim(); - value = s5.trim(); - } else { - name = null; - value = s3 + s5; - value = value.trim(); - } - } else { - if (line.isEmpty()) { - name = null; - value = null; - indent = 0; - } else { - throw new IOException("parse error in YAML '" + line + "'"); - } - } - } - } - - static class PushableReader implements AutoCloseable { - - final Stack stack = new Stack<>(); - final BufferedReader in; - - PushableReader(BufferedReader in) { - this.in = in; - } - - String readLine() throws IOException { - if (stack.isEmpty()) { - return in.readLine(); - } else { - return stack.pop(); - } - } - - void push(String s) { - stack.push(s); - } - - @Override - public void close() throws IOException { - in.close(); - } - } - - /* - * utility function to convert YAML file to JSON stdout - */ - public static void main(String[] args) { - boolean pretty = false; - for (final String fn : args) { - if ("--pretty".equals(fn)) { - pretty = true; - } else if ("--help".equals("fn")) { - System.err.println("YamlToJason [--pretty] [--help] infile1 [infile2] ..."); - } else { - try { - final YamlToJson y2j = new YamlToJson(); - final File fin = new File(fn); - final JsonObject json = y2j.yamlToJsonObject(fin); - if (pretty) { - final GsonBuilder gsonBuilder = new GsonBuilder(); - gsonBuilder.setPrettyPrinting(); - final Gson gson = gsonBuilder.create(); - System.out.println(gson.toJson(json)); - } else { - System.out.println(json.toString()); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/java/com/redhat/thermostat/common/json/JsonUtilTest.java --- a/common/json/src/test/java/com/redhat/thermostat/common/json/JsonUtilTest.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - * 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.common.json; - -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import org.junit.Test; - -import java.util.NoSuchElementException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -public class JsonUtilTest { - - private static final String JSON = - "{\n" + - " \"parents\" : [ \"homer\", \"marge\" ],\n" + - " \"children\" : {\n" + - " \"bart\" : {\n" + - " \"title\" : \"son\",\n" + - " \"age\" : \"14\"\n" + - " },\n" + - " \"lisa\" : {\n" + - " \"title\" : \"daughter\",\n" + - " \"age\" : \"12\"\n" + - " },\n" + - " \"maggie\" : {\n" + - " \"title\" : \"daughter\",\n" + - " \"age\" : \"1\"\n" + - " }\n" + - " \n" + - " },\n" + - " \"surname\" : \"simpsons\"\n" + - "}\n"; - - @Test - public void testCapitalize() { - assertEquals("Fred", JsonUtil.capitalize("Fred")); - assertEquals("Barney", JsonUtil.capitalize("barney")); - } - - @Test - public void testDeepCopy() { - final JsonParser parser = new JsonParser(); - final JsonElement j0 = parser.parse(JSON); - final JsonElement j1 = JsonUtil.deepCopy(j0); - assertEquals(j0, j1); - - j1.getAsJsonObject().get("children").getAsJsonObject().get("bart").getAsJsonObject().addProperty("age", 99); - assertNotEquals(j0, j1); - } - - @Test - public void testFetchObject() { - final JsonParser parser = new JsonParser(); - final JsonElement j0 = parser.parse(JSON); - final JsonElement bartAge = JsonUtil.fetch(j0, "children.bart.age"); - assertEquals(14, bartAge.getAsInt()); - } - - @Test(expected = NoSuchElementException.class) - public void testFetchTooMuch() { - final JsonParser parser = new JsonParser(); - final JsonElement j0 = parser.parse(JSON); - JsonUtil.fetch(j0, "children.bart.age.overflow"); - } - - @Test(expected = NoSuchElementException.class) - public void testFetchTooLittle() { - final JsonParser parser = new JsonParser(); - final JsonElement j0 = parser.parse(JSON); - JsonUtil.fetch(j0, ""); - } - - @Test - public void testFetchArray() { - final JsonParser parser = new JsonParser(); - final JsonElement j0 = parser.parse(JSON); - final JsonElement homer = JsonUtil.fetch(j0, "parents.0"); - assertEquals("homer", homer.getAsString()); - final JsonElement marge = JsonUtil.fetch(j0, "parents.1"); - assertEquals("marge", marge.getAsString()); - } - - //@Test - // disable until this syntax feature is implemented - public void testFetchArraySquareBrackets() { - final JsonParser parser = new JsonParser(); - final JsonElement j0 = parser.parse(JSON); - final JsonElement homer = JsonUtil.fetch(j0, "parents[0]"); - assertEquals("homer", homer.getAsString()); - final JsonElement marge = JsonUtil.fetch(j0, "parents[1]"); - assertEquals("marge", marge.getAsString()); - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/java/com/redhat/thermostat/common/json/models/SchemaDefTest.java --- a/common/json/src/test/java/com/redhat/thermostat/common/json/models/SchemaDefTest.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * 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.common.json.models; - -import com.redhat.thermostat.common.yaml.JsonToYaml; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class SchemaDefTest { - - @Test - public void testShallowFunctionality() { - final SchemaDef def = new SchemaDef(JsonToYaml.class); - assertTrue(def.getProperties().get("out") instanceof SchemaDef.SimpleType); - final SchemaDef.SimpleType typeOfOut = (SchemaDef.SimpleType)def.getProperties().get("out"); - assertEquals(SchemaType.TypeClass.OBJECT, typeOfOut.getTypeClass()); - assertEquals("Writer", typeOfOut.getTypeName()); - } - - @Test - public void testDeepFunctionality() { - SchemaDef def = new SchemaDef(JsonToYaml.class, 99); - assertTrue(def.getProperties().get("out") instanceof SchemaDef); - final SchemaDef typeOfOut = (SchemaDef)def.getProperties().get("out"); - assertEquals(SchemaType.TypeClass.OBJECT, typeOfOut.getTypeClass()); - assertFalse(typeOfOut.getProperties().isEmpty()); - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/java/com/redhat/thermostat/common/yaml/JsonToYamlTest.java --- a/common/json/src/test/java/com/redhat/thermostat/common/yaml/JsonToYamlTest.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * 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.common.yaml; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import org.junit.Test; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; - - -import static org.junit.Assert.assertEquals; - -public class JsonToYamlTest { - - private static final File API1_YAML_FILE = new File("./src/test/resources/systems-swagger.yaml"); - private static final File API1_JSON_FILE = new File("./src/test/resources/systems-swagger.json"); - - @Test - public void testConvert() throws IOException { - - // read source JSON file - JsonObject goodjson = readFileToJson(API1_JSON_FILE).getAsJsonObject(); - - final JsonToYaml j2y = new JsonToYaml(); - - // convert to YAML string - final String yamlStr = j2y.jsonToYamlString(goodjson); - - // get a temp file name - final File tmpFile = mktempfile("JsonToYamlTest.testConvert", ".yaml"); - - // write a new YAML file - writeFile(tmpFile, yamlStr); - - // read the known good YAML file - final YamlToJson y2j = new YamlToJson(); - final JsonObject goodyaml = y2j.yamlToJsonObject(API1_YAML_FILE); - assertEquals(goodjson, goodyaml); - - // read the new YAML file - final JsonObject testyaml = y2j.yamlToJsonObject(tmpFile); - assertEquals(goodjson, testyaml); - } - - private File mktempfile(final String prefix, final String suffix) throws IOException { - final File f = File.createTempFile(prefix, suffix); - f.deleteOnExit(); - return f; - } - - private JsonElement readFileToJson(File f) throws IOException { - try (final Reader in = new BufferedReader(new FileReader(f))) { - final JsonParser parser = new JsonParser(); - return parser.parse(in); - } catch (IOException e) { - throw e; - } - } - - private void writeFile(File f, String contents) throws IOException { - try (final Writer out = new BufferedWriter(new FileWriter(f))) { - out.write(contents); - out.close(); - } catch (IOException e) { - throw e; - } - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/java/com/redhat/thermostat/common/yaml/RefResolverTest.java --- a/common/json/src/test/java/com/redhat/thermostat/common/yaml/RefResolverTest.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * 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.common.yaml; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.redhat.thermostat.common.json.JsonUtil; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class RefResolverTest { - - private static final File API1_YAML_FILE = new File("./src/test/resources/systems-swagger.yaml"); - - @Test - public void resolverTest() throws IOException { - YamlToJson y2j = new YamlToJson(); - JsonObject yaml = y2j.yamlToJsonObject(API1_YAML_FILE); - assertNotNull(yaml); - - JsonElement getRefType = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.responses.200.schema.$ref"); - assertTrue(getRefType.getAsString().endsWith("definitions/systems-get-response")); - - // ref1 is the defintion pointed to by the reference - JsonElement ref1 = JsonUtil.fetch(yaml, "definitions.systems-get-response"); - - // resolve all refs - RefResolver.resolveRefs(yaml, yaml); - - // get the response type, which should no longer be a reference but a copy of the definition pointed to by the reference - JsonElement resolvedType = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.responses.200.schema"); - assertEquals(ref1, resolvedType); - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/java/com/redhat/thermostat/common/yaml/YamlToJsonTest.java --- a/common/json/src/test/java/com/redhat/thermostat/common/yaml/YamlToJsonTest.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * 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.common.yaml; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.redhat.thermostat.common.json.JsonUtil; -import com.redhat.thermostat.common.json.models.SwaggerDef; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class YamlToJsonTest { - - private static final File API1_YAML_FILE = new File("./src/test/resources/systems-swagger.yaml"); - - @Test - public void readYamlTest() throws IOException { - YamlToJson y2j = new YamlToJson(); - JsonObject yaml = y2j.yamlToJsonObject(API1_YAML_FILE); - assertNotNull(yaml); - JsonElement getDescr = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.description"); - assertNotNull(getDescr); - assertTrue(getDescr.isJsonPrimitive()); - assertEquals("Get information for system {systemId}.", getDescr.getAsString()); - } - - @Test - public void yamlToModelTest() throws IOException { - YamlToJson y2j = new YamlToJson(); - JsonObject yaml = y2j.yamlToJsonObject(API1_YAML_FILE); - assertNotNull(yaml); - - // resolve all refs - RefResolver.resolveRefs(yaml, yaml); - - // convert JSON to actual Java class - Gson gson = new Gson(); - SwaggerDef swaggerDef = gson.fromJson(yaml, SwaggerDef.class); - - final String getdescr = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.description").getAsString(); - assertEquals(getdescr, swaggerDef.getPaths().get("/systems/{systemId}").getGETAPI().getDescription()); - } - - private static final String GPL = "GPL v2 with Classpath Exception"; - - private static final String YAML_WITH_NULL = - "info:\n" + - " title: Thermostat Web Gateway JVM Information API\n" + - " license:\n" + - " name: " + GPL + "\n" + - " url: 'http://www.gnu.org/licenses'\n" + - " org: null\n" + - " phone: 416-363-6097\n" + - "consumes:\n" + - " - application/json\n" + - "produces:\n" + - " - application/json\n" + - " - text/html; charset=utf-8\n" + - "basePath: /jvms/0.0.1\n"; - - @Test - public void testNull() throws IOException { - YamlToJson y2j = new YamlToJson(); - JsonObject yaml = y2j.yamlToJsonObject(YAML_WITH_NULL); - assertEquals(GPL, JsonUtil.fetch(yaml, "info.license.name").getAsString()); - final JsonElement nell = JsonUtil.fetch(yaml, "info.license.org"); - assertTrue(nell.isJsonNull()); - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/resources/jvms-swagger.json --- a/common/json/src/test/resources/jvms-swagger.json Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,480 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "0.0.1", - "title": "Thermostat Web Gateway JVM Information API", - "license": { - "name": "GPL v2 with Classpath Exception", - "url": "http://www.gnu.org/licenses" - } - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json", - "text/html; charset=utf-8" - ], - "basePath": "/jvms/0.0.1", - "paths": { - "/systems/{systemId}": { - "parameters": [ - { - "$ref": "#/parameters/system-id" - } - ], - "get": { - "description": "Get jvms for system {systemId}", - "parameters": [ - { - "$ref": "#/parameters/limit" - }, - { - "$ref": "#/parameters/offset" - }, - { - "$ref": "#/parameters/sort" - }, - { - "$ref": "#/parameters/include" - }, - { - "$ref": "#/parameters/exclude" - }, - { - "$ref": "#/parameters/query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/jvms-get-response" - } - } - } - }, - "post": { - "description": "Add jvms for system {systemId}", - "parameters": [ - { - "$ref": "#/parameters/jvms-post-body" - } - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "delete": { - "description": "Delete all jvms on system {systemId}", - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/systems/{systemId}/jvms/{jvmId}": { - "parameters": [ - { - "$ref": "#/parameters/system-id" - }, - { - "$ref": "#/parameters/jvm-id" - } - ], - "get": { - "description": "Get information for the JVM with id {jvmId} running on system {systemId}", - "parameters": [ - { - "$ref": "#/parameters/include" - }, - { - "$ref": "#/parameters/exclude" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/jvms-get-response" - } - } - } - }, - "put": { - "description": "Update the JVM with id {jvmId} running on system {systemId}", - "responses": { - "200": { - "description": "OK" - } - }, - "parameters": [ - { - "$ref": "#/parameters/jvms-put-body" - } - ] - }, - "delete": { - "description": "Delete the JVM with id {jvmId} running on system {systemId}", - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/tree": { - "get": { - "description": "Get jvm information organized by systemId", - "parameters": [ - { - "$ref": "#/parameters/alive-only" - }, - { - "$ref": "#/parameters/include" - }, - { - "$ref": "#/parameters/exclude" - }, - { - "$ref": "#/parameters/limit" - }, - { - "$ref": "#/parameters/offset" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/tree-get-response" - } - } - } - } - }, - "/update/systems/{systemId}/ts/{timeStamp}": { - "parameters": [ - { - "$ref": "#/parameters/system-id" - }, - { - "$ref": "#/parameters/timestamp" - } - ], - "put": { - "description": "Set last updated to {timeStamp} for jvm information on system {systemId}", - "parameters": [ - { - "$ref": "#/parameters/update-put-body" - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - } - }, - "definitions": { - "jvm-get-info": { - "type": "object", - "properties": { - "systemId": { - "type": "string" - }, - "agentId": { - "type": "string" - }, - "jvmId": { - "type": "string" - }, - "mainClass": { - "type": "string" - }, - "startTime": { - "$ref": "#/definitions/metric" - }, - "stopTime": { - "$ref": "#/definitions/metric" - }, - "jvmPid": { - "type": "integer" - }, - "javaVersion": { - "type": "string" - }, - "javaHome": { - "type": "string" - }, - "javaCommandLine": { - "type": "string" - }, - "jvmArguments": { - "type": "string" - }, - "jvmName": { - "type": "string" - }, - "jvmInfo": { - "type": "string" - }, - "jvmVersion": { - "type": "string" - }, - "classpath": { - "type": "string" - }, - "environment": { - "type": "array", - "items": { - "$ref": "#/definitions/environment-items" - } - }, - "uid": { - "$ref": "#/definitions/metric" - }, - "username": { - "type": "string" - }, - "lastUpdated": { - "$ref": "#/definitions/metric" - } - } - }, - "jvm-post-info": { - "type": "object", - "properties": { - "agentId": { - "type": "string" - }, - "jvmId": { - "type": "string" - }, - "mainClass": { - "type": "string" - }, - "startTime": { - "$ref": "#/definitions/metric" - }, - "stopTime": { - "$ref": "#/definitions/metric" - }, - "jvmPid": { - "type": "integer" - }, - "javaVersion": { - "type": "string" - }, - "javaHome": { - "type": "string" - }, - "javaCommandLine": { - "type": "string" - }, - "jvmArguments": { - "type": "string" - }, - "jvmName": { - "type": "string" - }, - "jvmInfo": { - "type": "string" - }, - "jvmVersion": { - "type": "string" - }, - "classpath": { - "type": "string" - }, - "environment": { - "type": "array", - "items": { - "$ref": "#/definitions/environment-items" - } - }, - "uid": { - "$ref": "#/definitions/metric" - }, - "username": { - "type": "string" - }, - "lastUpdated": { - "$ref": "#/definitions/metric" - } - } - }, - "environment-items": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "metric": { - "type": "object", - "properties": { - "$numberLong": { - "type": "string" - } - } - }, - "jvms-get-response": { - "type": "object", - "properties": { - "response": { - "type": "array", - "items": { - "$ref": "#/definitions/jvm-get-info" - } - } - } - }, - "jvms-put-body": { - "type": "object", - "properties": { - "set": { - "type": "object" - } - } - }, - "jvms-post-body": { - "type": "array", - "items": { - "$ref": "#/definitions/jvm-post-info" - } - }, - "update-put-body": { - "type": "array", - "description": "An array of jvm ID strings", - "items": { - "type": "string" - } - }, - "tree-get-response": { - "type": "object", - "properties": { - "systemId": { - "type": "string" - }, - "jvms": { - "type": "array", - "items": { - "$ref": "#/definitions/jvm-get-info" - } - } - } - } - }, - "parameters": { - "system-id": { - "name": "systemId", - "in": "path", - "required": true, - "type": "string", - "description": "The system ID for the jvms" - }, - "jvm-id": { - "name": "jvmId", - "in": "path", - "required": true, - "type": "string", - "description": "The ID of the jvm" - }, - "timestamp": { - "name": "timeStamp", - "in": "path", - "required": true, - "type": "integer", - "format": "int64", - "description": "The UNIX timestamp in milliseconds to set the last_updated field for." - }, - "jvms-post-body": { - "name": "body", - "in": "body", - "description": "The jvm information", - "required": true, - "schema": { - "$ref": "#/definitions/jvms-post-body" - } - }, - "jvms-put-body": { - "name": "body", - "in": "body", - "description": "The JSON object containing a 'set' object. This contains single item JSON objects that specify the field to replace and the JSON value to replace with. Must not include 'systemId' or 'jvmId' fields. Example { \"set\" : { \"field\" : \"value\", \"field2\":{\"object\":\"item\"} }", - "required": true, - "schema": { - "$ref": "#/definitions/jvms-put-body" - } - }, - "update-put-body": { - "name": "body", - "in": "body", - "description": "An array of jvmIds for which to update the last_updated field.", - "required": true, - "schema": { - "$ref": "#/definitions/update-put-body" - } - }, - "limit": { - "name": "limit", - "in": "query", - "description": "Limit of items to return. Example '1'", - "type": "integer", - "required": false, - "default": 1 - }, - "offset": { - "name": "offset", - "in": "query", - "description": "Offset of items to return. Example '0'", - "type": "integer", - "required": false, - "default": 0 - }, - "sort": { - "name": "sort", - "in": "query", - "description": "Sort string. Comma separated list of fields prefixed with '+' for ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", - "type": "string", - "required": false - }, - "query": { - "name": "query", - "in": "query", - "description": "Query string. Comma separated list of key, comparator, value pairs. Comparator supports '==', '<=', '>=', '<', '>', '!='. Example '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", - "type": "string", - "required": false - }, - "include": { - "name": "include", - "in": "query", - "description": "Inclusion string. Comma separated list of fields to include in the response. Example '?include=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'exclude' parameter Overriden by 'exclude' parameter", - "type": "string", - "required": false - }, - "exclude": { - "name": "exclude", - "in": "query", - "description": "Exclusion string. Comma separated list of fields to exclude in the response. Example '?exclude=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'include' parameter; takes precedence over 'include' parameter", - "type": "string", - "required": false - }, - "alive-only": { - "name": "aliveOnly", - "in": "query", - "description": "Whether or not to return only JVMs that are live", - "type": "boolean", - "default": true, - "required": false - } - } -} \ No newline at end of file diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/resources/jvms-swagger.yaml --- a/common/json/src/test/resources/jvms-swagger.yaml Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -swagger: '2.0' -info: - version: 0.0.1 - title: Thermostat Web Gateway JVM Information API - license: - name: GPL v2 with Classpath Exception - url: 'http://www.gnu.org/licenses' -consumes: - - application/json -produces: - - application/json - - text/html; charset=utf-8 -basePath: /jvms/0.0.1 -paths: - '/systems/{systemId}': - parameters: - - $ref: '#/parameters/system-id' - get: - description: 'Get jvms for system {systemId}' - parameters: - - $ref: '#/parameters/limit' - - $ref: '#/parameters/offset' - - $ref: '#/parameters/sort' - - $ref: '#/parameters/include' - - $ref: '#/parameters/exclude' - - $ref: '#/parameters/query' - responses: - '200': - description: OK - schema: - $ref: '#/definitions/jvms-get-response' - post: - description: 'Add jvms for system {systemId}' - parameters: - - $ref: '#/parameters/jvms-post-body' - responses: - '200': - description: OK - delete: - description: 'Delete all jvms on system {systemId}' - responses: - '200': - description: OK - '/systems/{systemId}/jvms/{jvmId}': - parameters: - - $ref: '#/parameters/system-id' - - $ref: '#/parameters/jvm-id' - get: - description: 'Get information for the JVM with id {jvmId} running on system {systemId}' - parameters: - - $ref: '#/parameters/include' - - $ref: '#/parameters/exclude' - responses: - '200': - description: OK - schema: - $ref: '#/definitions/jvms-get-response' - put: - description: 'Update the JVM with id {jvmId} running on system {systemId}' - responses: - '200': - description: OK - parameters: - - $ref: "#/parameters/jvms-put-body" - delete: - description: 'Delete the JVM with id {jvmId} running on system {systemId}' - responses: - '200': - description: OK - '/tree': - get: - description: Get jvm information organized by systemId - parameters: - - $ref: '#/parameters/alive-only' - - $ref: '#/parameters/include' - - $ref: '#/parameters/exclude' - - $ref: '#/parameters/limit' - - $ref: '#/parameters/offset' - responses: - '200': - description: OK - schema: - $ref: '#/definitions/tree-get-response' - '/update/systems/{systemId}/ts/{timeStamp}': - parameters: - - $ref: '#/parameters/system-id' - - $ref: '#/parameters/timestamp' - put: - description: 'Set last updated to {timeStamp} for jvm information on system {systemId}' - parameters: - - $ref: "#/parameters/update-put-body" - responses: - '200': - description: OK - -definitions: - jvm-get-info: - type: object - properties: - systemId: - type: string - agentId: - type: string - jvmId: - type: string - mainClass: - type: string - startTime: - $ref: '#/definitions/metric' - stopTime: - $ref: '#/definitions/metric' - jvmPid: - type: integer - javaVersion: - type: string - javaHome: - type: string - javaCommandLine: - type: string - jvmArguments: - type: string - jvmName: - type: string - jvmInfo: - type: string - jvmVersion: - type: string - classpath: - type: string - environment: - type: array - items: - $ref: '#/definitions/environment-items' - uid: - $ref: '#/definitions/metric' - username: - type: string - lastUpdated: - $ref: '#/definitions/metric' - - jvm-post-info: - type: object - properties: - agentId: - type: string - jvmId: - type: string - mainClass: - type: string - startTime: - $ref: '#/definitions/metric' - stopTime: - $ref: '#/definitions/metric' - jvmPid: - type: integer - javaVersion: - type: string - javaHome: - type: string - javaCommandLine: - type: string - jvmArguments: - type: string - jvmName: - type: string - jvmInfo: - type: string - jvmVersion: - type: string - classpath: - type: string - environment: - type: array - items: - $ref: '#/definitions/environment-items' - uid: - $ref: '#/definitions/metric' - username: - type: string - lastUpdated: - $ref: '#/definitions/metric' - environment-items: - type: object - properties: - key: - type: string - value: - type: string - - metric: - type: object - properties: - $numberLong: - type: string - - jvms-get-response: - type: object - properties: - response: - type: array - items: - $ref: '#/definitions/jvm-get-info' - jvms-put-body: - type: object - properties: - set: - type: object - jvms-post-body: - type: array - items: - $ref: '#/definitions/jvm-post-info' - - update-put-body: - type: array - description: 'An array of jvm ID strings' - items: - type: string - - tree-get-response: - type: object - properties: - systemId: - type: string - jvms: - type: array - items: - $ref: '#/definitions/jvm-get-info' -parameters: - system-id: - name: systemId - in: path - required: true - type: string - description: The system ID for the jvms - jvm-id: - name: jvmId - in: path - required: true - type: string - description: The ID of the jvm - timestamp: - name: timeStamp - in: path - required: true - type: integer - format: int64 - description: The UNIX timestamp in milliseconds to set the last_updated field for. - jvms-post-body: - name: body - in: body - description: The jvm information - required: true - schema: - $ref: '#/definitions/jvms-post-body' - jvms-put-body: - name: body - in: body - description: >- - The JSON object containing a 'set' object. This contains single item JSON - objects that specify the field to replace and the JSON value to replace with. - Must not include 'systemId' or 'jvmId' fields. Example { "set" : { - "field" : "value", "field2":{"object":"item"} } - required: true - schema: - $ref: '#/definitions/jvms-put-body' - update-put-body: - name: body - in: body - description: >- - An array of jvmIds for which to update the last_updated field. - required: true - schema: - $ref: '#/definitions/update-put-body' - limit: - name: limit - in: query - description: Limit of items to return. Example '1' - type: integer - required: false - default: 1 - offset: - name: offset - in: query - description: Offset of items to return. Example '0' - type: integer - required: false - default: 0 - sort: - name: sort - in: query - description: >- - Sort string. Comma separated list of fields prefixed with '+' for - ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot - notation for embedded documents. Example 'outer.inner' refers to field - inner contained in field outer. - type: string - required: false - query: - name: query - in: query - description: >- - Query string. Comma separated list of key, comparator, value pairs. - Comparator supports '==', '<=', '>=', '<', '>', '!='. Example - '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for - embedded documents. Example 'outer.inner' refers to field inner contained - in field outer. - type: string - required: false - include: - name: include - in: query - description: >- - Inclusion string. Comma separated list of fields to include in the - response. Example '?include=a,b' Fields use dot notation for embedded - documents. Example 'outer.inner' refers to field inner contained in field - outer. Cannot be used in combination with 'exclude' parameter Overriden by - 'exclude' parameter - type: string - required: false - exclude: - name: exclude - in: query - description: >- - Exclusion string. Comma separated list of fields to exclude in the - response. Example '?exclude=a,b' Fields use dot notation for embedded - documents. Example 'outer.inner' refers to field inner contained in field - outer. Cannot be used in combination with 'include' parameter; takes - precedence over 'include' parameter - type: string - required: false - alive-only: - name: aliveOnly - in: query - description: Whether or not to return only JVMs that are live - type: boolean - default: true - required: false \ No newline at end of file diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/resources/systems-swagger.json --- a/common/json/src/test/resources/systems-swagger.json Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,283 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "version": "0.0.1", - "title": "Thermostat Web Gateway System Information API", - "license": { - "name": "GPL v2 with Classpath Exception", - "url": "http://www.gnu.org/licenses" - } - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json", - "text/html; charset=utf-8" - ], - "basePath": "/systems/0.0.1", - "paths": { - "/": { - "get": { - "description": "Get information for all systems.", - "parameters": [ - { - "$ref": "#/parameters/limit" - }, - { - "$ref": "#/parameters/offset" - }, - { - "$ref": "#/parameters/sort" - }, - { - "$ref": "#/parameters/include" - }, - { - "$ref": "#/parameters/exclude" - }, - { - "$ref": "#/parameters/query" - }, - { - "$ref": "#/parameters/alive" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/systems-get-response" - } - } - } - } - }, - "/systems/{systemId}": { - "parameters": [ - { - "$ref": "#/parameters/system-id" - } - ], - "get": { - "description": "Get information for system {systemId}.", - "parameters": [ - { - "$ref": "#/parameters/limit" - }, - { - "$ref": "#/parameters/offset" - }, - { - "$ref": "#/parameters/sort" - }, - { - "$ref": "#/parameters/include" - }, - { - "$ref": "#/parameters/exclude" - }, - { - "$ref": "#/parameters/query" - }, - { - "$ref": "#/parameters/alive" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/systems-get-response" - } - } - } - }, - "put": { - "description": "Update information for system {systemId}.", - "parameters": [ - { - "$ref": "#/parameters/systems-put-body" - }, - { - "$ref": "#/parameters/query" - } - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "post": { - "description": "Add information for system {systemId}", - "parameters": [ - { - "$ref": "#/parameters/system-info-array" - } - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "delete": { - "description": "Delete information for system ID {systemId}.", - "parameters": [ - { - "$ref": "#/parameters/query" - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - } - }, - "definitions": { - "systems-get-response": { - "type": "object", - "properties": { - "response": { - "$ref": "#/definitions/system-info-array" - } - } - }, - "system-info-array": { - "type": "array", - "items": { - "$ref": "#/definitions/system-info" - } - }, - "system-info": { - "type": "object", - "properties": { - "systemId": { - "type": "string" - }, - "agentId": { - "type": "string" - }, - "hostname": { - "type": "string" - }, - "osName": { - "type": "string" - }, - "osKernel": { - "type": "string" - }, - "osArch": { - "type": "string" - }, - "cpuCount": { - "type": "integer" - }, - "cpuModel": { - "type": "string" - }, - "totalMemory": { - "type": "integer", - "format": "int64" - }, - "timeCreated": { - "type": "integer", - "format": "int64" - }, - "lastUpdated": { - "type": "integer", - "format": "int64" - } - } - }, - "systems-put-body": { - "type": "object", - "properties": { - "set": { - "type": "object" - } - } - } - }, - "parameters": { - "system-id": { - "name": "systemId", - "in": "path", - "required": true, - "type": "string" - }, - "system-info-array": { - "name": "system-info-array", - "in": "body", - "description": "The system information", - "required": true, - "schema": { - "$ref": "#/definitions/system-info-array" - } - }, - "systems-put-body": { - "name": "body", - "in": "body", - "description": "The JSON object containing a 'set' object. This contains single item JSON objects that specify the field to replace and the JSON value to replace with. Must not include 'systemId' field. Example { \"set\" : { \"field\" : \"value\", \"field2\":{\"object\":\"item\"} }", - "required": true, - "schema": { - "$ref": "#/definitions/systems-put-body" - } - }, - "alive": { - "name": "alive", - "in": "query", - "description": "Whether to return only systems that are currently running", - "type": "boolean", - "required": false, - "default": true - }, - "limit": { - "name": "limit", - "in": "query", - "description": "Limit of items to return. Example '1'", - "type": "integer", - "required": false, - "default": 1 - }, - "offset": { - "name": "offset", - "in": "query", - "description": "Offset of items to return. Example '0'", - "type": "integer", - "required": true, - "default": 0 - }, - "sort": { - "name": "sort", - "in": "query", - "description": "Sort string. Comma separated list of fields prefixed with '+' for ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", - "type": "string", - "required": false - }, - "query": { - "name": "query", - "in": "query", - "description": "Query string. Comma separated list of key, comparator, value pairs. Comparator supports '==', '<=', '>=', '<', '>', '!='. Example '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", - "type": "string", - "required": false - }, - "include": { - "name": "include", - "in": "query", - "description": "Inclusion string. Comma separated list of fields to include in the response. Example '?include=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'exclude' parameter Overriden by 'exclude' parameter", - "type": "string", - "required": false - }, - "exclude": { - "name": "exclude", - "in": "query", - "description": "Exclusion string. Comma separated list of fields to exclude in the response. Example '?exclude=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'include' parameter; takes precedence over 'include' parameter", - "type": "string", - "required": false - } - } -} diff -r e7a2adb465d1 -r dd0992bd51aa common/json/src/test/resources/systems-swagger.yaml --- a/common/json/src/test/resources/systems-swagger.yaml Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -swagger: '2.0' -info: - version: 0.0.1 - title: Thermostat Web Gateway System Information API - license: - name: GPL v2 with Classpath Exception - url: 'http://www.gnu.org/licenses' -consumes: - - application/json -produces: - - application/json - - text/html; charset=utf-8 -basePath: /systems/0.0.1 -paths: - /: - get: - description: Get information for all systems. - parameters: - - $ref: '#/parameters/limit' - - $ref: '#/parameters/offset' - - $ref: '#/parameters/sort' - - $ref: '#/parameters/include' - - $ref: '#/parameters/exclude' - - $ref: '#/parameters/query' - - $ref: '#/parameters/alive' - responses: - '200': - description: OK - schema: - $ref: '#/definitions/systems-get-response' - /systems/{systemId}: - parameters: - - $ref: '#/parameters/system-id' - get: - description: Get information for system {systemId}. - parameters: - - $ref: '#/parameters/limit' - - $ref: '#/parameters/offset' - - $ref: '#/parameters/sort' - - $ref: '#/parameters/include' - - $ref: '#/parameters/exclude' - - $ref: '#/parameters/query' - - $ref: '#/parameters/alive' - responses: - '200': - description: OK - schema: - $ref: '#/definitions/systems-get-response' - put: - description: Update information for system {systemId}. - parameters: - - $ref: '#/parameters/systems-put-body' - - $ref: '#/parameters/query' - responses: - '200': - description: OK - post: - description: Add information for system {systemId} - parameters: - - $ref: '#/parameters/system-info-array' - responses: - '200': - description: OK - delete: - description: Delete information for system ID {systemId}. - parameters: - - $ref: '#/parameters/query' - responses: - '200': - description: OK -definitions: - systems-get-response: - type: object - properties: - response: - $ref: '#/definitions/system-info-array' - system-info-array: - type: array - items: - $ref: '#/definitions/system-info' - system-info: - type: object - properties: - systemId: - type: string - agentId: - type: string - hostname: - type: string - osName: - type: string - osKernel: - type: string - osArch: - type: string - cpuCount: - type: integer - cpuModel: - type: string - totalMemory: - type: integer - format: int64 - timeCreated: - type: integer - format: int64 - lastUpdated: - type: integer - format: int64 - systems-put-body: - type: object - properties: - "set": - type: object -parameters: - system-id: - name: systemId - in: path - required: true - type: string - system-info-array: - name: system-info-array - in: body - description: The system information - required: true - schema: - $ref: '#/definitions/system-info-array' - systems-put-body: - name: body - in: body - description: >- - The JSON object containing a 'set' object. This contains single item JSON - objects that specify the field to replace and the JSON value to replace with. - Must not include 'systemId' field. Example { "set" : { - "field" : "value", "field2":{"object":"item"} } - required: true - schema: - $ref: '#/definitions/systems-put-body' - alive: - name: alive - in: query - description: Whether to return only systems that are currently running - type: boolean - required: false - default: true - limit: - name: limit - in: query - description: Limit of items to return. Example '1' - type: integer - required: false - default: 1 - offset: - name: offset - in: query - description: Offset of items to return. Example '0' - type: integer - required: true - default: 0 - sort: - name: sort - in: query - description: Sort string. Comma separated list of fields prefixed with '+' for ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. - type: string - required: false - query: - name: query - in: query - description: Query string. Comma separated list of key, comparator, value pairs. Comparator supports '==', '<=', '>=', '<', '>', '!='. Example '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. - type: string - required: false - include: - name: include - in: query - description: >- - Inclusion string. Comma separated list of fields to include in the - response. Example '?include=a,b' Fields use dot notation for embedded - documents. Example 'outer.inner' refers to field inner contained in field - outer. Cannot be used in combination with 'exclude' parameter Overriden by - 'exclude' parameter - type: string - required: false - exclude: - name: exclude - in: query - description: >- - Exclusion string. Comma separated list of fields to exclude in the - response. Example '?exclude=a,b' Fields use dot notation for embedded - documents. Example 'outer.inner' refers to field inner contained in field - outer. Cannot be used in combination with 'include' parameter; takes - precedence over 'include' parameter - type: string - required: false diff -r e7a2adb465d1 -r dd0992bd51aa common/pom.xml --- a/common/pom.xml Thu Sep 28 10:50:29 2017 +0200 +++ b/common/pom.xml Fri Sep 29 14:48:00 2017 -0400 @@ -1,58 +1,235 @@ - - + 4.0.0 - - com.redhat.thermostat - thermostat-base - 1.99.12-SNAPSHOT - + com.redhat.thermostat + thermostat-common + 0.1.0 + bundle + + + Thermostat project - common library + A shared library used by other components of Thermostat + http://icedtea.classpath.org/thermostat + + + GNU General Public License, version 2 (with "classpath exception") + https://www.gnu.org/licenses/gpl-2.0.html + + + + + Severin Gehwolf + sgehwolf@redhat.com + Red Hat, Inc. + http://www.redhat.com + + + Simon Tooke + stooke@redhat.com + Red Hat, Inc. + http://www.redhat.com + + + Mario Torre + neugens@redhat.com + Red Hat, Inc. + http://www.redhat.com + + + + scm:hg:http://icedtea.classpath.org/hg/thermostat-ng + scm:hg:ssh://icedtea.classpath.org/hg/thermostat-ng + http://icedtea.classpath.org/thermostat + + + + 1.7 + + + 4.3.1 + 4.3.1 + 4.3.1.201210102024 + osgi.cmpn + 4.2.0 + 1.8.2 + 1.9.12 - base-common - pom + + 2.6.2 + 4.12 + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + + deploy + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 3.6.1 + + true + 128m + 1024m + ${thermostat.java.version} + ${thermostat.java.version} + + - Thermostat Base Common + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + com.redhat.thermostat.common + Red Hat, Inc. + + com.redhat.thermostat.common.json, + com.redhat.thermostat.common.json.models, + com.redhat.thermostat.common.yaml, + 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 + maven-scr-plugin + + + generate-scr-scrdescriptor + + scr + + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + + - - type-system - json - + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + *.internal + + + + attach-javadocs + + jar + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/json/JsonUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/json/JsonUtil.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,149 @@ +/* + * 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.common.json; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.Map; +import java.util.NoSuchElementException; + +/** + * misc GSON utility classes + */ +public class JsonUtil { + + static String capitalize(final String s) { + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + + /** + * access a nested JSON object via a path string + * "foo.bar.2.fred" is equivalent to + * root.getAsJsonObject().get("foo").getAsJsonObject().get("bar").getAsJsonArray().get(2).getAsJsonObject().get("fred") + * + * @param root object to access + * @param path path into object + * @return element within root + */ + public static JsonElement fetch(final JsonElement root, final String path) { + String[] pathelements = path.split("[.]"); + // NOTE - it would be nice to parse foo[N] to foo.N to allow normal subscripting + return fetch(root, pathelements, 0); + } + + /** + * access a nexted JSON object via a path string + * "foo.bar.2.fred" is equivalent to + * root.getAsJsonObject().get("foo").getAsJsonObject().get("bar").getAsJsonArray().get(2).getAsJsonObject().get("fred") + * + * @param root object to access + * @param path path into object + * @param delimiter delimiter regex for path antries (default '.') + * @return element within root + */ + public static JsonElement fetch(final JsonElement root, final String path, final String delimiter) { + String[] pathelements = path.split(delimiter); + return fetch(root, pathelements, 0); + } + + private static JsonElement fetch(final JsonElement e, final String[] pathelements, int idx) { + if (idx == pathelements.length) { + // we've fallen off the end of the input path - now it's time to return the current object. + return e; + } else if (idx > pathelements.length) { + throw new IndexOutOfBoundsException("Internal error in JsonUtil.fetch() - index = " + idx); + } else { + if (e.isJsonObject()) { + JsonObject obj = e.getAsJsonObject(); + JsonElement next = obj.get(pathelements[idx]); + if (next == null) { + throw new NoSuchElementException(pathelements[idx]); + } else { + return fetch(next, pathelements, idx + 1); + } + } else if (e.isJsonArray()) { + JsonArray arr = e.getAsJsonArray(); + int n = Integer.parseInt(pathelements[idx]); + if (arr.size() <= n) { + throw new ArrayIndexOutOfBoundsException(n); + } else { + return fetch(arr.get(n), pathelements, idx + 1); + } + } else { + throw new NoSuchElementException(pathelements[idx]); + } + } + } + + /** + * perform a deep copy of a JsonElement + * + * @param jsonElement element to copy + * @return deep copy of the element tree + */ + // why isn't JsonElement.deepCopy() public? + public static JsonElement deepCopy(JsonElement jsonElement) { + if (jsonElement.isJsonPrimitive() || jsonElement.isJsonNull()) { + return jsonElement; // these are immutables anyway + } else if (jsonElement.isJsonObject()) { + return deepCopy(jsonElement.getAsJsonObject()); + } else if (jsonElement.isJsonArray()) { + return deepCopy(jsonElement.getAsJsonArray()); + } else { + throw new UnsupportedOperationException("Unsupported element: " + jsonElement); + } + } + + private static JsonObject deepCopy(JsonObject jsonObject) { + JsonObject result = new JsonObject(); + for (Map.Entry entry : jsonObject.entrySet()) { + result.add(entry.getKey(), deepCopy(entry.getValue())); + } + return result; + } + + private static JsonArray deepCopy(JsonArray jsonArray) { + JsonArray result = new JsonArray(); + for (JsonElement e : jsonArray) { + result.add(deepCopy(e)); + } + return result; + } +} + diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/json/models/ApiDef.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/json/models/ApiDef.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,108 @@ +/* + * 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.common.json.models; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; + +import java.util.List; +import java.util.Map; + +/** + * Java representation of a Swagger-defined web API endpoint + */ +public class ApiDef { + + String path; + String description; + JsonObject root; + List parameters; + MethodDef get; + MethodDef put; + MethodDef post; + MethodDef delete; + + /** + * Java representation of a Swagger endpoint + */ + public static class MethodDef { + List parameters; + String description; + Map responses; + + public String getDescription() { + return this.description; + } + } + + static class ResponseDef { + String description; + JsonObject schema; + } + + static class ParameterDef { + enum In { query, path, body }; + enum Type { integer, string, bool }; + String name; + String description; + In in; + Type type; + boolean required; + @SerializedName("default") + String deflt; + } + + public void setPath(String path) { + this.path = path; + } + + public MethodDef getGETAPI() { + return get; + } + + public MethodDef getPOSTAPI() { + return post; + } + + public MethodDef getDELETEAPI() { + return delete; + } + + public MethodDef getPUTAPI() { + return put; + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/json/models/SchemaDef.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/json/models/SchemaDef.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,209 @@ +/* + * 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.common.json.models; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; + +import com.redhat.thermostat.common.yaml.JsonToYaml; +import com.redhat.thermostat.lang.schema.annotations.Schema; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Partial Java representation of a JSON Schema
+ * (see json-schema.org) + */ +public class SchemaDef implements SchemaType { + + private static final Gson gson; + private static final int DEFAULT_MAXDEPTH = 1; + + static { + final boolean ENABLE_PRETTY_PRINT = false; + if (ENABLE_PRETTY_PRINT) { + GsonBuilder gbuilder = new GsonBuilder(); + gbuilder.setPrettyPrinting(); + gson = gbuilder.create(); + } else { + gson = new Gson(); + } + } + + @SerializedName("$schema") + private String schema; + @SerializedName("$id") + private String id; + private String title; + private String description; + private Map properties; + private List required; + + /** standard JSON schema properties that are not yet implemented: + private int multipleOf; + private long maximum; + private long exclusiveMaximum; + private long minimum; + private long exclusiveMinimum; + private int maxLength; + private int minLength; + private String pattern; + private int maxItems; + private int minItems; + private boolean uniqueItems; + private int maxProperties; + private int minProperties; + (and more, see json-schema.org) + ***/ + + // for GSon + public SchemaDef() {} + + public SchemaDef(Object target) { + this(target.getClass(), DEFAULT_MAXDEPTH); + } + + public SchemaDef(Object target, int maxDepth) { + this(target.getClass(), maxDepth); + } + + public SchemaDef(Class target) { + this(target, true, DEFAULT_MAXDEPTH); + } + + public SchemaDef(Class target, int maxDepth) { + this(target, true, maxDepth); + } + + private SchemaDef(Class target, boolean rootLevel, int maxDepth) { + if (rootLevel) { + schema = "http://json-schema.org/draft-04/schema#"; + } + Field[] fields = target.getDeclaredFields(); + if (fields.length > 0) { + properties = new HashMap<>(fields.length); + required = new ArrayList<>(); + for (Field field : fields) { + final boolean isTransient = Modifier.isTransient(field.getModifiers()); + if (!isTransient) { + String fname = field.getAnnotation(SerializedName.class) != null ? field.getAnnotation(SerializedName.class).value() : field.getName(); + Schema schema = field.getAnnotation(Schema.class); + String descr = null; + if (schema != null) { + if (!schema.name().isEmpty()) { + fname = schema.name(); + } + descr = schema.description(); + if (schema.required()) { + required.add(fname); + } + } + if (field.getType().isPrimitive()) { + String tt = field.getType().getSimpleName(); + properties.put(fname, new SimpleType(tt, descr)); + } else if (maxDepth > 1){ + properties.put(fname, new SchemaDef(field.getType(), false, maxDepth - 1)); + } else { + properties.put(fname, new SimpleType(field.getType().getSimpleName(), descr)); + } + } + } + if (required.isEmpty()) { + required = null; + } + } + } + + public Map getProperties() { + return this.properties; + } + + public List getRequired() { + return this.required; + } + + public JsonObject toJsonObject() { + JsonElement el = gson.toJsonTree(this); + return el.isJsonObject() ? el.getAsJsonObject() : null; + } + + public String toString() { + return gson.toJson(this); + } + + @Override + public TypeClass getTypeClass() { + return TypeClass.OBJECT; + } + + public static class SimpleType implements SchemaType { + transient TypeClass type; + @SerializedName("type") + String typeStr; + String description; + SimpleType(String tname, String descr) { + if ("string".equals(tname)) { + type = TypeClass.STRING; + } else if ("int".equals(tname) || "float".equals(tname) || "double".equals(tname) || "long".equals(tname) || "number".equals(tname)) { + type = TypeClass.NUMBER; + } else if ("Integer".equals(tname) || "Float".equals(tname) || "Double".equals(tname) || "Long".equals(tname)) { + type = TypeClass.NUMBER; + } else if ("boolean".equals(tname) || "Boolean".equals(tname)) { + type = TypeClass.BOOLEAN; + } else { + type = TypeClass.OBJECT; + } + this.typeStr = type == TypeClass.OBJECT ? tname : type.toString(); + this.description = descr; + } + @Override + public TypeClass getTypeClass() { + return type; + } + public String getTypeName() { + return type == TypeClass.OBJECT ? typeStr : type.toString(); + } + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/json/models/SchemaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/json/models/SchemaType.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,65 @@ +/* + * 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.common.json.models; + +/** + * the type of a JSON schema element + */ +public interface SchemaType { + TypeClass getTypeClass(); + + enum TypeClass { + + OBJECT("object"), + ARRAY("array"), + NUMBER("number"), + STRING("string"), + BOOLEAN("boolean"), + NULL("null"); + + private final String typeString; + + private TypeClass(String s) { + typeString = s; + } + + @Override + public String toString() { + return typeString; + } + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/json/models/SwaggerDef.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/json/models/SwaggerDef.java Fri Sep 29 14:48:00 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.common.json.models; + +import java.util.List; +import java.util.Map; + +/** + * Java representation of a Swagger file + */ +public class SwaggerDef { + + String swagger; + InfoDef info; + List consumes; + List produces; + String basePath; + Map paths; + + static class InfoDef { + String version; + String title; + LicenseDef license; + } + + static class LicenseDef { + String name; + String url; + } + + static class SwaggerSchema extends SchemaDef { + private String type; + } + + public String getBasePath() { + return basePath; + } + + public Map getPaths() { + return paths; + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/yaml/JsonToYaml.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/yaml/JsonToYaml.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,119 @@ +/* + * 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.common.yaml; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Map; + +/** + * convert JSON object to YAML string + */ +public class JsonToYaml { + + private Writer out; + private int indent = 2; + + public void setIndentation(int i) { + this.indent = i; + } + + String jsonToYamlString(JsonObject root) throws IOException { + this.out = new StringWriter(); + jsonToYaml(root, out); + return out.toString(); + } + + public void jsonToYaml(JsonObject root, Writer out) throws IOException { + this.out = out; + jsonToYaml(root, 0); + } + + private void dispatch(JsonElement el, int currentIndent) throws IOException { + if (el.isJsonPrimitive()) { + final JsonPrimitive pr = el.getAsJsonPrimitive(); + if (pr.isBoolean() || pr.isNumber()) { + out.append(el.getAsString()).append('\n'); + } else { + out.append("'").append(el.getAsString()).append("'\n"); + } + } else if (el.isJsonArray()) { + out.append('\n'); + jsonToYaml(el.getAsJsonArray(), currentIndent); + } else if (el.isJsonObject()) { + out.append('\n'); + jsonToYaml(el.getAsJsonObject(), currentIndent); + } else { + throw new UnsupportedOperationException("Unsupported element: " + el); + } + } + + private void jsonToYaml(JsonObject obj, int currentIndent) throws IOException { + final int newindent = currentIndent + indent; + for (final Map.Entry entry : obj.entrySet()) { + doIndent(currentIndent); + out.append(entry.getKey()).append(": "); + dispatch(entry.getValue(), newindent); + } + } + + private void jsonToYaml(JsonArray array, int currentIndent) throws IOException { + for (final JsonElement el : array) { + doIndent(currentIndent); + out.append("- "); + if (el.isJsonArray()) { + jsonToYaml(el.getAsJsonArray(), 0); + } else if (el.isJsonObject()) { + jsonToYaml(el.getAsJsonObject(), 0); + } else { + dispatch(el, 0); + } + } + } + + private void doIndent(int currentIndent) throws IOException { + for (int i = 0; i < currentIndent; i++) + out.append(' '); + } +} + diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/yaml/RefResolver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/yaml/RefResolver.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,114 @@ +/* + * 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.common.yaml; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.redhat.thermostat.common.json.JsonUtil; + +import java.io.IOException; +import java.util.Map; + +/** + * Given a JSON object (created from a Swagger YAML or JSON file), resolve all $ref paths + * TODO: currently doesn't test for circular references + */ +public class RefResolver { + + private static final String REF_MEMBER = "$ref"; + + /** + * resolve a path into an object + * @param defsroot root of object that is referred to + * @param current current object within defsroot (for relative paths) + * @param path path to resolve (e.g. "#/definitions/return-code") + * @return object pointed to by path + * @throws IOException if path is unresolvable + */ + public static JsonObject resolvePath(JsonObject defsroot, JsonObject current, String path) throws IOException { + String[] pathElements = path.split("/"); + for (String pe : pathElements) { + if ("#".equals(pe)) { + current = defsroot; + } else if (current.has(pe)) { + current = current.getAsJsonObject(pe); + } else { + throw new IOException("unresolvable reference '" + pe + "' in path '" + path + "'"); + } + } + return current; + } + + /** + * replace all $ref paths by nested objects + * @param defsRoot root of object that is referred to (usually the same as objeToResolve) + * @param objToResolve root of object to resolve references of + * @return objsToResolve + * @throws IOException if any referencesa are unresolveable + */ + public static JsonElement resolveRefs(JsonObject defsRoot, JsonElement objToResolve) throws IOException { + + if (objToResolve.isJsonObject()) { + final JsonObject obj = objToResolve.getAsJsonObject(); + for (Map.Entry entry : obj.entrySet()) { + if (REF_MEMBER.equals(entry.getKey())) { + String ref = entry.getValue().getAsString(); + obj.remove(REF_MEMBER); + JsonObject refObject = resolvePath(defsRoot, obj, ref); + resolveRefs(defsRoot, refObject); + // hoist all members of refObject to contents + for (Map.Entry refentry : refObject.entrySet()) { + obj.add(refentry.getKey(), JsonUtil.deepCopy(refentry.getValue())); + } + } else { + resolveRefs(defsRoot, entry.getValue()); + } + } + } else if (objToResolve.isJsonArray()) { + final JsonArray contents = objToResolve.getAsJsonArray(); + for (int i = 0; i < contents.size(); i++) { + JsonElement el = contents.get(i); + if (el.isJsonObject()) { + contents.set(i, resolveRefs(defsRoot, el.getAsJsonObject())); + } + } + } + return objToResolve; + } + +} \ No newline at end of file diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/common/yaml/YamlToJson.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/common/yaml/YamlToJson.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,309 @@ +/* + * 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.common.yaml; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utility class to read YAML files and convert to GSON objects + * + * Limitations: + * Only enough code to read Swagger YAML is implemented + * $ref only works within the same document, not across the network + */ +public class YamlToJson { + + public YamlToJson() { + } + + public JsonObject yamlToJsonObject(final File fn) throws IOException { + try (final Reader in = new FileReader(fn)) { + return yamlToJsonObject(in); + } + } + + public JsonObject yamlToJsonObject(final String yaml) throws IOException { + try (final Reader in = new StringReader(yaml)) { + return yamlToJsonObject(in); + } + } + + public JsonObject yamlToJsonObject(final Reader in) throws IOException { + try (final PushableReader pr = new PushableReader(in instanceof BufferedReader ? (BufferedReader)in : new BufferedReader(in));) { + final JsonObject obj = new JsonObject(); + yamlToJson(pr, obj, 0); + pr.close(); + return obj; + } + } + + private void yamlToJson(PushableReader in, JsonElement parent, int currentIndent) throws IOException { + for (String s = in.readLine(); s != null; s = in.readLine()) { + YamlLine line = new YamlLine(s); + if (line.indent == 0 && line.value == null && line.name == null) { + // blsnk or unparseable line + continue; + } + if (line.indent < currentIndent) { + in.push(s); + return; + } + final JsonElement child; + if (line.hasColon) { + if (line.value != null && !line.value.isEmpty()) { + if (">-".equals(line.value)) { + //the next few lines are the value for the current line + child = makeUnquotedPrimitive(absorb(in, currentIndent)); + } else { + JsonElement ce = makeUnquotedPrimitive(line.value); + if (parent.isJsonArray()) { + JsonObject childobj = new JsonObject(); + childobj.add(makeUnquotedString(line.name), ce); + child = childobj; + } else { + child = ce; + } + } + } else { + // no value specified; this could be the start of an object or array + final String next = in.readLine(); + boolean isArray = false; + if (next != null) { + YamlLine nextLine = new YamlLine(next); + isArray = nextLine.hasDashPrefix; + in.push(next); + } + child = isArray ? new JsonArray() : new JsonObject(); + yamlToJson(in, child, line.indent); + } + } + else { + child = (line.value != null) ? makeUnquotedPrimitive(line.value) : new JsonPrimitive(""); + } + if (parent.isJsonArray()) { + if (line.hasDashPrefix) { + JsonArray parray = parent.getAsJsonArray(); + parray.add(child); + } else { + System.err.println("Array member must begin with dash: " + s); + } + } else if (parent.isJsonObject()) { + JsonObject pobject = parent.getAsJsonObject(); + pobject.add(makeUnquotedString(line.name), child); + } else { + System.err.println("Error: parent is neither object nor array"); + } + currentIndent = line.indent; + } + } + + private static String makeUnquotedString(final String s) { + String ret = s; + if (s.length() >= 2) { + if ((s.charAt(0) == '\'') && (s.charAt(s.length() - 1) == '\'') + || (s.charAt(0) == '"') && (s.charAt(s.length() - 1) == '"')) { + ret = s.substring(1, s.length() - 1); + } + } + return ret; + } + + private static JsonPrimitive makeUnquotedPrimitive(final String s) { + final String uqString = makeUnquotedString(s); + // anything quoted will return a string, otherwise try to parse + if (uqString.length() == s.length()) { + if ("true".equals(uqString)) + return new JsonPrimitive(true); + else if ("false".equals(uqString)) + return new JsonPrimitive(false); + else if ("null".equals(uqString)) + return null; + else { + // test for number + final char c0 = uqString.charAt(0); + if (Character.isDigit(c0) || c0 == '+' || c0 == '-') { + try { + return new JsonPrimitive(new Long(uqString)); + } catch (NumberFormatException ignored) { + ; // fall through to return String + } + + } + } + } + return new JsonPrimitive(uqString); + } + + private static String absorb(PushableReader in, int currentIndent) throws IOException { + // append lines until the indentation is the same as the currentIndent + StringBuilder a = new StringBuilder(); + for (String s = in.readLine(); s != null; s = in.readLine()) { + int wsCount; + for (wsCount = 0; wsCount < s.length(); wsCount++) { + if (!Character.isWhitespace(s.charAt(wsCount))) { + break; + } + } + if (wsCount > currentIndent) { + a.append(a.length() == 0 ? s.trim() : ' ' + s.trim()); + } else { + in.push(s); + break; + } + } + return a.toString(); + } + + /** + * YamlLine - parse a single line of YAML file + */ + static class YamlLine { + int indent; + String name; + String value; + boolean hasColon; + boolean hasDashPrefix; + + private static final String regexpr = "^([\\s]*)([-]?[\\s]*)([^:]+)([:]?)(.*)$"; + private static final Pattern p = Pattern.compile(regexpr); + + YamlLine(String line) throws IOException { + Matcher m = p.matcher(line); + if (m.matches()) { + final String s1 = m.group(1); // leading whitespace + final String s2 = m.group(2); // optional '-' indicating array element + final String s3 = m.group(3); // key + final String s4 = m.group(4); // ':' + final String s5 = m.group(5).trim(); // value or optional '>-' + hasColon = !(s4 == null || s4.isEmpty()); + hasDashPrefix = !(s2 == null || s2.isEmpty()); + indent = s1.length() + (hasDashPrefix ? s2.length() : 0); + if (hasColon) { + name = s3.trim(); + value = s5.trim(); + } else { + name = null; + value = s3 + s5; + value = value.trim(); + } + } else { + if (line.isEmpty()) { + name = null; + value = null; + indent = 0; + } else { + throw new IOException("parse error in YAML '" + line + "'"); + } + } + } + } + + static class PushableReader implements AutoCloseable { + + final Stack stack = new Stack<>(); + final BufferedReader in; + + PushableReader(BufferedReader in) { + this.in = in; + } + + String readLine() throws IOException { + if (stack.isEmpty()) { + return in.readLine(); + } else { + return stack.pop(); + } + } + + void push(String s) { + stack.push(s); + } + + @Override + public void close() throws IOException { + in.close(); + } + } + + /* + * utility function to convert YAML file to JSON stdout + */ + public static void main(String[] args) { + boolean pretty = false; + for (final String fn : args) { + if ("--pretty".equals(fn)) { + pretty = true; + } else if ("--help".equals("fn")) { + System.err.println("YamlToJason [--pretty] [--help] infile1 [infile2] ..."); + } else { + try { + final YamlToJson y2j = new YamlToJson(); + final File fin = new File(fn); + final JsonObject json = y2j.yamlToJsonObject(fin); + if (pretty) { + final GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.setPrettyPrinting(); + final Gson gson = gsonBuilder.create(); + System.out.println(gson.toJson(json)); + } else { + System.out.println(json.toString()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,51 @@ +/* + * 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 target object to JSON. + * + * @param target the object to serialize + * @return string representation of the target object + */ + String serialiase(Object target); +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java Fri Sep 29 14:48:00 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; + +/** + * JSON schema building service + */ +public interface SchemaBuilder { + + /** + * Returns the Schema for the given class + * @param target the object of which to return the schema + * @return string (format: JSON) representation of the schema + */ + String getSchema(Class target); + + /** + * Registers a type in the schema + * @param target the type to be registered + */ + void registerType(Class target); + +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java Fri Sep 29 14:48:00 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 e7a2adb465d1 -r dd0992bd51aa common/src/test/java/com/redhat/thermostat/common/json/JsonUtilTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/common/json/JsonUtilTest.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,130 @@ +/* + * 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.common.json; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.junit.Test; + +import java.util.NoSuchElementException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +public class JsonUtilTest { + + private static final String JSON = + "{\n" + + " \"parents\" : [ \"homer\", \"marge\" ],\n" + + " \"children\" : {\n" + + " \"bart\" : {\n" + + " \"title\" : \"son\",\n" + + " \"age\" : \"14\"\n" + + " },\n" + + " \"lisa\" : {\n" + + " \"title\" : \"daughter\",\n" + + " \"age\" : \"12\"\n" + + " },\n" + + " \"maggie\" : {\n" + + " \"title\" : \"daughter\",\n" + + " \"age\" : \"1\"\n" + + " }\n" + + " \n" + + " },\n" + + " \"surname\" : \"simpsons\"\n" + + "}\n"; + + @Test + public void testCapitalize() { + assertEquals("Fred", JsonUtil.capitalize("Fred")); + assertEquals("Barney", JsonUtil.capitalize("barney")); + } + + @Test + public void testDeepCopy() { + final JsonParser parser = new JsonParser(); + final JsonElement j0 = parser.parse(JSON); + final JsonElement j1 = JsonUtil.deepCopy(j0); + assertEquals(j0, j1); + + j1.getAsJsonObject().get("children").getAsJsonObject().get("bart").getAsJsonObject().addProperty("age", 99); + assertNotEquals(j0, j1); + } + + @Test + public void testFetchObject() { + final JsonParser parser = new JsonParser(); + final JsonElement j0 = parser.parse(JSON); + final JsonElement bartAge = JsonUtil.fetch(j0, "children.bart.age"); + assertEquals(14, bartAge.getAsInt()); + } + + @Test(expected = NoSuchElementException.class) + public void testFetchTooMuch() { + final JsonParser parser = new JsonParser(); + final JsonElement j0 = parser.parse(JSON); + JsonUtil.fetch(j0, "children.bart.age.overflow"); + } + + @Test(expected = NoSuchElementException.class) + public void testFetchTooLittle() { + final JsonParser parser = new JsonParser(); + final JsonElement j0 = parser.parse(JSON); + JsonUtil.fetch(j0, ""); + } + + @Test + public void testFetchArray() { + final JsonParser parser = new JsonParser(); + final JsonElement j0 = parser.parse(JSON); + final JsonElement homer = JsonUtil.fetch(j0, "parents.0"); + assertEquals("homer", homer.getAsString()); + final JsonElement marge = JsonUtil.fetch(j0, "parents.1"); + assertEquals("marge", marge.getAsString()); + } + + //@Test + // disable until this syntax feature is implemented + public void testFetchArraySquareBrackets() { + final JsonParser parser = new JsonParser(); + final JsonElement j0 = parser.parse(JSON); + final JsonElement homer = JsonUtil.fetch(j0, "parents[0]"); + assertEquals("homer", homer.getAsString()); + final JsonElement marge = JsonUtil.fetch(j0, "parents[1]"); + assertEquals("marge", marge.getAsString()); + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/java/com/redhat/thermostat/common/json/models/SchemaDefTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/common/json/models/SchemaDefTest.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,65 @@ +/* + * 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.common.json.models; + +import com.redhat.thermostat.common.yaml.JsonToYaml; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class SchemaDefTest { + + @Test + public void testShallowFunctionality() { + final SchemaDef def = new SchemaDef(JsonToYaml.class); + assertTrue(def.getProperties().get("out") instanceof SchemaDef.SimpleType); + final SchemaDef.SimpleType typeOfOut = (SchemaDef.SimpleType)def.getProperties().get("out"); + assertEquals(SchemaType.TypeClass.OBJECT, typeOfOut.getTypeClass()); + assertEquals("Writer", typeOfOut.getTypeName()); + } + + @Test + public void testDeepFunctionality() { + SchemaDef def = new SchemaDef(JsonToYaml.class, 99); + assertTrue(def.getProperties().get("out") instanceof SchemaDef); + final SchemaDef typeOfOut = (SchemaDef)def.getProperties().get("out"); + assertEquals(SchemaType.TypeClass.OBJECT, typeOfOut.getTypeClass()); + assertFalse(typeOfOut.getProperties().isEmpty()); + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/java/com/redhat/thermostat/common/yaml/JsonToYamlTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/common/yaml/JsonToYamlTest.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,112 @@ +/* + * 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.common.yaml; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.junit.Test; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; + + +import static org.junit.Assert.assertEquals; + +public class JsonToYamlTest { + + private static final File API1_YAML_FILE = new File("./src/test/resources/systems-swagger.yaml"); + private static final File API1_JSON_FILE = new File("./src/test/resources/systems-swagger.json"); + + @Test + public void testConvert() throws IOException { + + // read source JSON file + JsonObject goodjson = readFileToJson(API1_JSON_FILE).getAsJsonObject(); + + final JsonToYaml j2y = new JsonToYaml(); + + // convert to YAML string + final String yamlStr = j2y.jsonToYamlString(goodjson); + + // get a temp file name + final File tmpFile = mktempfile("JsonToYamlTest.testConvert", ".yaml"); + + // write a new YAML file + writeFile(tmpFile, yamlStr); + + // read the known good YAML file + final YamlToJson y2j = new YamlToJson(); + final JsonObject goodyaml = y2j.yamlToJsonObject(API1_YAML_FILE); + assertEquals(goodjson, goodyaml); + + // read the new YAML file + final JsonObject testyaml = y2j.yamlToJsonObject(tmpFile); + assertEquals(goodjson, testyaml); + } + + private File mktempfile(final String prefix, final String suffix) throws IOException { + final File f = File.createTempFile(prefix, suffix); + f.deleteOnExit(); + return f; + } + + private JsonElement readFileToJson(File f) throws IOException { + try (final Reader in = new BufferedReader(new FileReader(f))) { + final JsonParser parser = new JsonParser(); + return parser.parse(in); + } catch (IOException e) { + throw e; + } + } + + private void writeFile(File f, String contents) throws IOException { + try (final Writer out = new BufferedWriter(new FileWriter(f))) { + out.write(contents); + out.close(); + } catch (IOException e) { + throw e; + } + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/java/com/redhat/thermostat/common/yaml/RefResolverTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/common/yaml/RefResolverTest.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,74 @@ +/* + * 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.common.yaml; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.redhat.thermostat.common.json.JsonUtil; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class RefResolverTest { + + private static final File API1_YAML_FILE = new File("./src/test/resources/systems-swagger.yaml"); + + @Test + public void resolverTest() throws IOException { + YamlToJson y2j = new YamlToJson(); + JsonObject yaml = y2j.yamlToJsonObject(API1_YAML_FILE); + assertNotNull(yaml); + + JsonElement getRefType = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.responses.200.schema.$ref"); + assertTrue(getRefType.getAsString().endsWith("definitions/systems-get-response")); + + // ref1 is the defintion pointed to by the reference + JsonElement ref1 = JsonUtil.fetch(yaml, "definitions.systems-get-response"); + + // resolve all refs + RefResolver.resolveRefs(yaml, yaml); + + // get the response type, which should no longer be a reference but a copy of the definition pointed to by the reference + JsonElement resolvedType = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.responses.200.schema"); + assertEquals(ref1, resolvedType); + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/java/com/redhat/thermostat/common/yaml/YamlToJsonTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/common/yaml/YamlToJsonTest.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,110 @@ +/* + * 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.common.yaml; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.redhat.thermostat.common.json.JsonUtil; +import com.redhat.thermostat.common.json.models.SwaggerDef; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class YamlToJsonTest { + + private static final File API1_YAML_FILE = new File("./src/test/resources/systems-swagger.yaml"); + + @Test + public void readYamlTest() throws IOException { + YamlToJson y2j = new YamlToJson(); + JsonObject yaml = y2j.yamlToJsonObject(API1_YAML_FILE); + assertNotNull(yaml); + JsonElement getDescr = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.description"); + assertNotNull(getDescr); + assertTrue(getDescr.isJsonPrimitive()); + assertEquals("Get information for system {systemId}.", getDescr.getAsString()); + } + + @Test + public void yamlToModelTest() throws IOException { + YamlToJson y2j = new YamlToJson(); + JsonObject yaml = y2j.yamlToJsonObject(API1_YAML_FILE); + assertNotNull(yaml); + + // resolve all refs + RefResolver.resolveRefs(yaml, yaml); + + // convert JSON to actual Java class + Gson gson = new Gson(); + SwaggerDef swaggerDef = gson.fromJson(yaml, SwaggerDef.class); + + final String getdescr = JsonUtil.fetch(yaml, "paths./systems/{systemId}.get.description").getAsString(); + assertEquals(getdescr, swaggerDef.getPaths().get("/systems/{systemId}").getGETAPI().getDescription()); + } + + private static final String GPL = "GPL v2 with Classpath Exception"; + + private static final String YAML_WITH_NULL = + "info:\n" + + " title: Thermostat Web Gateway JVM Information API\n" + + " license:\n" + + " name: " + GPL + "\n" + + " url: 'http://www.gnu.org/licenses'\n" + + " org: null\n" + + " phone: 416-363-6097\n" + + "consumes:\n" + + " - application/json\n" + + "produces:\n" + + " - application/json\n" + + " - text/html; charset=utf-8\n" + + "basePath: /jvms/0.0.1\n"; + + @Test + public void testNull() throws IOException { + YamlToJson y2j = new YamlToJson(); + JsonObject yaml = y2j.yamlToJsonObject(YAML_WITH_NULL); + assertEquals(GPL, JsonUtil.fetch(yaml, "info.license.name").getAsString()); + final JsonElement nell = JsonUtil.fetch(yaml, "info.license.org"); + assertTrue(nell.isJsonNull()); + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,204 @@ +/* + * 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.internal.JSONServiceImpl; +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 e7a2adb465d1 -r dd0992bd51aa common/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,254 @@ +/* + * 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.internal.SchemaBuilderImpl; +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 e7a2adb465d1 -r dd0992bd51aa common/src/test/resources/jvms-swagger.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/resources/jvms-swagger.json Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,480 @@ +{ + "swagger": "2.0", + "info": { + "version": "0.0.1", + "title": "Thermostat Web Gateway JVM Information API", + "license": { + "name": "GPL v2 with Classpath Exception", + "url": "http://www.gnu.org/licenses" + } + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json", + "text/html; charset=utf-8" + ], + "basePath": "/jvms/0.0.1", + "paths": { + "/systems/{systemId}": { + "parameters": [ + { + "$ref": "#/parameters/system-id" + } + ], + "get": { + "description": "Get jvms for system {systemId}", + "parameters": [ + { + "$ref": "#/parameters/limit" + }, + { + "$ref": "#/parameters/offset" + }, + { + "$ref": "#/parameters/sort" + }, + { + "$ref": "#/parameters/include" + }, + { + "$ref": "#/parameters/exclude" + }, + { + "$ref": "#/parameters/query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/jvms-get-response" + } + } + } + }, + "post": { + "description": "Add jvms for system {systemId}", + "parameters": [ + { + "$ref": "#/parameters/jvms-post-body" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "description": "Delete all jvms on system {systemId}", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/systems/{systemId}/jvms/{jvmId}": { + "parameters": [ + { + "$ref": "#/parameters/system-id" + }, + { + "$ref": "#/parameters/jvm-id" + } + ], + "get": { + "description": "Get information for the JVM with id {jvmId} running on system {systemId}", + "parameters": [ + { + "$ref": "#/parameters/include" + }, + { + "$ref": "#/parameters/exclude" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/jvms-get-response" + } + } + } + }, + "put": { + "description": "Update the JVM with id {jvmId} running on system {systemId}", + "responses": { + "200": { + "description": "OK" + } + }, + "parameters": [ + { + "$ref": "#/parameters/jvms-put-body" + } + ] + }, + "delete": { + "description": "Delete the JVM with id {jvmId} running on system {systemId}", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/tree": { + "get": { + "description": "Get jvm information organized by systemId", + "parameters": [ + { + "$ref": "#/parameters/alive-only" + }, + { + "$ref": "#/parameters/include" + }, + { + "$ref": "#/parameters/exclude" + }, + { + "$ref": "#/parameters/limit" + }, + { + "$ref": "#/parameters/offset" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/tree-get-response" + } + } + } + } + }, + "/update/systems/{systemId}/ts/{timeStamp}": { + "parameters": [ + { + "$ref": "#/parameters/system-id" + }, + { + "$ref": "#/parameters/timestamp" + } + ], + "put": { + "description": "Set last updated to {timeStamp} for jvm information on system {systemId}", + "parameters": [ + { + "$ref": "#/parameters/update-put-body" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "definitions": { + "jvm-get-info": { + "type": "object", + "properties": { + "systemId": { + "type": "string" + }, + "agentId": { + "type": "string" + }, + "jvmId": { + "type": "string" + }, + "mainClass": { + "type": "string" + }, + "startTime": { + "$ref": "#/definitions/metric" + }, + "stopTime": { + "$ref": "#/definitions/metric" + }, + "jvmPid": { + "type": "integer" + }, + "javaVersion": { + "type": "string" + }, + "javaHome": { + "type": "string" + }, + "javaCommandLine": { + "type": "string" + }, + "jvmArguments": { + "type": "string" + }, + "jvmName": { + "type": "string" + }, + "jvmInfo": { + "type": "string" + }, + "jvmVersion": { + "type": "string" + }, + "classpath": { + "type": "string" + }, + "environment": { + "type": "array", + "items": { + "$ref": "#/definitions/environment-items" + } + }, + "uid": { + "$ref": "#/definitions/metric" + }, + "username": { + "type": "string" + }, + "lastUpdated": { + "$ref": "#/definitions/metric" + } + } + }, + "jvm-post-info": { + "type": "object", + "properties": { + "agentId": { + "type": "string" + }, + "jvmId": { + "type": "string" + }, + "mainClass": { + "type": "string" + }, + "startTime": { + "$ref": "#/definitions/metric" + }, + "stopTime": { + "$ref": "#/definitions/metric" + }, + "jvmPid": { + "type": "integer" + }, + "javaVersion": { + "type": "string" + }, + "javaHome": { + "type": "string" + }, + "javaCommandLine": { + "type": "string" + }, + "jvmArguments": { + "type": "string" + }, + "jvmName": { + "type": "string" + }, + "jvmInfo": { + "type": "string" + }, + "jvmVersion": { + "type": "string" + }, + "classpath": { + "type": "string" + }, + "environment": { + "type": "array", + "items": { + "$ref": "#/definitions/environment-items" + } + }, + "uid": { + "$ref": "#/definitions/metric" + }, + "username": { + "type": "string" + }, + "lastUpdated": { + "$ref": "#/definitions/metric" + } + } + }, + "environment-items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "metric": { + "type": "object", + "properties": { + "$numberLong": { + "type": "string" + } + } + }, + "jvms-get-response": { + "type": "object", + "properties": { + "response": { + "type": "array", + "items": { + "$ref": "#/definitions/jvm-get-info" + } + } + } + }, + "jvms-put-body": { + "type": "object", + "properties": { + "set": { + "type": "object" + } + } + }, + "jvms-post-body": { + "type": "array", + "items": { + "$ref": "#/definitions/jvm-post-info" + } + }, + "update-put-body": { + "type": "array", + "description": "An array of jvm ID strings", + "items": { + "type": "string" + } + }, + "tree-get-response": { + "type": "object", + "properties": { + "systemId": { + "type": "string" + }, + "jvms": { + "type": "array", + "items": { + "$ref": "#/definitions/jvm-get-info" + } + } + } + } + }, + "parameters": { + "system-id": { + "name": "systemId", + "in": "path", + "required": true, + "type": "string", + "description": "The system ID for the jvms" + }, + "jvm-id": { + "name": "jvmId", + "in": "path", + "required": true, + "type": "string", + "description": "The ID of the jvm" + }, + "timestamp": { + "name": "timeStamp", + "in": "path", + "required": true, + "type": "integer", + "format": "int64", + "description": "The UNIX timestamp in milliseconds to set the last_updated field for." + }, + "jvms-post-body": { + "name": "body", + "in": "body", + "description": "The jvm information", + "required": true, + "schema": { + "$ref": "#/definitions/jvms-post-body" + } + }, + "jvms-put-body": { + "name": "body", + "in": "body", + "description": "The JSON object containing a 'set' object. This contains single item JSON objects that specify the field to replace and the JSON value to replace with. Must not include 'systemId' or 'jvmId' fields. Example { \"set\" : { \"field\" : \"value\", \"field2\":{\"object\":\"item\"} }", + "required": true, + "schema": { + "$ref": "#/definitions/jvms-put-body" + } + }, + "update-put-body": { + "name": "body", + "in": "body", + "description": "An array of jvmIds for which to update the last_updated field.", + "required": true, + "schema": { + "$ref": "#/definitions/update-put-body" + } + }, + "limit": { + "name": "limit", + "in": "query", + "description": "Limit of items to return. Example '1'", + "type": "integer", + "required": false, + "default": 1 + }, + "offset": { + "name": "offset", + "in": "query", + "description": "Offset of items to return. Example '0'", + "type": "integer", + "required": false, + "default": 0 + }, + "sort": { + "name": "sort", + "in": "query", + "description": "Sort string. Comma separated list of fields prefixed with '+' for ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", + "type": "string", + "required": false + }, + "query": { + "name": "query", + "in": "query", + "description": "Query string. Comma separated list of key, comparator, value pairs. Comparator supports '==', '<=', '>=', '<', '>', '!='. Example '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", + "type": "string", + "required": false + }, + "include": { + "name": "include", + "in": "query", + "description": "Inclusion string. Comma separated list of fields to include in the response. Example '?include=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'exclude' parameter Overriden by 'exclude' parameter", + "type": "string", + "required": false + }, + "exclude": { + "name": "exclude", + "in": "query", + "description": "Exclusion string. Comma separated list of fields to exclude in the response. Example '?exclude=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'include' parameter; takes precedence over 'include' parameter", + "type": "string", + "required": false + }, + "alive-only": { + "name": "aliveOnly", + "in": "query", + "description": "Whether or not to return only JVMs that are live", + "type": "boolean", + "default": true, + "required": false + } + } +} \ No newline at end of file diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/resources/jvms-swagger.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/resources/jvms-swagger.yaml Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,337 @@ +swagger: '2.0' +info: + version: 0.0.1 + title: Thermostat Web Gateway JVM Information API + license: + name: GPL v2 with Classpath Exception + url: 'http://www.gnu.org/licenses' +consumes: + - application/json +produces: + - application/json + - text/html; charset=utf-8 +basePath: /jvms/0.0.1 +paths: + '/systems/{systemId}': + parameters: + - $ref: '#/parameters/system-id' + get: + description: 'Get jvms for system {systemId}' + parameters: + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/sort' + - $ref: '#/parameters/include' + - $ref: '#/parameters/exclude' + - $ref: '#/parameters/query' + responses: + '200': + description: OK + schema: + $ref: '#/definitions/jvms-get-response' + post: + description: 'Add jvms for system {systemId}' + parameters: + - $ref: '#/parameters/jvms-post-body' + responses: + '200': + description: OK + delete: + description: 'Delete all jvms on system {systemId}' + responses: + '200': + description: OK + '/systems/{systemId}/jvms/{jvmId}': + parameters: + - $ref: '#/parameters/system-id' + - $ref: '#/parameters/jvm-id' + get: + description: 'Get information for the JVM with id {jvmId} running on system {systemId}' + parameters: + - $ref: '#/parameters/include' + - $ref: '#/parameters/exclude' + responses: + '200': + description: OK + schema: + $ref: '#/definitions/jvms-get-response' + put: + description: 'Update the JVM with id {jvmId} running on system {systemId}' + responses: + '200': + description: OK + parameters: + - $ref: "#/parameters/jvms-put-body" + delete: + description: 'Delete the JVM with id {jvmId} running on system {systemId}' + responses: + '200': + description: OK + '/tree': + get: + description: Get jvm information organized by systemId + parameters: + - $ref: '#/parameters/alive-only' + - $ref: '#/parameters/include' + - $ref: '#/parameters/exclude' + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + responses: + '200': + description: OK + schema: + $ref: '#/definitions/tree-get-response' + '/update/systems/{systemId}/ts/{timeStamp}': + parameters: + - $ref: '#/parameters/system-id' + - $ref: '#/parameters/timestamp' + put: + description: 'Set last updated to {timeStamp} for jvm information on system {systemId}' + parameters: + - $ref: "#/parameters/update-put-body" + responses: + '200': + description: OK + +definitions: + jvm-get-info: + type: object + properties: + systemId: + type: string + agentId: + type: string + jvmId: + type: string + mainClass: + type: string + startTime: + $ref: '#/definitions/metric' + stopTime: + $ref: '#/definitions/metric' + jvmPid: + type: integer + javaVersion: + type: string + javaHome: + type: string + javaCommandLine: + type: string + jvmArguments: + type: string + jvmName: + type: string + jvmInfo: + type: string + jvmVersion: + type: string + classpath: + type: string + environment: + type: array + items: + $ref: '#/definitions/environment-items' + uid: + $ref: '#/definitions/metric' + username: + type: string + lastUpdated: + $ref: '#/definitions/metric' + + jvm-post-info: + type: object + properties: + agentId: + type: string + jvmId: + type: string + mainClass: + type: string + startTime: + $ref: '#/definitions/metric' + stopTime: + $ref: '#/definitions/metric' + jvmPid: + type: integer + javaVersion: + type: string + javaHome: + type: string + javaCommandLine: + type: string + jvmArguments: + type: string + jvmName: + type: string + jvmInfo: + type: string + jvmVersion: + type: string + classpath: + type: string + environment: + type: array + items: + $ref: '#/definitions/environment-items' + uid: + $ref: '#/definitions/metric' + username: + type: string + lastUpdated: + $ref: '#/definitions/metric' + environment-items: + type: object + properties: + key: + type: string + value: + type: string + + metric: + type: object + properties: + $numberLong: + type: string + + jvms-get-response: + type: object + properties: + response: + type: array + items: + $ref: '#/definitions/jvm-get-info' + jvms-put-body: + type: object + properties: + set: + type: object + jvms-post-body: + type: array + items: + $ref: '#/definitions/jvm-post-info' + + update-put-body: + type: array + description: 'An array of jvm ID strings' + items: + type: string + + tree-get-response: + type: object + properties: + systemId: + type: string + jvms: + type: array + items: + $ref: '#/definitions/jvm-get-info' +parameters: + system-id: + name: systemId + in: path + required: true + type: string + description: The system ID for the jvms + jvm-id: + name: jvmId + in: path + required: true + type: string + description: The ID of the jvm + timestamp: + name: timeStamp + in: path + required: true + type: integer + format: int64 + description: The UNIX timestamp in milliseconds to set the last_updated field for. + jvms-post-body: + name: body + in: body + description: The jvm information + required: true + schema: + $ref: '#/definitions/jvms-post-body' + jvms-put-body: + name: body + in: body + description: >- + The JSON object containing a 'set' object. This contains single item JSON + objects that specify the field to replace and the JSON value to replace with. + Must not include 'systemId' or 'jvmId' fields. Example { "set" : { + "field" : "value", "field2":{"object":"item"} } + required: true + schema: + $ref: '#/definitions/jvms-put-body' + update-put-body: + name: body + in: body + description: >- + An array of jvmIds for which to update the last_updated field. + required: true + schema: + $ref: '#/definitions/update-put-body' + limit: + name: limit + in: query + description: Limit of items to return. Example '1' + type: integer + required: false + default: 1 + offset: + name: offset + in: query + description: Offset of items to return. Example '0' + type: integer + required: false + default: 0 + sort: + name: sort + in: query + description: >- + Sort string. Comma separated list of fields prefixed with '+' for + ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot + notation for embedded documents. Example 'outer.inner' refers to field + inner contained in field outer. + type: string + required: false + query: + name: query + in: query + description: >- + Query string. Comma separated list of key, comparator, value pairs. + Comparator supports '==', '<=', '>=', '<', '>', '!='. Example + '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for + embedded documents. Example 'outer.inner' refers to field inner contained + in field outer. + type: string + required: false + include: + name: include + in: query + description: >- + Inclusion string. Comma separated list of fields to include in the + response. Example '?include=a,b' Fields use dot notation for embedded + documents. Example 'outer.inner' refers to field inner contained in field + outer. Cannot be used in combination with 'exclude' parameter Overriden by + 'exclude' parameter + type: string + required: false + exclude: + name: exclude + in: query + description: >- + Exclusion string. Comma separated list of fields to exclude in the + response. Example '?exclude=a,b' Fields use dot notation for embedded + documents. Example 'outer.inner' refers to field inner contained in field + outer. Cannot be used in combination with 'include' parameter; takes + precedence over 'include' parameter + type: string + required: false + alive-only: + name: aliveOnly + in: query + description: Whether or not to return only JVMs that are live + type: boolean + default: true + required: false \ No newline at end of file diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/resources/systems-swagger.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/resources/systems-swagger.json Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,283 @@ +{ + "swagger": "2.0", + "info": { + "version": "0.0.1", + "title": "Thermostat Web Gateway System Information API", + "license": { + "name": "GPL v2 with Classpath Exception", + "url": "http://www.gnu.org/licenses" + } + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json", + "text/html; charset=utf-8" + ], + "basePath": "/systems/0.0.1", + "paths": { + "/": { + "get": { + "description": "Get information for all systems.", + "parameters": [ + { + "$ref": "#/parameters/limit" + }, + { + "$ref": "#/parameters/offset" + }, + { + "$ref": "#/parameters/sort" + }, + { + "$ref": "#/parameters/include" + }, + { + "$ref": "#/parameters/exclude" + }, + { + "$ref": "#/parameters/query" + }, + { + "$ref": "#/parameters/alive" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/systems-get-response" + } + } + } + } + }, + "/systems/{systemId}": { + "parameters": [ + { + "$ref": "#/parameters/system-id" + } + ], + "get": { + "description": "Get information for system {systemId}.", + "parameters": [ + { + "$ref": "#/parameters/limit" + }, + { + "$ref": "#/parameters/offset" + }, + { + "$ref": "#/parameters/sort" + }, + { + "$ref": "#/parameters/include" + }, + { + "$ref": "#/parameters/exclude" + }, + { + "$ref": "#/parameters/query" + }, + { + "$ref": "#/parameters/alive" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/systems-get-response" + } + } + } + }, + "put": { + "description": "Update information for system {systemId}.", + "parameters": [ + { + "$ref": "#/parameters/systems-put-body" + }, + { + "$ref": "#/parameters/query" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "description": "Add information for system {systemId}", + "parameters": [ + { + "$ref": "#/parameters/system-info-array" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "description": "Delete information for system ID {systemId}.", + "parameters": [ + { + "$ref": "#/parameters/query" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "definitions": { + "systems-get-response": { + "type": "object", + "properties": { + "response": { + "$ref": "#/definitions/system-info-array" + } + } + }, + "system-info-array": { + "type": "array", + "items": { + "$ref": "#/definitions/system-info" + } + }, + "system-info": { + "type": "object", + "properties": { + "systemId": { + "type": "string" + }, + "agentId": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "osName": { + "type": "string" + }, + "osKernel": { + "type": "string" + }, + "osArch": { + "type": "string" + }, + "cpuCount": { + "type": "integer" + }, + "cpuModel": { + "type": "string" + }, + "totalMemory": { + "type": "integer", + "format": "int64" + }, + "timeCreated": { + "type": "integer", + "format": "int64" + }, + "lastUpdated": { + "type": "integer", + "format": "int64" + } + } + }, + "systems-put-body": { + "type": "object", + "properties": { + "set": { + "type": "object" + } + } + } + }, + "parameters": { + "system-id": { + "name": "systemId", + "in": "path", + "required": true, + "type": "string" + }, + "system-info-array": { + "name": "system-info-array", + "in": "body", + "description": "The system information", + "required": true, + "schema": { + "$ref": "#/definitions/system-info-array" + } + }, + "systems-put-body": { + "name": "body", + "in": "body", + "description": "The JSON object containing a 'set' object. This contains single item JSON objects that specify the field to replace and the JSON value to replace with. Must not include 'systemId' field. Example { \"set\" : { \"field\" : \"value\", \"field2\":{\"object\":\"item\"} }", + "required": true, + "schema": { + "$ref": "#/definitions/systems-put-body" + } + }, + "alive": { + "name": "alive", + "in": "query", + "description": "Whether to return only systems that are currently running", + "type": "boolean", + "required": false, + "default": true + }, + "limit": { + "name": "limit", + "in": "query", + "description": "Limit of items to return. Example '1'", + "type": "integer", + "required": false, + "default": 1 + }, + "offset": { + "name": "offset", + "in": "query", + "description": "Offset of items to return. Example '0'", + "type": "integer", + "required": true, + "default": 0 + }, + "sort": { + "name": "sort", + "in": "query", + "description": "Sort string. Comma separated list of fields prefixed with '+' for ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", + "type": "string", + "required": false + }, + "query": { + "name": "query", + "in": "query", + "description": "Query string. Comma separated list of key, comparator, value pairs. Comparator supports '==', '<=', '>=', '<', '>', '!='. Example '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer.", + "type": "string", + "required": false + }, + "include": { + "name": "include", + "in": "query", + "description": "Inclusion string. Comma separated list of fields to include in the response. Example '?include=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'exclude' parameter Overriden by 'exclude' parameter", + "type": "string", + "required": false + }, + "exclude": { + "name": "exclude", + "in": "query", + "description": "Exclusion string. Comma separated list of fields to exclude in the response. Example '?exclude=a,b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. Cannot be used in combination with 'include' parameter; takes precedence over 'include' parameter", + "type": "string", + "required": false + } + } +} diff -r e7a2adb465d1 -r dd0992bd51aa common/src/test/resources/systems-swagger.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/src/test/resources/systems-swagger.yaml Fri Sep 29 14:48:00 2017 -0400 @@ -0,0 +1,192 @@ +swagger: '2.0' +info: + version: 0.0.1 + title: Thermostat Web Gateway System Information API + license: + name: GPL v2 with Classpath Exception + url: 'http://www.gnu.org/licenses' +consumes: + - application/json +produces: + - application/json + - text/html; charset=utf-8 +basePath: /systems/0.0.1 +paths: + /: + get: + description: Get information for all systems. + parameters: + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/sort' + - $ref: '#/parameters/include' + - $ref: '#/parameters/exclude' + - $ref: '#/parameters/query' + - $ref: '#/parameters/alive' + responses: + '200': + description: OK + schema: + $ref: '#/definitions/systems-get-response' + /systems/{systemId}: + parameters: + - $ref: '#/parameters/system-id' + get: + description: Get information for system {systemId}. + parameters: + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/sort' + - $ref: '#/parameters/include' + - $ref: '#/parameters/exclude' + - $ref: '#/parameters/query' + - $ref: '#/parameters/alive' + responses: + '200': + description: OK + schema: + $ref: '#/definitions/systems-get-response' + put: + description: Update information for system {systemId}. + parameters: + - $ref: '#/parameters/systems-put-body' + - $ref: '#/parameters/query' + responses: + '200': + description: OK + post: + description: Add information for system {systemId} + parameters: + - $ref: '#/parameters/system-info-array' + responses: + '200': + description: OK + delete: + description: Delete information for system ID {systemId}. + parameters: + - $ref: '#/parameters/query' + responses: + '200': + description: OK +definitions: + systems-get-response: + type: object + properties: + response: + $ref: '#/definitions/system-info-array' + system-info-array: + type: array + items: + $ref: '#/definitions/system-info' + system-info: + type: object + properties: + systemId: + type: string + agentId: + type: string + hostname: + type: string + osName: + type: string + osKernel: + type: string + osArch: + type: string + cpuCount: + type: integer + cpuModel: + type: string + totalMemory: + type: integer + format: int64 + timeCreated: + type: integer + format: int64 + lastUpdated: + type: integer + format: int64 + systems-put-body: + type: object + properties: + "set": + type: object +parameters: + system-id: + name: systemId + in: path + required: true + type: string + system-info-array: + name: system-info-array + in: body + description: The system information + required: true + schema: + $ref: '#/definitions/system-info-array' + systems-put-body: + name: body + in: body + description: >- + The JSON object containing a 'set' object. This contains single item JSON + objects that specify the field to replace and the JSON value to replace with. + Must not include 'systemId' field. Example { "set" : { + "field" : "value", "field2":{"object":"item"} } + required: true + schema: + $ref: '#/definitions/systems-put-body' + alive: + name: alive + in: query + description: Whether to return only systems that are currently running + type: boolean + required: false + default: true + limit: + name: limit + in: query + description: Limit of items to return. Example '1' + type: integer + required: false + default: 1 + offset: + name: offset + in: query + description: Offset of items to return. Example '0' + type: integer + required: true + default: 0 + sort: + name: sort + in: query + description: Sort string. Comma separated list of fields prefixed with '+' for ascending or '-' for descending. Example '?sort=+a,-b' Fields use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. + type: string + required: false + query: + name: query + in: query + description: Query string. Comma separated list of key, comparator, value pairs. Comparator supports '==', '<=', '>=', '<', '>', '!='. Example '?query=a==b,c!=d'. Keys are fields in documents and use dot notation for embedded documents. Example 'outer.inner' refers to field inner contained in field outer. + type: string + required: false + include: + name: include + in: query + description: >- + Inclusion string. Comma separated list of fields to include in the + response. Example '?include=a,b' Fields use dot notation for embedded + documents. Example 'outer.inner' refers to field inner contained in field + outer. Cannot be used in combination with 'exclude' parameter Overriden by + 'exclude' parameter + type: string + required: false + exclude: + name: exclude + in: query + description: >- + Exclusion string. Comma separated list of fields to exclude in the + response. Example '?exclude=a,b' Fields use dot notation for embedded + documents. Example 'outer.inner' refers to field inner contained in field + outer. Cannot be used in combination with 'include' parameter; takes + precedence over 'include' parameter + type: string + required: false diff -r e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java --- a/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java --- a/common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * 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 e7a2adb465d1 -r dd0992bd51aa common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java --- a/common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java Thu Sep 28 10:50:29 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,253 +0,0 @@ -/* - * 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); - } -}