changeset 18:5100a9b678f4

Initial Schema related services This patch adds initial support for schema validation and exposition services. I am down as a reviewer since the initial code is from neugens, modified by me before this first commit. Reviewed-by: neugens, stooke Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-August/024759.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024823.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024918.html
author Simon Tooke <stooke@redhat.com>
date Fri, 08 Sep 2017 13:24:37 -0400
parents 85d12e67675d
children ddccb0f61879
files common/pom.xml common/type-system/pom.xml common/type-system/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java pom.xml thermostat-ng.sh
diffstat 19 files changed, 1761 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/pom.xml	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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
+ <http://www.gnu.org/licenses/>.
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-base</artifactId>
+        <version>1.99.12-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>base-common</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Thermostat Base Common</name>
+
+    <modules>
+        <module>type-system</module>
+    </modules>
+</project>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/pom.xml	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>base-common</artifactId>
+        <version>1.99.12-SNAPSHOT</version>
+    </parent>
+
+    <groupId>com.redhat.thermostat.lang.schema</groupId>
+    <artifactId>thermostat-lang-schema</artifactId>
+    <version>1.99.12-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <thermostat.java.version>1.7</thermostat.java.version>
+
+        <!-- OSGi stuff -->
+        <osgi.core.version>4.3.1</osgi.core.version>
+        <osgi.compendium.version>4.3.1</osgi.compendium.version>
+        <osgi.compendium.osgi-version>4.3.1.201210102024</osgi.compendium.osgi-version>
+        <osgi.compendium.bundle.symbolic-name>osgi.cmpn</osgi.compendium.bundle.symbolic-name>
+        <felix.framework.version>4.2.0</felix.framework.version>
+        <felix.scr.version>1.8.2</felix.scr.version>
+        <felix.scr.annotations.version>1.9.12</felix.scr.annotations.version>
+
+        <gson.version>2.2.2</gson.version>
+        <junit.version>4.10</junit.version>
+
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <!--
+                     3.6+ is JDK 9 compatible. See:
+                     https://cwiki.apache.org/confluence/display/MAVEN/Java+9+-+Jigsaw
+                 -->
+                <version>3.6.1</version>
+                <configuration>
+                    <fork>true</fork>
+                    <meminitial>128m</meminitial>
+                    <maxmem>1024m</maxmem>
+                    <source>${thermostat.java.version}</source>
+                    <target>${thermostat.java.version}</target>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>com.redhat.thermostat.lang.schema</Bundle-SymbolicName>
+                        <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+                        <Export-Package>
+                            com.redhat.thermostat.lang.schema,
+                            com.redhat.thermostat.lang.schema.models,
+                            com.redhat.thermostat.lang.schema.annotations
+                        </Export-Package>
+                        <!-- TODO: For the thread tab (i.e. thread plug-in) the web server
+                             bundle requires model classes provided by said bundle. Since
+                             no explicit imports (in the Java import sense) are in our code,
+                             the maven bundle plugin seems to fail on us. Therefore we need
+                             these explicit Import-Package instructions. If not there, this
+                             results in class not found exceptions. This may be a problem
+                             for user-provided bundles which contribute DAOs/models in the
+                             same way. -->
+                        <Private-Package>
+                            com.redhat.thermostat.lang.schema.internal,
+                        </Private-Package>
+                        <!-- Do not autogenerate uses clauses in Manifests -->
+                        <_nouses>true</_nouses>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr</artifactId>
+            <version>${felix.scr.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>${felix.framework.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <version>${felix.scr.annotations.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>${gson.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/JSONService.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaBuilder.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/SchemaValidationException.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,24 @@
+package com.redhat.thermostat.lang.schema;
+
+/**
+ */
+public class SchemaValidationException extends RuntimeException {
+    public SchemaValidationException() {
+    }
+
+    public SchemaValidationException(String message) {
+        super(message);
+    }
+
+    public SchemaValidationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SchemaValidationException(Throwable cause) {
+        super(cause);
+    }
+
+    public SchemaValidationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Maximum.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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. <br />
+ * 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Minimum.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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. <br />
+ * 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Schema.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/annotations/Type.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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 "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/JSONServiceImpl.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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<Object> {
+
+        @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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderImpl.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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<FieldProperties> properties = new TreeSet<>(new Comparator<FieldProperties>() {
+            @Override
+            public int compare(FieldProperties o1, FieldProperties o2) {
+                return o1.toString().compareTo(o2.toString());
+            }
+        });
+        Set<String> required = new TreeSet<>();
+    }
+
+    private GsonBuilder schemaBuilder;
+
+    private Map<String, String> schemas;
+    private Map<String, SchemaDefinition> 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<Object> {
+
+        @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");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Id.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Pid.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/ProcessState.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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 {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/main/java/com/redhat/thermostat/lang/schema/models/Timestamp.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/JSONServiceTest.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/type-system/src/test/java/com/redhat/thermostat/lang/schema/internal/SchemaBuilderTest.java	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pom.xml	Fri Sep 08 13:24:37 2017 -0400
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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
+ <http://www.gnu.org/licenses/>.
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-base</artifactId>
+    <version>1.99.12-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>Thermostat Base</name>
+    <url>${thermostat.url}</url>
+
+    <properties>
+        <main.basedir>${project.basedir}</main.basedir>
+        <maven.build.timestamp.format>yyyy-MM-dd</maven.build.timestamp.format>
+        <thermostat.releasedate>${maven.build.timestamp}</thermostat.releasedate>
+        <thermostat.email>thermostat@icedtea.classpath.org</thermostat.email>
+        <thermostat.url>http://icedtea.classpath.org/thermostat/</thermostat.url>
+        <thermostat.bug.url>http://icedtea.classpath.org/bugzilla/enter_bug.cgi?product=Thermostat</thermostat.bug.url>
+        <thermostat.user.guide>http://icedtea.classpath.org/wiki/Thermostat/UserGuide</thermostat.user.guide>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <thermostat.build.directory>target</thermostat.build.directory>
+        <thermostat.java.version>1.7</thermostat.java.version>
+        <thermostat.jdk.home>${java.home}</thermostat.jdk.home>
+
+        <junit.version>4.10</junit.version>
+        <mockito.version>1.9.5</mockito.version>
+        <gson.version>2.6.2</gson.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                </configuration>
+                <!--
+                     3.6+ is JDK 9 compatible. See:
+                     https://cwiki.apache.org/confluence/display/MAVEN/Java+9+-+Jigsaw
+                 -->
+                <version>3.6.1</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>1.4.0</version>
+            </plugin>
+        </plugins>
+    </build>
+
+    <modules>
+        <module>common</module>
+    </modules>
+</project>
--- a/thermostat-ng.sh	Thu Aug 31 15:20:47 2017 +0200
+++ b/thermostat-ng.sh	Fri Sep 08 13:24:37 2017 -0400
@@ -193,6 +193,10 @@
   mvn clean verify
 }
 
+mvn_install() {
+  mvn clean verify install
+}
+
 npm_build() {
   # setup environment variables
   export NODE_ENV=testing
@@ -225,6 +229,12 @@
   fi
 }
 
+build_support_libs() {
+  for i in "${SUPPORT_LIBS_ROOTS[@]}"
+  do
+      build "$i" mvn_install
+  done
+}
 
 build_agent() {
   build "$AGENT_ROOT" mvn_build
@@ -291,6 +301,7 @@
 AGENT_ROOT="${TOP_DIR}/agent"
 WEB_CLIENT_ROOT="${TOP_DIR}/web-client"
 GATEWAY_URL="$(get_gateway_url)"
+SUPPORT_LIBS_ROOTS="${TOP_DIR}/common"
 
 DO_BUILD=${BUILD:-true}
 RUN_DATA_DIR="$TOP_DIR/data"
@@ -307,6 +318,7 @@
 WEB_GATEWAY=true
 WEB_CLIENT=true
 AGENT=true
+SUPPORT_LIBS=true
 
 HELP_STRING="\nUSAGE: $0 [BUILD_OPTION]
     -a
@@ -325,12 +337,14 @@
   WEB_GATEWAY=true
   WEB_CLIENT=true
   AGENT=true
+  SUPPORT_LIBS=true
 }
 
 mark_nothing_to_be_built() {
   WEB_GATEWAY=false
   WEB_CLIENT=false
   AGENT=false
+  SUPPORT_LIBS=false
 }
 
 # Check whether the component passed as the first argument of this function exists.
@@ -399,6 +413,9 @@
 }
 
 build_all_requested_components() {
+  if [ "$SUPPORT_LIBS" = "true" ]; then
+    build_support_libs
+  fi
   if [ "$WEB_GATEWAY" = "true" ]; then
     build_web_gateway; ensure_web_client_present_in_gateway
   fi