This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/johnzon.git


The following commit(s) were added to refs/heads/master by this push:
     new 7001b97  [JOHNZON-329] make jsonlogic completionstage friendly
7001b97 is described below

commit 7001b971b72a7352f2b27f1b9a445e6fe533dd47
Author: Romain Manni-Bucau <rmannibu...@gmail.com>
AuthorDate: Thu Dec 17 10:23:03 2020 +0100

    [JOHNZON-329] make jsonlogic completionstage friendly
---
 .../org/apache/johnzon/jsonb/CdiAdapterTest.java   | 24 ++++--
 .../johnzon/jsonb/JohnzonConverterInJsonbTest.java |  4 +-
 .../apache/johnzon/jsonlogic/JohnzonJsonLogic.java | 41 +++++++++-
 .../spi/{Operator.java => AsyncOperator.java}      | 23 +++++-
 .../org/apache/johnzon/jsonlogic/spi/Operator.java | 14 ++++
 .../johnzon/jsonlogic/JohnzonJsonLogicTest.java    | 90 ++++++++++++++++++++++
 pom.xml                                            | 15 ++--
 7 files changed, 191 insertions(+), 20 deletions(-)

diff --git 
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java 
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
index 79685bb..d071541 100644
--- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
@@ -20,10 +20,14 @@ package org.apache.johnzon.jsonb;
 
 import org.apache.webbeans.config.WebBeansContext;
 import org.apache.webbeans.config.WebBeansFinder;
-import org.apache.webbeans.lifecycle.test.OpenWebBeansTestLifeCycle;
-import 
org.apache.webbeans.lifecycle.test.OpenWebBeansTestMetaDataDiscoveryService;
+import org.apache.webbeans.corespi.se.DefaultScannerService;
+import org.apache.webbeans.lifecycle.StandaloneLifeCycle;
 import org.apache.webbeans.proxy.OwbNormalScopeProxy;
+import org.apache.webbeans.spi.ContainerLifecycle;
+import org.apache.webbeans.spi.ScannerService;
 import org.apache.webbeans.util.WebBeansUtil;
+import org.apache.xbean.finder.AnnotationFinder;
+import org.apache.xbean.finder.archive.ClassesArchive;
 import org.junit.Test;
 
 import javax.enterprise.context.ApplicationScoped;
@@ -32,8 +36,9 @@ import javax.json.bind.Jsonb;
 import javax.json.bind.JsonbBuilder;
 import javax.json.bind.adapter.JsonbAdapter;
 import javax.json.bind.annotation.JsonbTypeAdapter;
+import java.util.Properties;
 
-import static java.util.Arrays.asList;
+import static java.util.Collections.singletonMap;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -42,10 +47,14 @@ public class CdiAdapterTest {
     @Test
     public void run() {
         WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader());
-        final OpenWebBeansTestLifeCycle testLifecycle = new 
OpenWebBeansTestLifeCycle();
-        final WebBeansContext ctx = WebBeansContext.currentInstance();
-        final OpenWebBeansTestMetaDataDiscoveryService discoveryService = 
OpenWebBeansTestMetaDataDiscoveryService.class.cast(ctx.getScannerService());
-        discoveryService.deployClasses(asList(Service.class, 
ModelAdapter.class));
+        final ContainerLifecycle testLifecycle = new StandaloneLifeCycle();
+        new WebBeansContext(singletonMap(
+                ScannerService.class, new DefaultScannerService() {
+                    @Override
+                    protected AnnotationFinder initFinder() {
+                        return new AnnotationFinder(new 
ClassesArchive(Service.class, ModelAdapter.class));
+                    }
+                }), new Properties());
         testLifecycle.startApplication(null);
         try {
             Jsonb jsonb = JsonbBuilder.create();
@@ -57,6 +66,7 @@ public class CdiAdapterTest {
             }
         } finally {
             testLifecycle.stopApplication(null);
+            
WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader());
         }
     }
 
diff --git 
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
 
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
index c72cac5..4ce2e13 100644
--- 
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
+++ 
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
@@ -53,7 +53,7 @@ public class JohnzonConverterInJsonbTest {
         assertNotNull(json);
 
         TestDTO deserialized = jsonb.fromJson(json, TestDTO.class);
-        assertEquals(dto.instant, deserialized.instant);
+        assertEquals(dto.instant.toEpochMilli(), 
deserialized.instant.toEpochMilli());
     }
 
     @Test
@@ -67,7 +67,7 @@ public class JohnzonConverterInJsonbTest {
         assertNotNull(json);
 
         TestDTOWithOC deserialized = jsonb.fromJson(json, TestDTOWithOC.class);
-        assertEquals(deserialized.dto.instant, dto.dto.instant);
+        assertEquals(deserialized.dto.instant.toEpochMilli(), 
dto.dto.instant.toEpochMilli());
     }
 
     public static class TestDTOWithOC {
diff --git 
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java
 
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java
index 691146c..9691c82 100644
--- 
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java
+++ 
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java
@@ -35,12 +35,15 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
 import java.util.function.BiPredicate;
 import java.util.stream.Collector;
 import java.util.stream.DoubleStream;
 import java.util.stream.Stream;
 
 import static java.util.Collections.emptyMap;
+import static java.util.concurrent.CompletableFuture.completedFuture;
 import static java.util.stream.Collectors.joining;
 
 public class JohnzonJsonLogic {
@@ -82,16 +85,42 @@ public class JohnzonJsonLogic {
 
         final Set<String> keys = object.keySet();
         if (keys.size() != 1) {
-            throw new IllegalArgumentException("Invalid argument, multiple 
keys found: " + keys);
+            throw invalidArgument(keys);
         }
         final String operator = keys.iterator().next();
         final Operator impl = operators.get(operator);
         if (impl == null) {
-            throw new IllegalArgumentException("Missing operator '" + operator 
+ "'");
+            throw missingOperator(operator);
         }
         return impl.apply(this, object.get(operator), args);
     }
 
+    public CompletionStage<JsonValue> applyStage(final JsonValue logic, final 
JsonValue args) {
+        if (logic.getValueType() != JsonValue.ValueType.OBJECT) {
+            return completedFuture(logic);
+        }
+
+        final JsonObject object = logic.asJsonObject();
+        if (object.size() > 1) {
+            return completedFuture(object);
+        }
+
+        final Set<String> keys = object.keySet();
+        if (keys.size() != 1) {
+            final CompletableFuture<JsonValue> promise = new 
CompletableFuture<>();
+            promise.completeExceptionally(invalidArgument(keys));
+            return promise;
+        }
+        final String operator = keys.iterator().next();
+        final Operator impl = operators.get(operator);
+        if (impl == null) {
+            final CompletableFuture<JsonValue> promise = new 
CompletableFuture<>();
+            promise.completeExceptionally(missingOperator(operator));
+            return promise;
+        }
+        return impl.applyStage(this, object.get(operator), args);
+    }
+
     public boolean isTruthy(final JsonValue value) {
         return !isFalsy(value);
     }
@@ -206,6 +235,14 @@ public class JohnzonJsonLogic {
         return this;
     }
 
+    private IllegalArgumentException invalidArgument(final Set<String> keys) {
+        return new IllegalArgumentException("Invalid argument, multiple keys 
found: " + keys);
+    }
+
+    private IllegalArgumentException missingOperator(final String operator) {
+        return new IllegalArgumentException("Missing operator '" + operator + 
"'");
+    }
+
     private JsonValue minImpl(final JohnzonJsonLogic logic, final JsonValue 
config, final JsonValue params) {
         if (config.getValueType() != JsonValue.ValueType.ARRAY) {
             throw new IllegalArgumentException("min only supports arrays: '" + 
config + "'");
diff --git 
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
 
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/AsyncOperator.java
similarity index 52%
copy from 
johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
copy to 
johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/AsyncOperator.java
index 8531e0b..42e2d22 100644
--- 
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
+++ 
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/AsyncOperator.java
@@ -21,8 +21,27 @@ package org.apache.johnzon.jsonlogic.spi;
 import org.apache.johnzon.jsonlogic.JohnzonJsonLogic;
 
 import javax.json.JsonValue;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
 
 @FunctionalInterface
-public interface Operator {
-    JsonValue apply(JohnzonJsonLogic logic, JsonValue config, JsonValue 
params);
+public interface AsyncOperator extends Operator {
+    @Override
+    CompletionStage<JsonValue> applyStage(JohnzonJsonLogic logic, JsonValue 
config, JsonValue params);
+
+    @Override
+    default JsonValue apply(JohnzonJsonLogic logic, JsonValue config, 
JsonValue params) {
+        try {
+            return applyStage(logic, config, 
params).toCompletableFuture().get();
+        } catch (final InterruptedException e) {
+            Thread.currentThread().interrupt();
+            return null;
+        } catch (ExecutionException e) {
+            final Throwable cause = e.getCause();
+            if (RuntimeException.class.isInstance(cause)) {
+                throw RuntimeException.class.cast(cause);
+            }
+            throw new IllegalStateException(cause);
+        }
+    }
 }
diff --git 
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
 
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
index 8531e0b..a66c16f 100644
--- 
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
+++ 
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
@@ -21,8 +21,22 @@ package org.apache.johnzon.jsonlogic.spi;
 import org.apache.johnzon.jsonlogic.JohnzonJsonLogic;
 
 import javax.json.JsonValue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+
+import static java.util.concurrent.CompletableFuture.completedFuture;
 
 @FunctionalInterface
 public interface Operator {
+    default CompletionStage<JsonValue> applyStage(JohnzonJsonLogic logic, 
JsonValue config, JsonValue params) {
+        try {
+            return completedFuture(apply(logic, config, params));
+        } catch (final RuntimeException re) {
+            final CompletableFuture<JsonValue> promise = new 
CompletableFuture<>();
+            promise.completeExceptionally(re);
+            return promise;
+        }
+    }
+
     JsonValue apply(JohnzonJsonLogic logic, JsonValue config, JsonValue 
params);
 }
diff --git 
a/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java
 
b/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java
index 49295b3..f126cfd 100644
--- 
a/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java
+++ 
b/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java
@@ -18,12 +18,18 @@
  */
 package org.apache.johnzon.jsonlogic;
 
+import org.apache.johnzon.jsonlogic.spi.AsyncOperator;
+import org.apache.johnzon.jsonlogic.spi.Operator;
 import org.junit.Test;
 
 import javax.json.Json;
 import javax.json.JsonBuilderFactory;
 import javax.json.JsonObject;
 import javax.json.JsonValue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
 
 import static java.util.Collections.emptyMap;
 import static org.junit.Assert.assertEquals;
@@ -33,6 +39,90 @@ public class JohnzonJsonLogicTest {
     private final JsonBuilderFactory builderFactory = 
Json.createBuilderFactory(emptyMap());
 
     @Test
+    public void stage() throws InterruptedException {
+        // if the async exec is too immediate we will execute the thenAccept 
callback in main thread
+        // which is not the goal of this test so let's ensure we are in the 
expected case
+        final CountDownLatch waitChainReady = new CountDownLatch(1);
+
+        final JohnzonJsonLogic jsonLogic = new JohnzonJsonLogic()
+                .registerOperator("async", new Operator() {
+                    @Override
+                    public CompletionStage<JsonValue> applyStage(final 
JohnzonJsonLogic logic,
+                                                                 final 
JsonValue config,
+                                                                 final 
JsonValue params) {
+                        return logic.applyStage(
+                                
builderFactory.createObjectBuilder().add("async2", "ok").build(),
+                                builderFactory.createObjectBuilder().add("p2", 
"1").build())
+                                .thenApplyAsync(
+                                        previous -> 
builderFactory.createObjectBuilder()
+                                                .add("thread", 
Thread.currentThread().getName())
+                                                .add("config", config)
+                                                .add("params", params)
+                                                .add("exec2", previous)
+                                                .build(),
+                                        r -> new Thread(r, "async").start());
+                    }
+
+                    @Override
+                    public JsonValue apply(final JohnzonJsonLogic logic, final 
JsonValue config, final JsonValue params) {
+                        throw new UnsupportedOperationException();
+                    }
+                })
+                .registerOperator("async2", new AsyncOperator() {
+                    @Override
+                    public CompletionStage<JsonValue> applyStage(final 
JohnzonJsonLogic logic,
+                                                                 final 
JsonValue config,
+                                                                 final 
JsonValue params) {
+                        return CompletableFuture.supplyAsync(() -> {
+                            try {
+                                waitChainReady.await();
+                            } catch (final InterruptedException e) {
+                                Thread.currentThread().interrupt();
+                            }
+                            return builderFactory.createObjectBuilder()
+                                    .add("thread2", 
Thread.currentThread().getName())
+                                    .add("config2", config)
+                                    .add("params2", params)
+                                    .build();
+                        }, r -> new Thread(r, "async2").start());
+                    }
+
+                    @Override
+                    public JsonValue apply(final JohnzonJsonLogic logic, final 
JsonValue config, final JsonValue params) {
+                        throw new UnsupportedOperationException();
+                    }
+                });
+
+        final CountDownLatch latch = new CountDownLatch(1); // if we use 
Future.get we break stage threading
+        final AtomicReference<JsonValue> output = new AtomicReference<>();
+        jsonLogic
+                .applyStage(
+                        builderFactory.createObjectBuilder()
+                                .add("async", "a")
+                                .build(),
+                        builderFactory.createObjectBuilder()
+                                .add("p1", "0")
+                                .build())
+                .thenAccept(result -> {
+                    output.set(builderFactory.createObjectBuilder()
+                            .add("exec1", result)
+                            .add("thenSyncThread", 
Thread.currentThread().getName())
+                            .build());
+                    latch.countDown();
+                });
+        waitChainReady.countDown();
+        latch.await();
+        assertEquals("" +
+                        "{" +
+                        
"\"exec1\":{\"thread\":\"async\",\"config\":\"a\",\"params\":{\"p1\":\"0\"}," +
+                        
"\"exec2\":{\"thread2\":\"async2\",\"config2\":\"ok\",\"params2\":{\"p2\":\"1\"}}},"
 +
+                        "\"thenSyncThread\":\"async\"" +
+                        "}" +
+                        "",
+                output.get().toString());
+    }
+
+    @Test
     public void varObjectString() {
         assertEquals(Json.createValue("b"), jsonLogic.apply(
                 builderFactory.createObjectBuilder()
diff --git a/pom.xml b/pom.xml
index 38d33fa..6a44f98 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,12 +45,11 @@
     <felix.plugin.version>4.0.0</felix.plugin.version>
     
<bnd.version.policy>[$(version;==;$(@)),$(version;+;$(@)))</bnd.version.policy>
     <java-compile.version>1.8</java-compile.version>
-    <cxf.version>3.0.0</cxf.version>
-    <javadoc.params /> <!-- for java 8 set disable doclint (by profile) -->
+    <cxf.version>3.4.1</cxf.version>
     <checkstyle.version>2.15</checkstyle.version> <!-- checkstyle > 2.15 
version do not support java 6 -->
     <!-- JVM values for surefire plugin -->
     <surefire.jvm.params>-Xms1024m -Xmx2048m 
-Dfile.encoding=UTF-8</surefire.jvm.params>
-    <owb.version>1.7.5</owb.version>
+    <owb.version>2.0.20</owb.version>
   </properties>
 
   <modules>
@@ -345,7 +344,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
-        <version>2.10.3</version>
+        <version>3.2.0</version>
         <executions>
           <execution>
             <id>attach-javadocs</id>
@@ -354,7 +353,11 @@
             </goals>
             <configuration>
               <show>private</show>
-              <additionalparam>${javadoc.params}</additionalparam> <!-- maven 
plugin generated a HelpMojo with malformed javadoc -->
+              <detectJavaApiLink>false</detectJavaApiLink>
+              <detectLinks>false</detectLinks>
+              <detectOfflineLinks>false</detectOfflineLinks>
+              <doclint>none</doclint>
+              <source>8</source>
             </configuration>
           </execution>
         </executions>
@@ -508,7 +511,6 @@
         <configuration>
           <notimestamp>true</notimestamp>
           <show>private</show>
-          <additionalparam>${javadoc.params}</additionalparam> <!-- maven 
plugin generated a HelpMojo with malformed javadoc -->
         </configuration>
         <reportSets>
           <reportSet>
@@ -762,7 +764,6 @@
       </activation>
       <properties>
         <checkstyle.version>2.17</checkstyle.version>
-        <javadoc.params>-Xdoclint:none</javadoc.params>
       </properties>
     </profile>
   </profiles>

Reply via email to