From 81a20cb0ea5be551db1ed74fd8846fd5ca392496 Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Mon, 29 Apr 2024 18:12:55 +0300 Subject: [PATCH] AbstractProperties --- .../main/java/oap/json/schema/JsonSchema.java | 31 +++++----- .../json/schema/ResourceSchemaStorage.java | 25 +++++--- .../java/oap/json/AbstractProperties.java | 37 +++++++++++ .../src/main/java/oap/ws/admin/SchemaWS.java | 23 +++++++ .../main/resources/META-INF/oap-module.conf | 8 +++ .../test/java/oap/ws/admin/SchemaWSTest.java | 62 +++++++++++++++++++ .../src/test/resources/application.test.conf | 7 ++- .../test/resources/schema/test-schema.conf | 6 ++ .../schema/test-schema/test-schema.conf | 5 ++ .../oap/ws/validate/JsonValidatorPeer.java | 6 +- pom.xml | 2 +- 11 files changed, 182 insertions(+), 30 deletions(-) create mode 100644 oap-stdlib/src/main/java/oap/json/AbstractProperties.java create mode 100644 oap-ws/oap-ws-admin-ws/src/main/java/oap/ws/admin/SchemaWS.java create mode 100644 oap-ws/oap-ws-admin-ws/src/test/java/oap/ws/admin/SchemaWSTest.java create mode 100644 oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema.conf create mode 100644 oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema/test-schema.conf diff --git a/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/JsonSchema.java b/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/JsonSchema.java index f4f4698522..0eb3b085e5 100644 --- a/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/JsonSchema.java +++ b/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/JsonSchema.java @@ -98,7 +98,7 @@ public static void add( AbstractJsonSchemaValidator validator ) { } private Object parseWithTemplate( String schema, SchemaStorage storage ) { - var obj = Binder.hoconWithoutSystemProperties.unmarshal( Object.class, schema ); + Object obj = Binder.hoconWithoutSystemProperties.unmarshal( Object.class, schema ); resolveTemplates( obj, storage ); log.trace( "schema = {}", Binder.json.marshal( obj ) ); return obj; @@ -107,13 +107,13 @@ private Object parseWithTemplate( String schema, SchemaStorage storage ) { @SuppressWarnings( "unchecked" ) private void resolveTemplates( Object obj, SchemaStorage storage ) { if( obj instanceof Map ) { - var map = ( Map ) obj; - var templatePath = map.get( "template" ); + Map map = ( Map ) obj; + Object templatePath = map.get( "template" ); if( templatePath != null ) { Preconditions.checkArgument( templatePath instanceof String ); - var templateStr = storage.get( ( String ) templatePath ); - var templateMap = Binder.hoconWithoutSystemProperties.unmarshal( Object.class, templateStr ); + String templateStr = storage.get( ( String ) templatePath ); + Object templateMap = Binder.hoconWithoutSystemProperties.unmarshal( Object.class, templateStr ); log.trace( "template path = {}, template = {}", templatePath, templateStr ); map.remove( "template" ); @@ -121,8 +121,7 @@ private void resolveTemplates( Object obj, SchemaStorage storage ) { } map.values().forEach( obj1 -> resolveTemplates( obj1, storage ) ); - } else if( obj instanceof List ) { - var list = ( List ) obj; + } else if( obj instanceof List list ) { list.forEach( obj1 -> resolveTemplates( obj1, storage ) ); } } @@ -132,15 +131,17 @@ private void addTemplate( Object sl, Object sr ) { if( sl instanceof Map ) { Preconditions.checkArgument( sr instanceof Map ); - var mapl = ( Map ) sl; - var mapr = ( Map ) sr; - mapr.forEach( ( key, vr ) -> { - var vl = mapl.get( key ); + Map mapl = ( Map ) sl; + Map mapr = ( Map ) sr; + for( Map.Entry entry : mapr.entrySet() ) { + Object key = entry.getKey(); + Object vr = entry.getValue(); + Object vl = mapl.get( key ); if( vl != null ) { addTemplate( vl, vr ); } else mapl.put( key, vr ); - } ); + } } } @@ -194,7 +195,7 @@ AbstractSchemaASTWrapper parse( String schema, SchemaStorage storage ) { } AbstractSchemaASTWrapper parse( String schemaName, String schema, String rootPath, SchemaStorage storage ) { - var context = new JsonSchemaParserContext( + JsonSchemaParserContext context = new JsonSchemaParserContext( schemaName, null, "", this::parse, @@ -204,7 +205,7 @@ AbstractSchemaASTWrapper parse( String schemaName, String schema, String rootPat } private AbstractSchemaASTWrapper parse( JsonSchemaParserContext context ) { - var schemaParser = validators.get( context.schemaType ); + AbstractJsonSchemaValidator> schemaParser = validators.get( context.schemaType ); if( schemaParser != null ) { return schemaParser.parse( context ); } else { @@ -215,7 +216,7 @@ private AbstractSchemaASTWrapper parse( JsonSchemaParserContext context ) { } public List partialValidate( Object root, Object json, String path, boolean ignoreRequiredDefault ) { - var traverseResult = SchemaPath.traverse( this.schema, path ); + SchemaPath.Result traverseResult = SchemaPath.traverse( this.schema, path ); final AbstractSchemaAST partialSchema = traverseResult.schema .orElseThrow( () -> new ValidationSyntaxException( "path " + path + " not found" ) ); diff --git a/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/ResourceSchemaStorage.java b/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/ResourceSchemaStorage.java index e3ad229f53..715f76ad07 100644 --- a/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/ResourceSchemaStorage.java +++ b/oap-formats/oap-json/oap-json-schema/src/main/java/oap/json/schema/ResourceSchemaStorage.java @@ -31,6 +31,7 @@ import org.apache.commons.io.FilenameUtils; import java.util.ArrayList; +import java.util.List; import java.util.Map; public final class ResourceSchemaStorage implements SchemaStorage { @@ -41,20 +42,24 @@ private ResourceSchemaStorage() { @Override public String get( String name ) { - var ext = FilenameUtils.getExtension( name ); - var prefix = FilenameUtils.removeExtension( name ); - var fileName = FilenameUtils.removeExtension( FilenameUtils.getName( name ) ); + String ext = FilenameUtils.getExtension( name ); + String prefix = FilenameUtils.removeExtension( name ); + String fileName = FilenameUtils.removeExtension( FilenameUtils.getName( name ) ); - var conf = Resources.readOrThrow( getClass(), name, ContentReader.ofString() ); - if( "yaml".equalsIgnoreCase( ext ) ) conf = Binder.json.marshal( Binder.yaml.unmarshal( Map.class, conf ) ); + String conf = Resources.readOrThrow( getClass(), name, ContentReader.ofString() ); + if( "yaml".equalsIgnoreCase( ext ) ) { + conf = Binder.json.marshal( Binder.yaml.unmarshal( Map.class, conf ) ); + } - var extConf = Resources.readStrings( getClass(), prefix + "/" + fileName + ".conf" ); - var extJson = Resources.readStrings( getClass(), prefix + "/" + fileName + ".json" ); - var extYaml = Resources.readStrings( getClass(), prefix + "/" + fileName + ".yaml" ); + List extConf = Resources.readStrings( getClass(), prefix + "/" + fileName + ".conf" ); + List extJson = Resources.readStrings( getClass(), prefix + "/" + fileName + ".json" ); + List extYaml = Resources.readStrings( getClass(), prefix + "/" + fileName + ".yaml" ); - if( extConf.isEmpty() && extJson.isEmpty() && extYaml.isEmpty() ) return conf; + if( extConf.isEmpty() && extJson.isEmpty() && extYaml.isEmpty() ) { + return conf; + } - var list = new ArrayList(); + ArrayList list = new ArrayList<>(); list.addAll( extConf ); list.addAll( extJson ); list.addAll( Lists.map( extYaml, y -> Binder.json.marshal( Binder.yaml.unmarshal( Map.class, y ) ) ) ); diff --git a/oap-stdlib/src/main/java/oap/json/AbstractProperties.java b/oap-stdlib/src/main/java/oap/json/AbstractProperties.java new file mode 100644 index 0000000000..dc2f6f9dde --- /dev/null +++ b/oap-stdlib/src/main/java/oap/json/AbstractProperties.java @@ -0,0 +1,37 @@ +package oap.json; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import oap.json.properties.PropertiesDeserializer; + +import javax.annotation.Nullable; +import java.util.LinkedHashMap; +import java.util.Map; + +@ToString +@EqualsAndHashCode +public abstract class AbstractProperties { + @JsonIgnore + private final LinkedHashMap properties = new LinkedHashMap<>(); + + @JsonAnySetter + @JsonDeserialize( contentUsing = PropertiesDeserializer.class ) + public void putProperty( String name, Object value ) { + properties.put( name, value ); + } + + @JsonAnyGetter + public Map getProperties() { + return properties; + } + + @SuppressWarnings( "unchecked" ) + @Nullable + public T getProperty( String property ) { + return ( T ) properties.get( property ); + } +} diff --git a/oap-ws/oap-ws-admin-ws/src/main/java/oap/ws/admin/SchemaWS.java b/oap-ws/oap-ws-admin-ws/src/main/java/oap/ws/admin/SchemaWS.java new file mode 100644 index 0000000000..6792bb5368 --- /dev/null +++ b/oap-ws/oap-ws-admin-ws/src/main/java/oap/ws/admin/SchemaWS.java @@ -0,0 +1,23 @@ +package oap.ws.admin; + +import oap.http.Http; +import oap.json.Binder; +import oap.json.schema.ResourceSchemaStorage; +import oap.ws.Response; +import oap.ws.WsMethod; +import oap.ws.WsParam; + +import java.util.Map; + +import static oap.ws.WsParam.From.QUERY; + +public class SchemaWS { + @WsMethod( path = "/" ) + public Response getSchema( @WsParam( from = QUERY ) String path ) { + String json = ResourceSchemaStorage.INSTANCE.get( path ); + + return new Response( Http.StatusCode.OK ) + .withBody( Binder.json.marshalWithDefaultPrettyPrinter( Binder.json.unmarshal( Map.class, json ) ), true ) + .withContentType( Http.ContentType.APPLICATION_JSON ); + } +} diff --git a/oap-ws/oap-ws-admin-ws/src/main/resources/META-INF/oap-module.conf b/oap-ws/oap-ws-admin-ws/src/main/resources/META-INF/oap-module.conf index c446dba608..dd11bff783 100644 --- a/oap-ws/oap-ws-admin-ws/src/main/resources/META-INF/oap-module.conf +++ b/oap-ws/oap-ws-admin-ws/src/main/resources/META-INF/oap-module.conf @@ -19,4 +19,12 @@ services { port = httpprivate } } + + ws-schema { + implementation = oap.ws.admin.SchemaWS + ws-service { + path = system/admin/schema + port = httpprivate + } + } } diff --git a/oap-ws/oap-ws-admin-ws/src/test/java/oap/ws/admin/SchemaWSTest.java b/oap-ws/oap-ws-admin-ws/src/test/java/oap/ws/admin/SchemaWSTest.java new file mode 100644 index 0000000000..bdd70c3213 --- /dev/null +++ b/oap-ws/oap-ws-admin-ws/src/test/java/oap/ws/admin/SchemaWSTest.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.ws.admin; + +import oap.application.testng.KernelFixture; +import oap.testng.Fixtures; +import oap.testng.TestDirectoryFixture; +import org.testng.annotations.Test; + +import static oap.http.test.HttpAsserts.assertGet; +import static oap.io.Resources.urlOrThrow; + +public class SchemaWSTest extends Fixtures { + private final KernelFixture kernel; + + public SchemaWSTest() { + TestDirectoryFixture testDirectoryFixture = fixture( new TestDirectoryFixture() ); + kernel = fixture( new KernelFixture( testDirectoryFixture, urlOrThrow( getClass(), "/application.test.conf" ) ) ); + } + + @Test + public void testSchema() { + assertGet( kernel.httpUrl( "/system/admin/schema?path=/schema/test-schema.conf" ) ) + .isOk() + .respondedJson( """ + { + "properties" : { + "a" : { + "type" : "string" + }, + "b" : { + "type" : "string" + } + }, + "type" : "object" + } + """ ); + + } +} diff --git a/oap-ws/oap-ws-admin-ws/src/test/resources/application.test.conf b/oap-ws/oap-ws-admin-ws/src/test/resources/application.test.conf index b794478f8a..0b9b50d9ab 100644 --- a/oap-ws/oap-ws-admin-ws/src/test/resources/application.test.conf +++ b/oap-ws/oap-ws-admin-ws/src/test/resources/application.test.conf @@ -1,7 +1,12 @@ boot.main = oap-ws-admin-ws-test services { - oap.oap-http-server.parameters.port = ${TEST_HTTP_PORT} + oap-http { + oap-http-server.parameters { + defaultPort.httpPort = ${TEST_HTTP_PORT} + additionalHttpPorts.httpprivate = ${TEST_HTTP_PORT} + } + } oap-ws.session-manager.parameters.cookieDomain: "" } diff --git a/oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema.conf b/oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema.conf new file mode 100644 index 0000000000..8dc0a385b5 --- /dev/null +++ b/oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema.conf @@ -0,0 +1,6 @@ +{ + type = object + properties { + a.type = string + } +} diff --git a/oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema/test-schema.conf b/oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema/test-schema.conf new file mode 100644 index 0000000000..e2031fa465 --- /dev/null +++ b/oap-ws/oap-ws-admin-ws/src/test/resources/schema/test-schema/test-schema.conf @@ -0,0 +1,5 @@ +{ + properties { + b.type = string + } +} diff --git a/oap-ws/oap-ws/src/main/java/oap/ws/validate/JsonValidatorPeer.java b/oap-ws/oap-ws/src/main/java/oap/ws/validate/JsonValidatorPeer.java index b5f61ad455..378e2a519e 100644 --- a/oap-ws/oap-ws/src/main/java/oap/ws/validate/JsonValidatorPeer.java +++ b/oap-ws/oap-ws/src/main/java/oap/ws/validate/JsonValidatorPeer.java @@ -50,8 +50,8 @@ public JsonValidatorPeer( WsValidateJson validate, Reflection.Method targetMetho @Override public ValidationErrors validate( Object value, Map originalValues ) { try { - var mapValue = Binder.json.unmarshal( Map.class, ( String ) value ); - var factory = getJsonSchema( originalValues ); + Map mapValue = Binder.json.unmarshal( Map.class, ( String ) value ); + JsonSchema factory = getJsonSchema( originalValues ); return ValidationErrors.errors( factory.validate( mapValue, validate.ignoreRequired() ) ); } catch( JsonException e ) { throw new WsClientException( e.getMessage(), e ); @@ -59,7 +59,7 @@ public ValidationErrors validate( Object value, Map originalValues ) { - if( !dynamic ) return cache.computeIfAbsent( Strings.UNDEFINED, s -> JsonSchema.schema( schemaRef ) ); + if( !dynamic ) return cache.computeIfAbsent( Strings.UNDEFINED, _ -> JsonSchema.schema( schemaRef ) ); log.trace( "dynamic schema ref {}", schemaRef ); diff --git a/pom.xml b/pom.xml index b0c1b34b2c..fa06e9e5aa 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ - 22.1.4 + 22.1.5 21.0.0 21.0.1