├── .editorconfig ├── src ├── main │ ├── java │ │ ├── io │ │ │ └── vertx │ │ │ │ └── ext │ │ │ │ └── sync │ │ │ │ ├── package-info.java │ │ │ │ ├── SuspendableRunnable.java │ │ │ │ ├── impl │ │ │ │ ├── HandlerAdaptor.java │ │ │ │ ├── AsyncAdaptor.java │ │ │ │ └── HandlerReceiverAdaptorImpl.java │ │ │ │ ├── HandlerReceiverAdaptor.java │ │ │ │ ├── Receiver.java │ │ │ │ ├── SyncVerticle.java │ │ │ │ └── Sync.java │ │ └── examples │ │ │ ├── package-info.java │ │ │ └── Examples.java │ └── asciidoc │ │ └── index.adoc └── test │ └── java │ └── io │ └── vertx │ └── ext │ └── sync │ ├── benchmark │ ├── SomeAsyncInterface.java │ ├── SomeAsyncInterfaceImpl.java │ ├── Benchmarker.java │ ├── AsyncBenchmarkVerticle.java │ └── SyncBenchmarkVerticle.java │ ├── testmodel │ ├── ReturnedInterface.java │ ├── ReturnedInterfaceImpl.java │ ├── AsyncInterface.java │ └── AsyncInterfaceImpl.java │ └── test │ ├── SyncTest.java │ └── TestVerticle.java ├── .gitignore ├── .github ├── workflows │ └── ci-4.x.yml ├── maven-ci-settings.xml └── maven-cd-settings.xml ├── README.adoc ├── pom.xml └── LICENSE.txt /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/package-info.java: -------------------------------------------------------------------------------- 1 | @ModuleGen(name = "vertx-sync", groupPackage = "io.vertx") 2 | @Deprecated 3 | package io.vertx.ext.sync; 4 | 5 | import io.vertx.codegen.annotations.ModuleGen; 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .gradle 3 | .idea 4 | .classpath 5 | .project 6 | .settings 7 | .yardoc 8 | .yardopts 9 | build 10 | target 11 | out 12 | *.iml 13 | *.ipr 14 | *.iws 15 | .vertx 16 | test-output 17 | src/scratchpad 18 | test-results 19 | test-tmp 20 | *.class 21 | *.swp 22 | .vertx 23 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/benchmark/SomeAsyncInterface.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.benchmark; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Handler; 5 | 6 | /** 7 | * @author Tim Fox 8 | */ 9 | public interface SomeAsyncInterface { 10 | 11 | void asyncMethod(String str, Handler> resultHandler); 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/testmodel/ReturnedInterface.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.testmodel; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Handler; 5 | 6 | /** 7 | * 8 | * @author Tim Fox 9 | */ 10 | 11 | public interface ReturnedInterface { 12 | 13 | void methodWithParamsAndHandlerNoReturn(String foo, long bar, Handler> resultHandler); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/SuspendableRunnable.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync; 2 | 3 | import co.paralleluniverse.fibers.SuspendExecution; 4 | 5 | /** 6 | * @author Tim Fox 7 | * @deprecated This project will be removed with Quasar being effectively abandoned 8 | */ 9 | @Deprecated 10 | public interface SuspendableRunnable { 11 | 12 | void run() throws SuspendExecution, InterruptedException; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/impl/HandlerAdaptor.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.impl; 2 | 3 | import co.paralleluniverse.fibers.FiberAsync; 4 | import io.vertx.core.Handler; 5 | 6 | /** 7 | * 8 | * @author Tim Fox 9 | */ 10 | public abstract class HandlerAdaptor extends FiberAsync implements Handler { 11 | 12 | @Override 13 | public void handle(T res) { 14 | asyncCompleted(res); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/HandlerReceiverAdaptor.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync; 2 | 3 | import io.vertx.core.Handler; 4 | 5 | /** 6 | * 7 | * Represents an object that is both a handler of a particular event and also a receiver of that event. 8 | *

9 | * In other words it converts an asynchronous stream of events into a synchronous receiver of events 10 | * 11 | * @author Tim Fox 12 | * @deprecated This project will be removed with Quasar being effectively abandoned 13 | */ 14 | @Deprecated 15 | public interface HandlerReceiverAdaptor extends Handler, Receiver { 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/impl/AsyncAdaptor.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.impl; 2 | 3 | import co.paralleluniverse.fibers.FiberAsync; 4 | import io.vertx.core.AsyncResult; 5 | import io.vertx.core.Handler; 6 | 7 | /** 8 | * 9 | * @author Tim Fox 10 | */ 11 | public abstract class AsyncAdaptor extends FiberAsync implements Handler> { 12 | 13 | @Override 14 | public void handle(AsyncResult res) { 15 | if (res.succeeded()) { 16 | asyncCompleted(res.result()); 17 | } else { 18 | asyncFailed(res.cause()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/benchmark/SomeAsyncInterfaceImpl.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.benchmark; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.Vertx; 7 | 8 | /** 9 | * @author Tim Fox 10 | */ 11 | public class SomeAsyncInterfaceImpl implements SomeAsyncInterface { 12 | 13 | private final Vertx vertx; 14 | 15 | public SomeAsyncInterfaceImpl(Vertx vertx) { 16 | this.vertx = vertx; 17 | } 18 | 19 | @Override 20 | public void asyncMethod(String str, Handler> resultHandler) { 21 | vertx.runOnContext(v -> resultHandler.handle(Future.succeededFuture("done"))); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/testmodel/ReturnedInterfaceImpl.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.testmodel; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.Vertx; 7 | 8 | /** 9 | * @author Tim Fox 10 | */ 11 | public class ReturnedInterfaceImpl implements ReturnedInterface { 12 | 13 | private final Vertx vertx; 14 | 15 | public ReturnedInterfaceImpl(Vertx vertx) { 16 | this.vertx = vertx; 17 | } 18 | 19 | @Override 20 | public void methodWithParamsAndHandlerNoReturn(String foo, long bar, Handler> resultHandler) { 21 | vertx.runOnContext(v -> resultHandler.handle(Future.succeededFuture(foo + bar))); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/examples/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2013 The original author or authors 3 | * ------------------------------------------------------ 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * and Apache License v2.0 which accompanies this distribution. 7 | * 8 | * The Eclipse Public License is available at 9 | * http://www.eclipse.org/legal/epl-v10.html 10 | * 11 | * The Apache License v2.0 is available at 12 | * http://www.opensource.org/licenses/apache2.0.php 13 | * 14 | * You may elect to redistribute this code under either of these licenses. 15 | */ 16 | 17 | /** 18 | * @author Tim Fox 19 | */ 20 | @Source 21 | package examples; 22 | 23 | import io.vertx.docgen.Source; -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/benchmark/Benchmarker.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.benchmark; 2 | 3 | /** 4 | * @author Tim Fox 5 | */ 6 | public class Benchmarker { 7 | 8 | private final long numItsReport; 9 | 10 | public Benchmarker(long numItsReport) { 11 | this.numItsReport = numItsReport; 12 | } 13 | 14 | private long count; 15 | private long resTot; 16 | private long start; 17 | 18 | public void iterDone(int res) { 19 | if (count == 0) { 20 | start = System.currentTimeMillis(); 21 | } 22 | count++; 23 | resTot += res; 24 | if (count == numItsReport) { 25 | long end = System.currentTimeMillis(); 26 | double rate = 1000 * (double)numItsReport/ (end - start); 27 | System.out.println("Rate is: " + rate + " iterations per second. r: " + resTot); 28 | count = 0; 29 | } 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/testmodel/AsyncInterface.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.testmodel; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Handler; 5 | 6 | /** 7 | * 8 | * @author Tim Fox 9 | */ 10 | public interface AsyncInterface { 11 | 12 | // Non Handler> methods 13 | 14 | String someMethod(String foo, long bar); 15 | 16 | // Methods with Handler> 17 | 18 | void methodWithParamsAndHandlerNoReturn(String foo, long bar, Handler> resultHandler); 19 | 20 | void methodWithNoParamsAndHandlerNoReturn(Handler> resultHandler); 21 | 22 | String methodWithParamsAndHandlerWithReturn(String foo, long bar, Handler> resultHandler); 23 | 24 | String methodWithNoParamsAndHandlerWithReturn(Handler> resultHandler); 25 | 26 | void methodWithParamsAndHandlerInterface(String foo, long bar, Handler> resultHandler); 27 | 28 | void methodThatFails(String foo, Handler> resultHandler); 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/benchmark/AsyncBenchmarkVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.benchmark; 2 | 3 | import co.paralleluniverse.fibers.Suspendable; 4 | import io.vertx.core.AbstractVerticle; 5 | import io.vertx.core.Vertx; 6 | 7 | /** 8 | * @author Tim Fox 9 | */ 10 | public class AsyncBenchmarkVerticle extends AbstractVerticle { 11 | 12 | private Benchmarker benchmarker = new Benchmarker(100000); 13 | 14 | public static void main(String[] args) { 15 | Vertx.vertx().deployVerticle(AsyncBenchmarkVerticle.class.getName()); 16 | } 17 | 18 | private SomeAsyncInterface ai; 19 | 20 | @Override 21 | @Suspendable 22 | public void start() { 23 | 24 | ai = new SomeAsyncInterfaceImpl(vertx); 25 | 26 | benchmarkMethod(); 27 | 28 | } 29 | 30 | @Suspendable 31 | protected void benchmarkMethod() { 32 | 33 | ai.asyncMethod("foo", res -> { 34 | if (res.succeeded()) { 35 | 36 | String result = res.result(); 37 | 38 | benchmarker.iterDone(result.hashCode()); 39 | 40 | vertx.runOnContext(v -> benchmarkMethod()); 41 | 42 | } else { 43 | res.cause().printStackTrace(); 44 | } 45 | }); 46 | 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/Receiver.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync; 2 | 3 | import co.paralleluniverse.fibers.Suspendable; 4 | import co.paralleluniverse.strands.channels.ReceivePort; 5 | 6 | /** 7 | * Represents a synchronous receiver of events. 8 | *

9 | * Note that the `receive` methods may block the calling fiber but will not block an underlying kernel thread. 10 | * 11 | * @author Tim Fox 12 | * @deprecated This project will be removed with Quasar being effectively abandoned 13 | */ 14 | @Deprecated 15 | public interface Receiver { 16 | 17 | /** 18 | * @return the underlying Quasar receivePort 19 | */ 20 | ReceivePort receivePort(); 21 | 22 | /** 23 | * Return an event when one is available. This method will block the fiber until one is available. 24 | * No kernel thread is blocked. 25 | * 26 | * @return the event 27 | */ 28 | @Suspendable 29 | T receive(); 30 | 31 | /** 32 | * Return an event when one is available. This method will block the fiber until one is available, or timeout occurs. 33 | * No kernel thread is blocked. 34 | * 35 | * @param timeout the max amount of time in ms to wait for an event to be available 36 | * @return the event 37 | */ 38 | @Suspendable 39 | T receive(long timeout); 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/benchmark/SyncBenchmarkVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.benchmark; 2 | 3 | import co.paralleluniverse.fibers.Suspendable; 4 | import io.vertx.core.Vertx; 5 | import io.vertx.ext.sync.SyncVerticle; 6 | import io.vertx.ext.sync.impl.AsyncAdaptor; 7 | 8 | import static io.vertx.ext.sync.Sync.fiberHandler; 9 | 10 | /** 11 | * @author Tim Fox 12 | */ 13 | public class SyncBenchmarkVerticle extends SyncVerticle { 14 | 15 | private Benchmarker benchmarker = new Benchmarker(100000); 16 | 17 | public static void main(String[] args) { 18 | Vertx.vertx().deployVerticle(SyncBenchmarkVerticle.class.getName()); 19 | } 20 | 21 | private SomeAsyncInterface ai; 22 | 23 | @Override 24 | @Suspendable 25 | public void start() { 26 | 27 | ai = new SomeAsyncInterfaceImpl(vertx); 28 | 29 | benchmarkMethod(); 30 | 31 | } 32 | 33 | @Suspendable 34 | protected void benchmarkMethod() { 35 | 36 | try { 37 | AsyncAdaptor aa = new AsyncAdaptor() { 38 | @Override 39 | protected void requestAsync() { 40 | ai.asyncMethod("foo", this); 41 | } 42 | }; 43 | 44 | String result = aa.run(); 45 | 46 | benchmarker.iterDone(result.hashCode()); 47 | 48 | vertx.runOnContext(fiberHandler(v -> benchmarkMethod())); 49 | 50 | } catch (Throwable t) { 51 | t.printStackTrace(); 52 | } 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /.github/workflows/ci-4.x.yml: -------------------------------------------------------------------------------- 1 | name: vertx-sync (4.x) 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - '[0-9]+.[0-9x]+' 7 | pull_request: 8 | branches: 9 | - master 10 | - '[0-9]+.[0-9x]+' 11 | schedule: 12 | - cron: '0 4 * * *' 13 | jobs: 14 | Test: 15 | name: Run tests 16 | strategy: 17 | matrix: 18 | os: [ubuntu-latest] 19 | jdk: [8] 20 | runs-on: ${{ matrix.os }} 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v2 24 | - name: Install JDK 25 | uses: actions/setup-java@v2 26 | with: 27 | java-version: ${{ matrix.jdk }} 28 | distribution: temurin 29 | - name: Run tests 30 | run: mvn -s .github/maven-ci-settings.xml -q clean verify -B 31 | Deploy: 32 | name: Deploy to OSSRH 33 | if: ${{ github.repository_owner == 'vert-x3' && (github.event_name == 'push' || github.event_name == 'schedule') }} 34 | needs: Test 35 | runs-on: ubuntu-latest 36 | env: 37 | VERTX_NEXUS_USERNAME: ${{ secrets.VERTX_NEXUS_USERNAME }} 38 | VERTX_NEXUS_PASSWORD: ${{ secrets.VERTX_NEXUS_PASSWORD }} 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v2 42 | - name: Install JDK 43 | uses: actions/setup-java@v2 44 | with: 45 | java-version: 8 46 | distribution: temurin 47 | - name: Get project version 48 | run: echo "PROJECT_VERSION=$(mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version -B | grep -v '\[')" >> $GITHUB_ENV 49 | - name: Maven deploy 50 | if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }} 51 | run: mvn deploy -s .github/maven-cd-settings.xml -DskipTests -B 52 | -------------------------------------------------------------------------------- /.github/maven-ci-settings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | false 20 | 21 | 22 | 23 | google-mirror 24 | 25 | true 26 | 27 | 28 | 29 | google-maven-central 30 | GCS Maven Central mirror EU 31 | https://maven-central.storage-download.googleapis.com/maven2/ 32 | 33 | true 34 | 35 | 36 | false 37 | 38 | 39 | 40 | 41 | 42 | google-maven-central 43 | GCS Maven Central mirror 44 | https://maven-central.storage-download.googleapis.com/maven2/ 45 | 46 | true 47 | 48 | 49 | false 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/examples/Examples.java: -------------------------------------------------------------------------------- 1 | package examples; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.core.eventbus.EventBus; 5 | import io.vertx.core.eventbus.Message; 6 | import io.vertx.ext.sync.HandlerReceiverAdaptor; 7 | 8 | import static io.vertx.ext.sync.Sync.*; 9 | 10 | /** 11 | * @author Tim Fox 12 | */ 13 | public class Examples { 14 | 15 | public void syncResultExample(Vertx vertx) { 16 | 17 | EventBus eb = vertx.eventBus(); 18 | 19 | // Send a message and get the reply synchronously 20 | 21 | Message reply = awaitResult(h -> eb.request("someaddress", "ping", h)); 22 | 23 | System.out.println("Received reply " + reply.body()); 24 | 25 | } 26 | 27 | public void syncEventExample(Vertx vertx) { 28 | 29 | // Set up a timer to fire 30 | long tid = awaitEvent(h -> vertx.setTimer(1000, h)); 31 | 32 | System.out.println("Timer has now fired"); 33 | 34 | } 35 | 36 | public void streamExample(Vertx vertx) { 37 | 38 | EventBus eb = vertx.eventBus(); 39 | 40 | HandlerReceiverAdaptor> adaptor = streamAdaptor(); 41 | 42 | eb.consumer("some-address").handler(adaptor); 43 | 44 | // Receive 10 messages from the consumer: 45 | for (int i = 0; i < 10; i++) { 46 | 47 | Message received1 = adaptor.receive(); 48 | 49 | System.out.println("got message: " + received1.body()); 50 | 51 | } 52 | 53 | } 54 | 55 | public void fiberHandlerExample(Vertx vertx) { 56 | 57 | EventBus eb = vertx.eventBus(); 58 | 59 | vertx.createHttpServer().requestHandler(fiberHandler(req -> { 60 | 61 | // Send a message to address and wait for a reply 62 | Message reply = awaitResult(h -> eb.request("some-address", "blah", h)); 63 | 64 | System.out.println("Got reply: " + reply.body()); 65 | 66 | // Now end the response 67 | req.response().end("blah"); 68 | 69 | })).listen(8080, "localhost"); 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/SyncVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync; 2 | 3 | import co.paralleluniverse.fibers.Fiber; 4 | import co.paralleluniverse.fibers.FiberScheduler; 5 | import co.paralleluniverse.fibers.Suspendable; 6 | import io.vertx.core.AbstractVerticle; 7 | import io.vertx.core.Future; 8 | import io.vertx.core.Promise; 9 | 10 | /** 11 | * A `Verticle` which runs its `start` and `stop` methods using fibers. 12 | * 13 | * You should subclass this class instead of `AbstractVerticle` to create any verticles that use vertx-sync. 14 | * 15 | * @author Tim Fox 16 | * @deprecated This project will be removed with Quasar being effectively abandoned 17 | */ 18 | @Deprecated 19 | public abstract class SyncVerticle extends AbstractVerticle { 20 | 21 | protected FiberScheduler instanceScheduler; 22 | 23 | @Override 24 | public void start(Promise startFuture) throws Exception { 25 | instanceScheduler = Sync.getContextScheduler(); 26 | new Fiber(instanceScheduler, () -> { 27 | try { 28 | SyncVerticle.this.start(); 29 | startFuture.complete(); 30 | } catch (Throwable t) { 31 | startFuture.fail(t); 32 | } 33 | }).start(); 34 | } 35 | 36 | @Override 37 | public void stop(Promise stopFuture) throws Exception { 38 | new Fiber(instanceScheduler, () -> { 39 | try { 40 | SyncVerticle.this.stop(); 41 | stopFuture.complete(); 42 | } catch (Throwable t) { 43 | stopFuture.fail(t); 44 | } finally { 45 | Sync.removeContextScheduler(); 46 | } 47 | }).start(); 48 | } 49 | 50 | /** 51 | * Override this method in your verticle 52 | */ 53 | @Override 54 | @Suspendable 55 | public void start() throws Exception { 56 | } 57 | 58 | /** 59 | * Optionally override this method in your verticle if you have cleanup to do 60 | */ 61 | @Override 62 | @Suspendable 63 | public void stop() throws Exception { 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/impl/HandlerReceiverAdaptorImpl.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.impl; 2 | 3 | import co.paralleluniverse.fibers.Fiber; 4 | import co.paralleluniverse.fibers.FiberScheduler; 5 | import co.paralleluniverse.fibers.Suspendable; 6 | import co.paralleluniverse.strands.channels.Channel; 7 | import co.paralleluniverse.strands.channels.Channels; 8 | import co.paralleluniverse.strands.channels.ReceivePort; 9 | import io.vertx.core.VertxException; 10 | import io.vertx.ext.sync.HandlerReceiverAdaptor; 11 | 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * @author Tim Fox 16 | */ 17 | public class HandlerReceiverAdaptorImpl implements HandlerReceiverAdaptor { 18 | 19 | private final FiberScheduler fiberScheduler; 20 | private final Channel channel; 21 | 22 | public HandlerReceiverAdaptorImpl(FiberScheduler fiberScheduler) { 23 | this.fiberScheduler = fiberScheduler; 24 | channel = Channels.newChannel(-1, Channels.OverflowPolicy.DROP, true, true); 25 | } 26 | 27 | public HandlerReceiverAdaptorImpl(FiberScheduler fiberScheduler, Channel channel) { 28 | this.fiberScheduler = fiberScheduler; 29 | this.channel = channel; 30 | } 31 | 32 | @Override 33 | @Suspendable 34 | public void handle(T t) { 35 | new Fiber(fiberScheduler, () -> { 36 | try { 37 | channel.send(t); 38 | } catch (Exception e) { 39 | throw new VertxException(e); 40 | } 41 | }).start(); 42 | } 43 | 44 | // Access to the underlying Quasar receivePort 45 | public ReceivePort receivePort() { 46 | return channel; 47 | } 48 | 49 | @Suspendable 50 | public T receive() { 51 | try { 52 | return channel.receive(); 53 | } catch (Exception e) { 54 | throw new VertxException(e); 55 | } 56 | } 57 | 58 | 59 | @Suspendable 60 | public T receive(long timeout) { 61 | try { 62 | return channel.receive(timeout, TimeUnit.MILLISECONDS); 63 | } catch (Exception e) { 64 | throw new VertxException(e); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/testmodel/AsyncInterfaceImpl.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.testmodel; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.Vertx; 7 | 8 | /** 9 | * 10 | * @author Tim Fox 11 | */ 12 | public class AsyncInterfaceImpl implements AsyncInterface { 13 | 14 | private final Vertx vertx; 15 | 16 | public AsyncInterfaceImpl(Vertx vertx) { 17 | this.vertx = vertx; 18 | } 19 | 20 | @Override 21 | public String someMethod(String foo, long bar) { 22 | return foo + bar; 23 | } 24 | 25 | @Override 26 | public void methodWithParamsAndHandlerNoReturn(String foo, long bar, Handler> resultHandler) { 27 | vertx.runOnContext(v -> resultHandler.handle(Future.succeededFuture(foo + bar))); 28 | } 29 | 30 | @Override 31 | public void methodWithNoParamsAndHandlerNoReturn(Handler> resultHandler) { 32 | vertx.runOnContext(v -> resultHandler.handle(Future.succeededFuture("wibble"))); 33 | } 34 | 35 | @Override 36 | public String methodWithParamsAndHandlerWithReturn(String foo, long bar, Handler> resultHandler) { 37 | vertx.runOnContext(v -> resultHandler.handle(Future.succeededFuture(foo + bar))); 38 | return "ooble"; 39 | } 40 | 41 | @Override 42 | public String methodWithNoParamsAndHandlerWithReturn(Handler> resultHandler) { 43 | vertx.runOnContext(v -> resultHandler.handle(Future.succeededFuture("wibble"))); 44 | return "flooble"; 45 | } 46 | 47 | @Override 48 | public void methodWithParamsAndHandlerInterface(String foo, long bar, Handler> resultHandler) { 49 | vertx.runOnContext(v -> resultHandler.handle(Future.succeededFuture(new ReturnedInterfaceImpl(vertx)))); 50 | } 51 | 52 | @Override 53 | public void methodThatFails(String foo, Handler> resultHandler) { 54 | vertx.runOnContext(v -> resultHandler.handle(Future.failedFuture(new Exception(foo)))); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /.github/maven-cd-settings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | false 20 | 21 | 22 | 23 | vertx-snapshots-repository 24 | ${env.VERTX_NEXUS_USERNAME} 25 | ${env.VERTX_NEXUS_PASSWORD} 26 | 27 | 28 | 29 | 30 | 31 | google-mirror 32 | 33 | true 34 | 35 | 36 | 37 | google-maven-central 38 | GCS Maven Central mirror EU 39 | https://maven-central.storage-download.googleapis.com/maven2/ 40 | 41 | true 42 | 43 | 44 | false 45 | 46 | 47 | 48 | 49 | 50 | google-maven-central 51 | GCS Maven Central mirror 52 | https://maven-central.storage-download.googleapis.com/maven2/ 53 | 54 | true 55 | 56 | 57 | false 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | [CAUTION] 2 | ==== 3 | This project is now deprecated with the https://github.com/puniverse/quasar[Quasar project] being effectively abandoned in Vert.x 4 and removed in Vert.x 5. 4 | 5 | Use https://github.com/vert-x3/vertx-virtual-threads-incubator/[Vert.x virtual thread instead]. 6 | ==== 7 | 8 | = Synchronous but non-OS-thread-blocking verticles 9 | 10 | image:https://github.com/vert-x3/vertx-sync/workflows/CI/badge.svg?branch=master["Build Status", link="https://github.com/vert-x3/vertx-sync/actions?query=workflow%3ACI"] 11 | 12 | *Love scalability?* 13 | 14 | *Hate blocking kernel threads?* 15 | 16 | *Hate callback hell?* 17 | 18 | *Want to squash the pyramid of doom?* 19 | 20 | *Well, now you can have your cake and eat it...* 21 | 22 | Vert.x lets you write code without blocking kernel threads for i/o by offering non-blocking implementations of common operations. However, these operations are necessarily asynchronous, meaning that for complex processing pipelines, it is necessary to either nest callbacks (leading to "callback hell" or use a library such as Rx to enable composition). Wouldn't it be nice if you could write asynchronous code that just looked like synchronous code? 23 | 24 | Vertx-sync allows you to deploy verticles that run using *fibers*. Fibers are very lightweight threads that can be 25 | blocked without blocking a kernel thread. 26 | 27 | This enables you to write your asynchronous verticle code in a familiar synchronous style (i.e. no callbacks or promises or Rx). Consider it syntactic sugar over asynchronous processing. (Note, it cannot magically convert code which will block, such as synchronous JDBC operations, into non-blocking asynchronous code, so you will need to avoid using blocking libraries. If you do use a blocking library, you will block the event loop, which is to be avoided at all times). 28 | 29 | As no kernel threads are blocked your application retains the scalability advantages of a non (kernel thread) blocking 30 | application. 31 | 32 | Please see the in source asciidoc documentation or the main documentation on the web-site for a full description 33 | of vertx-sync 34 | 35 | * Web-site docs 36 | * link:src/main/asciidoc/index.adoc[Java in-source docs] 37 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/test/SyncTest.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.test; 2 | 3 | import io.vertx.core.DeploymentOptions; 4 | import io.vertx.core.json.JsonObject; 5 | import io.vertx.test.core.VertxTestBase; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 10 | * @author Tim Fox 11 | */ 12 | public class SyncTest extends VertxTestBase { 13 | 14 | protected void runTest(String testName) throws Exception { 15 | 16 | vertx.deployVerticle(new TestVerticle(), 17 | new DeploymentOptions().setConfig(new JsonObject().put("testName", testName)), res -> { 18 | if (res.succeeded()) { 19 | vertx.undeploy(res.result(), res2 -> { 20 | if (res2.succeeded()) { 21 | testComplete(); 22 | } else { 23 | res2.cause().printStackTrace(); 24 | fail("Failure in undeploying"); 25 | } 26 | }); 27 | } else { 28 | res.cause().printStackTrace(); 29 | fail("Failure in running tests"); 30 | } 31 | }); 32 | 33 | await(); 34 | } 35 | 36 | protected String getMethodName() { 37 | return Thread.currentThread().getStackTrace()[2].getMethodName(); 38 | } 39 | 40 | // Test fiber handler 41 | 42 | @Test 43 | public void testFiberHandler() throws Exception { 44 | runTest(getMethodName()); 45 | } 46 | 47 | // Test exec sync 48 | 49 | @Test 50 | public void testExecSyncMethodWithParamsAndHandlerNoReturn() throws Exception { 51 | runTest(getMethodName()); 52 | } 53 | 54 | @Test 55 | public void testExecSyncMethodWithNoParamsAndHandlerNoReturn() throws Exception { 56 | runTest(getMethodName()); 57 | } 58 | 59 | @Test 60 | public void testExecSyncMethodWithParamsAndHandlerWithReturn() throws Exception { 61 | runTest(getMethodName()); 62 | } 63 | 64 | @Test 65 | public void testExecSyncMethodWithNoParamsAndHandlerWithReturn() throws Exception { 66 | runTest(getMethodName()); 67 | } 68 | 69 | @Test 70 | public void testExecSyncMethodWithParamsAndHandlerInterface() throws Exception { 71 | runTest(getMethodName()); 72 | } 73 | 74 | @Test 75 | public void testExecSyncMethodWithNoParamsAndHandlerWithReturnNoTimeout() throws Exception { 76 | runTest(getMethodName()); 77 | } 78 | 79 | @Test 80 | public void testExecSyncMethodWithNoParamsAndHandlerWithReturnTimedout() throws Exception { 81 | runTest(getMethodName()); 82 | } 83 | 84 | @Test 85 | public void testExecSyncMethodThatFails() throws Exception { 86 | runTest(getMethodName()); 87 | } 88 | 89 | // Test receive single event 90 | 91 | @Test 92 | public void testReceiveEvent() throws Exception { 93 | runTest(getMethodName()); 94 | } 95 | 96 | @Test 97 | public void testReceiveEventTimedout() throws Exception { 98 | runTest(getMethodName()); 99 | } 100 | 101 | @Test 102 | public void testReceiveEventNoTimeout() throws Exception { 103 | runTest(getMethodName()); 104 | } 105 | 106 | // Test Channels 107 | 108 | @Test 109 | public void testHandlerAdaptor() throws Exception { 110 | runTest(getMethodName()); 111 | } 112 | 113 | // Various misc 114 | 115 | @Test 116 | public void testSleep() throws Exception { 117 | runTest(getMethodName()); 118 | } 119 | 120 | 121 | } 122 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | 5 | io.vertx 6 | vertx-ext-parent 7 | 42 8 | 9 | 10 | vertx-sync 11 | vertx-sync (DEPRECATED) 12 | 4.5.15-SNAPSHOT 13 | 14 | 15 | 0.7.10 16 | 0.7.9 17 | 18 | 19 | 20 | 21 | 22 | io.vertx 23 | vertx-dependencies 24 | ${project.version} 25 | pom 26 | import 27 | 28 | 29 | 30 | 31 | 32 | 33 | io.vertx 34 | vertx-codegen 35 | 36 | 37 | io.vertx 38 | vertx-core 39 | 40 | 41 | co.paralleluniverse 42 | quasar-core 43 | ${quasar-core.version} 44 | jdk8 45 | 46 | 47 | io.dropwizard.metrics 48 | metrics-core 49 | 50 | 51 | org.latencyutils 52 | LatencyUtils 53 | 54 | 55 | org.hdrhistogram 56 | HdrHistogram 57 | 58 | 59 | com.google.protobuf 60 | protobuf-java 61 | 62 | 63 | com.google.guava 64 | guava 65 | 66 | 67 | 68 | 69 | io.vertx 70 | vertx-docgen 71 | true 72 | 73 | 74 | 75 | com.google.guava 76 | guava 77 | 78 | 79 | junit 80 | junit 81 | 4.13.1 82 | test 83 | 84 | 85 | io.vertx 86 | vertx-unit 87 | test 88 | 89 | 90 | io.vertx 91 | vertx-core 92 | test-jar 93 | test 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 103 | 104 | maven-dependency-plugin 105 | 2.8 106 | 107 | 108 | getClasspathFilenames 109 | 110 | properties 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | com.vlkan 122 | quasar-maven-plugin 123 | ${quasar-maven-plugin.version} 124 | 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | instrument 133 | 134 | 135 | 136 | 137 | 141 | 142 | co.paralleluniverse 143 | quasar-core 144 | ${quasar-core.version} 145 | 146 | 147 | 148 | 149 | 151 | 152 | maven-dependency-plugin 153 | 2.10 154 | 155 | 156 | getClasspathFilenames 157 | 158 | properties 159 | 160 | 161 | 162 | 163 | 164 | 165 | org.apache.maven.plugins 166 | maven-surefire-plugin 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | -javaagent:${co.paralleluniverse:quasar-core:jar:jdk8} 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/sync/Sync.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync; 2 | 3 | import co.paralleluniverse.fibers.Fiber; 4 | import co.paralleluniverse.fibers.FiberExecutorScheduler; 5 | import co.paralleluniverse.fibers.FiberScheduler; 6 | import co.paralleluniverse.fibers.Suspendable; 7 | import co.paralleluniverse.strands.channels.Channel; 8 | import io.vertx.core.*; 9 | import io.vertx.ext.sync.impl.AsyncAdaptor; 10 | import io.vertx.ext.sync.impl.HandlerAdaptor; 11 | import io.vertx.ext.sync.impl.HandlerReceiverAdaptorImpl; 12 | 13 | import java.util.concurrent.TimeUnit; 14 | import java.util.concurrent.TimeoutException; 15 | import java.util.function.Consumer; 16 | 17 | /** 18 | * This class contains various static methods to allowing events and asynchronous results to be accessed 19 | * in a synchronous way. 20 | * 21 | * @author Tim Fox 22 | * @deprecated This project will be removed with Quasar being effectively abandoned 23 | */ 24 | @Deprecated 25 | public class Sync { 26 | 27 | private static final String FIBER_SCHEDULER_CONTEXT_KEY = "__vertx-sync.fiberScheduler"; 28 | 29 | /** 30 | * Invoke an asynchronous operation and obtain the result synchronous. 31 | * The fiber will be blocked until the result is available. No kernel thread is blocked. 32 | * 33 | * @param consumer this should encapsulate the asynchronous operation. The handler is passed to it. 34 | * @param the type of the result 35 | * @return the result 36 | */ 37 | @Suspendable 38 | public static T awaitResult(Consumer>> consumer) { 39 | try { 40 | return new AsyncAdaptor() { 41 | @Override 42 | @Suspendable 43 | protected void requestAsync() { 44 | try { 45 | consumer.accept(this); 46 | } catch (Exception e) { 47 | throw new VertxException(e); 48 | } 49 | } 50 | }.run(); 51 | } catch (Throwable t) { 52 | throw new VertxException(t); 53 | } 54 | } 55 | 56 | /** 57 | * Invoke an asynchronous operation and obtain the result synchronous. 58 | * The fiber will be blocked until the result is available. No kernel thread is blocked. 59 | * 60 | * @param consumer this should encapsulate the asynchronous operation. The handler is passed to it. 61 | * @param timeout In milliseconds when to cancel the awaited result 62 | * @param the type of the result 63 | * @return the result or null in case of a time out 64 | */ 65 | @Suspendable 66 | public static T awaitResult(Consumer>> consumer, long timeout) { 67 | try { 68 | return new AsyncAdaptor() { 69 | @Override 70 | @Suspendable 71 | protected void requestAsync() { 72 | try { 73 | consumer.accept(this); 74 | } catch (Exception e) { 75 | throw new VertxException(e); 76 | } 77 | } 78 | }.run(timeout, TimeUnit.MILLISECONDS); 79 | } catch (TimeoutException to) { 80 | return null; 81 | } catch (Throwable t) { 82 | throw new VertxException(t); 83 | } 84 | } 85 | 86 | /** 87 | * Receive a single event from a handler synchronously. 88 | * The fiber will be blocked until the event occurs. No kernel thread is blocked. 89 | * 90 | * @param consumer this should encapsulate the setting of the handler to receive the event. The handler is passed to it. 91 | * @param the type of the event 92 | * @return the event 93 | */ 94 | @Suspendable 95 | public static T awaitEvent(Consumer> consumer) { 96 | try { 97 | return new HandlerAdaptor() { 98 | @Override 99 | @Suspendable 100 | protected void requestAsync() { 101 | try { 102 | consumer.accept(this); 103 | } catch (Exception e) { 104 | throw new VertxException(e); 105 | } 106 | } 107 | }.run(); 108 | } catch (Throwable t) { 109 | throw new VertxException(t); 110 | } 111 | } 112 | 113 | /** 114 | * Receive a single event from a handler synchronously. 115 | * The fiber will be blocked until the event occurs. No kernel thread is blocked. 116 | * 117 | * @param consumer this should encapsulate the setting of the handler to receive the event. The handler is passed to it. 118 | * @param timeout In milliseconds when to cancel the awaited event 119 | * @param the type of the event 120 | * @return the event 121 | */ 122 | @Suspendable 123 | public static T awaitEvent(Consumer> consumer, long timeout) { 124 | try { 125 | return new HandlerAdaptor() { 126 | @Suspendable 127 | @Override 128 | protected void requestAsync() { 129 | try { 130 | consumer.accept(this); 131 | } catch (Exception e) { 132 | throw new VertxException(e); 133 | } 134 | } 135 | }.run(timeout, TimeUnit.MILLISECONDS); 136 | } catch (TimeoutException to) { 137 | return null; 138 | } catch (Throwable t) { 139 | throw new VertxException(t); 140 | } 141 | } 142 | 143 | /** 144 | * Convert a standard handler to a handler which runs on a fiber. This is necessary if you want to do fiber blocking 145 | * synchronous operations in your handler. 146 | * 147 | * @param handler the standard handler 148 | * @param the event type of the handler 149 | * @return a wrapped handler that runs the handler on a fiber 150 | */ 151 | @Suspendable 152 | public static Handler fiberHandler(Handler handler) { 153 | FiberScheduler scheduler = getContextScheduler(); 154 | return p -> new Fiber(scheduler, () -> handler.handle(p)).start(); 155 | } 156 | 157 | /** 158 | * Create an adaptor that converts a stream of events from a handler into a receiver which allows the events to be 159 | * received synchronously. 160 | * 161 | * @param the type of the event 162 | * @return the adaptor 163 | */ 164 | @Suspendable 165 | public static HandlerReceiverAdaptor streamAdaptor() { 166 | return new HandlerReceiverAdaptorImpl<>(getContextScheduler()); 167 | } 168 | 169 | /** 170 | * Like {@link #streamAdaptor()} but using the specified Quasar `Channel` instance. This is useful if you want to 171 | * fine-tune the behaviour of the adaptor. 172 | * 173 | * @param channel the Quasar channel 174 | * @param the type of the event 175 | * @return the adaptor 176 | */ 177 | @Suspendable 178 | public static HandlerReceiverAdaptor streamAdaptor(Channel channel) { 179 | return new HandlerReceiverAdaptorImpl<>(getContextScheduler(), channel); 180 | } 181 | 182 | /** 183 | * Get the `FiberScheduler` for the current context. There should be only one instance per context. 184 | * @return the scheduler 185 | */ 186 | @Suspendable 187 | public static FiberScheduler getContextScheduler() { 188 | Context context = Vertx.currentContext(); 189 | if (context == null) { 190 | throw new IllegalStateException("Not in context"); 191 | } 192 | if (!context.isEventLoopContext()) { 193 | throw new IllegalStateException("Not on event loop"); 194 | } 195 | // We maintain one scheduler per context 196 | FiberScheduler scheduler = context.get(FIBER_SCHEDULER_CONTEXT_KEY); 197 | if (scheduler == null) { 198 | Thread eventLoop = Thread.currentThread(); 199 | scheduler = new FiberExecutorScheduler("vertx.contextScheduler", command -> { 200 | if (Thread.currentThread() != eventLoop) { 201 | context.runOnContext(v -> command.run()); 202 | } else { 203 | // Just run directly 204 | command.run(); 205 | } 206 | }); 207 | context.put(FIBER_SCHEDULER_CONTEXT_KEY, scheduler); 208 | } 209 | return scheduler; 210 | } 211 | 212 | /** 213 | * Remove the scheduler for the current context 214 | */ 215 | @Suspendable 216 | public static void removeContextScheduler() { 217 | Context context = Vertx.currentContext(); 218 | if (context != null) { 219 | context.remove(FIBER_SCHEDULER_CONTEXT_KEY); 220 | } 221 | } 222 | 223 | 224 | } 225 | -------------------------------------------------------------------------------- /src/main/asciidoc/index.adoc: -------------------------------------------------------------------------------- 1 | = Vertx-Sync 2 | 3 | Vertx-sync is a set of utilities that allow you to perform asynchronous operations and receive events in a 4 | synchronous way, but without blocking kernel threads. 5 | 6 | == Introduction 7 | 8 | One of the key advantages of Vert.x over many legacy application platforms is that it is almost entirely non-blocking 9 | (of kernel threads) - this allows it to handle a lot of concurrency (e.g. handle many connections, or messages) using 10 | a very small number of kernel threads, which allows it to scale very well. 11 | 12 | The non blocking nature of Vert.x leads to asynchronous APIs. Asynchronous APIs can take various forms including 13 | callback style, promises or Rx-style. Vert.x uses callback style in most places (although it also supports Rx). 14 | 15 | In some cases, programming using asynchronous APIs can be more challenging than using a direct synchronous style, in 16 | particular if you have several operations that you want to do in sequence. Also error propagation is often more complex 17 | when using asynchronous APIs. 18 | 19 | Vertx-sync allows you to work with asynchronous APIs, but using a direct synchronous style that you're already 20 | familiar with. 21 | 22 | It does this by using `fibers`. Fibers are very lightweight threads that do not correspond to underlying kernel threads. 23 | When they are blocked they do not block a kernel thread. 24 | 25 | Vert-sync uses http://docs.paralleluniverse.co/quasar/[Quasar] to implement the fibers. 26 | 27 | NOTE: Vert-sync currently only works with Java. 28 | 29 | == SyncVerticle 30 | 31 | In order to use vertx-sync you must deploy your code as instances of `io.vertx.ext.sync.SyncVerticle`. 32 | You should override the `start()` and (optionally) the `stop()` methods of the verticle. 33 | 34 | Those methods *must* be annotated with the `@Suspendable` annotation. 35 | 36 | Once you've written your sync verticle(s) you deploy them in exactly the same way as any other verticle. 37 | 38 | == Instrumentation 39 | 40 | Vert.x uses Quasar which implements fibers by using bytecode instrumentation. This is done at run-time using a java 41 | agent. 42 | 43 | In order for this to work you must start the JVM specifying the java agent jar which is located in the quasar-core 44 | jar. 45 | 46 | TODO how to reference quasar core jar in fatjar? 47 | 48 | ---- 49 | -javaagent:/path/to/quasar/core/quasar-core.jar 50 | ---- 51 | 52 | If you are using the `vertx` command line tools, the agent configuration can be enabled by setting the `ENABLE_VERTX_SYNC_AGENT` 53 | environment variable to `true`, before executing `vertx`. 54 | 55 | You can also use a offline instrumentation as with the https://github.com/vy/quasar-maven-plugin[quasar-maven-plugin] or or https://github.com/mtatheonly/quasar-gradle-plugin[quasar-gradle-plugin]. 56 | Check the http://docs.paralleluniverse.co/quasar/[Quasar documentation] for more details. 57 | 58 | == Getting one-shot async results 59 | 60 | Many async operations in Vert.x-land take a `Handler>` as the last argument. An example would 61 | executing a find using the Vert.x Mongo client or sending an event bus message and getting a reply. 62 | 63 | Vertx-sync allows you to get the result of a one-shot asynchronous operation in a synchronous way. 64 | 65 | This is done by using the {@link io.vertx.ext.sync.Sync#awaitResult(java.util.function.Consumer)} method. 66 | 67 | The method is executed specifying the asynchronous operation that you want to execute in the form of a {@link java.util.function.Consumer}, 68 | the consumer is passed the handler at run-time. 69 | 70 | Here's an example: 71 | 72 | [source,$lang] 73 | ---- 74 | {@link examples.Examples#syncResultExample(io.vertx.core.Vertx)} 75 | ---- 76 | 77 | In the above example the fiber is blocked until the reply is returned but no kernel thread is blocked. 78 | 79 | == Getting one-shot events 80 | 81 | Vertx-sync can be used to get one-shot events in a synchronous way, for example firings of timers, or the executing of 82 | an end handler. This is achieved using the {@link io.vertx.ext.sync.Sync#awaitEvent(java.util.function.Consumer)} method. 83 | 84 | Here's an example: 85 | 86 | [source,$lang] 87 | ---- 88 | {@link examples.Examples#syncEventExample(io.vertx.core.Vertx)} 89 | ---- 90 | 91 | == Streams of events 92 | 93 | In many places in Vert.x streams of events are provided by passing them to handlers. 94 | 95 | Examples include event bus message consumers and HTTP server requests on an HTTP server. 96 | 97 | Vert-sync allows you to receive events from such streams in a synchronous way. 98 | 99 | You do this with an instance of {@link io.vertx.ext.sync.HandlerReceiverAdaptor} which implements both 100 | {@link io.vertx.core.Handler} and {@link io.vertx.ext.sync.Receiver}. You create an instance using 101 | {@link io.vertx.ext.sync.Sync#streamAdaptor()}. 102 | 103 | You can set it as a normal handler and then use the methods on {@link io.vertx.ext.sync.Receiver} to receive 104 | events synchronously. 105 | 106 | Here's an example using an event bus message consumer: 107 | 108 | [source,$lang] 109 | ---- 110 | {@link examples.Examples#streamExample(io.vertx.core.Vertx)} 111 | ---- 112 | 113 | == Using a `FiberHandler` 114 | 115 | If you want to do use fibers in a normal handler, e.g. in the request handler of an Http Server then you must first 116 | convert the normal handler to a fiber handler. 117 | 118 | The fiber handler runs the normal handler on a fiber. 119 | 120 | Here's an example: 121 | 122 | [source,$lang] 123 | ---- 124 | {@link examples.Examples#fiberHandlerExample(io.vertx.core.Vertx)} 125 | ---- 126 | 127 | == Further examples 128 | 129 | There are a set of working examples demonstrating vertx-sync in action in the 130 | https://github.com/vert-x3/vertx-examples/tree/master/sync-examples[examples repository] 131 | 132 | == What if you get exceptions? 133 | 134 | Quasar and co-routines do not _"automagically"_ transform blocking code into non-blocking code. 135 | Especially, blocking using `Thread.sleep` or using `synchronized` blocks and methods _is_ a problem. 136 | 137 | There are 2 types of exceptions that you may observe when using `vertx-sync`. 138 | 139 | === Instrumentation warnings 140 | 141 | You may encounter stack traces like the following in your logs: 142 | 143 | ---- 144 | (...) 145 | [quasar] ERROR: while transforming io/vertx/core/impl/DeploymentManager$DeploymentImpl: Unable to instrument vertx/core/impl/DeploymentManager$DeploymentImpl#lambda$rollback$1(Ljava/lang/Throwable;Lio/vertx/core/impl/ContextInternal;Lio/vertx/core/Handler;/vertx/core/impl/ContextImpl;Lio/vertx/core/AsyncResult;)V because of synchronization 146 | co.paralleluniverse.fibers.instrument.UnableToInstrumentException: Unable to instrument vertx/core/impl/DeploymentManager$DeploymentImpl#lambda$rollback$1(Ljava/lang/Throwable;Lio/vertx/core/impl/ContextInternal;Lio/vertx/core/Handler;/vertx/core/impl/ContextImpl;Lio/vertx/core/AsyncResult;)V because of synchronization 147 | at co.paralleluniverse.fibers.instrument.InstrumentMethod.dumpCodeBlock(InstrumentMethod.java:720) 148 | at co.paralleluniverse.fibers.instrument.InstrumentMethod.accept(InstrumentMethod.java:415) 149 | at co.paralleluniverse.fibers.instrument.InstrumentClass.visitEnd(InstrumentClass.java:265) 150 | (...) 151 | ---- 152 | 153 | These errors are actually warnings from Quasar as it tries to instrument both your code and libraries (including Vert.x modules!). 154 | 155 | Quasar may encounter blocking constructs such as thread blocking and `synchronized` blocks or methods. 156 | There is sometimes little you can do, but this does not mean that your application will not be functional. 157 | 158 | There are just some parts reported by Quasar where coroutines may block without being able to yield execution to another coroutine. 159 | 160 | === Calling fiber code from outside a fiber 161 | 162 | You may encounter exceptions that prevent your application to function, such as: 163 | 164 | ---- 165 | (...) 166 | io.vertx.core.VertxException: java.lang.IllegalThreadStateException: Method called not from within a fiber 167 | at co.paralleluniverse.fibers.FiberAsync.requestSync(FiberAsync.java:289) 168 | at co.paralleluniverse.fibers.FiberAsync.runSync(FiberAsync.java:255) 169 | at co.paralleluniverse.fibers.FiberAsync.run(FiberAsync.java:111) 170 | (...) 171 | ---- 172 | 173 | This happens when you call fiber code (e.g., a method annotated with `@Suspendable`) from outside a fiber, such as from an event-loop thread. 174 | 175 | In most of the cases the solution lies in wrapping the call to the first fiber code using one of the helper methods from {@link io.vertx.ext.sync.Sync}: `awaitResult`, `awaitEvent`, `fiberHandler` and `streamAdaptor`. 176 | 177 | Suppose that we have a fiber method like the following: 178 | 179 | [source,java] 180 | ---- 181 | @Suspendable 182 | public String readData() { 183 | boolean exists = Sync.awaitResult(h -> vertx.fileSystem().exists("file.txt", h)); 184 | if (exists) { 185 | Buffer buf = Sync.awaitResult(h -> vertx.fileSystem().readFile("file.txt", h)); 186 | return buf.toString(); 187 | } 188 | return ""; 189 | } 190 | ---- 191 | 192 | Now suppose that we want to call this method in response to an event-bus method. 193 | To ensure that the event-bus message processing is from a fiber and we can call the `readData` method, then we need adapting with `fiberHandler`: 194 | 195 | [source,java] 196 | ---- 197 | vertx.eventBus().consumer("read", Sync.fiberHandler(m -> m.reply(readData()))); 198 | ---- 199 | 200 | Conversely, if you do not use `fiberHandler` then you will get an exception as above: 201 | 202 | [source,java] 203 | ---- 204 | // This crashes! 205 | vertx.eventBus().consumer("read", m -> m.reply(readData())); 206 | ---- 207 | 208 | TIP: If you need more flexibility you can always use {@link io.vertx.ext.sync.Sync#getContextScheduler()} to access the verticle context scheduler and start Quasar fibers / strands. 209 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/sync/test/TestVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.sync.test; 2 | 3 | import co.paralleluniverse.fibers.SuspendExecution; 4 | import co.paralleluniverse.fibers.Suspendable; 5 | import co.paralleluniverse.strands.Strand; 6 | import co.paralleluniverse.strands.channels.Channel; 7 | import co.paralleluniverse.strands.channels.Channels; 8 | import co.paralleluniverse.strands.channels.ReceivePort; 9 | import io.vertx.core.Context; 10 | import io.vertx.core.Vertx; 11 | import io.vertx.core.VertxException; 12 | import io.vertx.core.eventbus.EventBus; 13 | import io.vertx.core.eventbus.Message; 14 | import io.vertx.core.http.*; 15 | import io.vertx.ext.sync.HandlerReceiverAdaptor; 16 | import io.vertx.ext.sync.SyncVerticle; 17 | import io.vertx.ext.sync.testmodel.AsyncInterface; 18 | import io.vertx.ext.sync.testmodel.AsyncInterfaceImpl; 19 | import io.vertx.ext.sync.testmodel.ReturnedInterface; 20 | 21 | import java.lang.reflect.Method; 22 | import java.util.concurrent.TimeUnit; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | 25 | import static org.junit.Assert.*; 26 | import static io.vertx.ext.sync.Sync.*; 27 | 28 | import static org.hamcrest.core.Is.*; 29 | 30 | /** 31 | * @author Tim Fox 32 | */ 33 | public class TestVerticle extends SyncVerticle { 34 | 35 | private static final String ADDRESS1 = "address1"; 36 | private static final String ADDRESS2 = "address2"; 37 | private static final String ADDRESS3 = "address3"; 38 | 39 | private AsyncInterface ai; 40 | private Channel completeChannel; 41 | 42 | @Override 43 | @Suspendable 44 | public void start() throws Exception { 45 | 46 | ai = new AsyncInterfaceImpl(vertx); 47 | 48 | completeChannel = Channels.newChannel(1, Channels.OverflowPolicy.THROW); 49 | 50 | try { 51 | 52 | String testName = config().getString("testName"); 53 | 54 | Method meth = this.getClass().getDeclaredMethod(testName); 55 | meth.setAccessible(true); 56 | meth.invoke(this); 57 | 58 | } catch (AssertionError e) { 59 | e.printStackTrace(); 60 | throw new IllegalStateException("Tests failed", e); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | throw new IllegalStateException("Failed to invoke test", e); 64 | } 65 | 66 | completeChannel.receive(10, TimeUnit.SECONDS); 67 | 68 | } 69 | 70 | @Suspendable 71 | protected void complete() { 72 | try { 73 | completeChannel.send(new Object()); 74 | } catch (Exception e) { 75 | throw new VertxException(e); 76 | } 77 | } 78 | 79 | @Suspendable 80 | protected void testContext() { 81 | Context ctx = Vertx.currentContext(); 82 | assertTrue(ctx.isEventLoopContext()); 83 | complete(); 84 | } 85 | 86 | @Suspendable 87 | protected void testSleep() throws Exception { 88 | Thread th = Thread.currentThread(); 89 | AtomicInteger cnt = new AtomicInteger(); 90 | vertx.setPeriodic(1, tid -> { 91 | assertSame(Thread.currentThread(), th); 92 | cnt.incrementAndGet(); 93 | }); 94 | assertSame(Thread.currentThread(), th); 95 | Strand.sleep(1000, TimeUnit.MILLISECONDS); 96 | assertSame(Thread.currentThread(), th); 97 | assertTrue(cnt.get() > 900); 98 | complete(); 99 | } 100 | 101 | @Suspendable 102 | protected void testFiberHandler() { 103 | HttpServer server = vertx.createHttpServer(new HttpServerOptions().setPort(8080)); 104 | server.requestHandler(fiberHandler(req -> { 105 | String res = awaitResult(h -> ai.methodWithParamsAndHandlerNoReturn("oranges", 23, h)); 106 | assertEquals("oranges23", res); 107 | req.response().end(); 108 | })); 109 | server.listen(res -> { 110 | assertTrue(res.succeeded()); 111 | HttpClient client = vertx.createHttpClient(new HttpClientOptions().setDefaultPort(8080)); 112 | client.request(HttpMethod.GET, "/somepath", ar1 -> { 113 | assertTrue(ar1.succeeded()); 114 | if (ar1.succeeded()) { 115 | HttpClientRequest req = ar1.result(); 116 | req.send(ar2 -> { 117 | if (ar2.succeeded()) { 118 | HttpClientResponse resp = ar2.result(); 119 | assertEquals(200, resp.statusCode()); 120 | client.close(); 121 | server.close(res2 -> { 122 | complete(); 123 | }); 124 | } 125 | }); 126 | } 127 | }); 128 | }); 129 | } 130 | 131 | @Suspendable 132 | protected void testExecSyncMethodWithParamsAndHandlerNoReturn() { 133 | Thread th = Thread.currentThread(); 134 | String res = awaitResult(h -> ai.methodWithParamsAndHandlerNoReturn("oranges", 23, h)); 135 | assertEquals("oranges23", res); 136 | assertSame(Thread.currentThread(), th); 137 | complete(); 138 | } 139 | 140 | @Suspendable 141 | protected void testExecSyncMethodWithNoParamsAndHandlerNoReturn() { 142 | String res = awaitResult(h -> ai.methodWithNoParamsAndHandlerNoReturn(h)); 143 | assertEquals("wibble", res); 144 | complete(); 145 | } 146 | 147 | @Suspendable 148 | protected void testExecSyncMethodWithParamsAndHandlerWithReturn() { 149 | String res = awaitResult(h -> ai.methodWithParamsAndHandlerWithReturn("oranges", 23, h)); 150 | assertEquals("oranges23", res); 151 | complete(); 152 | } 153 | 154 | @Suspendable 155 | protected void testExecSyncMethodWithNoParamsAndHandlerWithReturn() { 156 | String res = awaitResult(h -> ai.methodWithNoParamsAndHandlerWithReturn(h)); 157 | assertEquals("wibble", res); 158 | complete(); 159 | } 160 | 161 | @Suspendable 162 | private void sleep(long millis) { 163 | try { 164 | Strand.sleep(millis); 165 | } catch (SuspendExecution | InterruptedException suspendExecution) { 166 | throw new AssertionError(); // Required to compile, but the try-catch block is reworked by the Quasar instrumentation 167 | } 168 | } 169 | 170 | @Suspendable 171 | protected void testExecSyncMethodWithNoParamsAndHandlerWithReturnNoTimeout() { 172 | long start = System.currentTimeMillis(); 173 | String res = awaitResult(h -> { 174 | sleep(500); 175 | ai.methodWithNoParamsAndHandlerWithReturn(h); 176 | }, 2000); 177 | long duration = (System.currentTimeMillis() - start); 178 | assertEquals("wibble", res); 179 | assertTrue("Expected 500 < (duration = " + duration + ") < 1000", duration > 500 && duration < 1000); 180 | complete(); 181 | } 182 | 183 | @Suspendable 184 | protected void testExecSyncMethodWithNoParamsAndHandlerWithReturnTimedout() { 185 | String res = awaitResult(h -> { 186 | sleep(1000); 187 | ai.methodWithNoParamsAndHandlerWithReturn(h); 188 | }, 500); 189 | assertNull(res); 190 | complete(); 191 | } 192 | 193 | @Suspendable 194 | protected void testExecSyncMethodWithParamsAndHandlerInterface() { 195 | ReturnedInterface returned = awaitResult(h -> ai.methodWithParamsAndHandlerInterface("apples", 123, h)); 196 | assertNotNull(returned); 197 | String res = awaitResult(h -> returned.methodWithParamsAndHandlerNoReturn("bananas", 100, h)); 198 | assertEquals(res, "bananas100"); 199 | complete(); 200 | } 201 | 202 | @Suspendable 203 | protected void testExecSyncMethodThatFails() { 204 | try { 205 | String res = awaitResult(h -> ai.methodThatFails("oranges", h)); 206 | fail("Should throw exception"); 207 | } catch (Exception e) { 208 | assertTrue(e instanceof VertxException); 209 | VertxException ve = (VertxException) e; 210 | assertEquals("oranges", ve.getCause().getMessage()); 211 | complete(); 212 | } 213 | 214 | } 215 | 216 | @Suspendable 217 | protected void testReceiveEvent() { 218 | 219 | long start = System.currentTimeMillis(); 220 | long tid = awaitEvent(h -> vertx.setTimer(500, h)); 221 | long end = System.currentTimeMillis(); 222 | assertTrue(end - start >= 500); 223 | assertTrue(tid >= 0); 224 | 225 | complete(); 226 | } 227 | 228 | @Suspendable 229 | protected void testReceiveEventTimedout() { 230 | 231 | long start = System.currentTimeMillis(); 232 | try { 233 | long tid = awaitEvent(h -> vertx.setTimer(500, h), 250); 234 | } catch (NullPointerException npe) { 235 | assertThat(npe, isA(NullPointerException.class)); 236 | } catch (Exception e) { 237 | assertTrue(false); 238 | } finally { 239 | complete(); 240 | } 241 | } 242 | 243 | @Suspendable 244 | protected void testReceiveEventNoTimeout() { 245 | 246 | long start = System.currentTimeMillis(); 247 | long tid = awaitEvent(h -> vertx.setTimer(500, h), 1000); 248 | long end = System.currentTimeMillis(); 249 | assertTrue(end - start >= 500); 250 | assertTrue(tid >= 0); 251 | 252 | complete(); 253 | } 254 | 255 | @Suspendable 256 | protected void testHandlerAdaptor() throws Exception { 257 | 258 | EventBus eb = vertx.eventBus(); 259 | 260 | // Create a couple of consumers on different addresses 261 | // The adaptor allows handler to be used as a Channel 262 | 263 | HandlerReceiverAdaptor> adaptor1 = streamAdaptor(); 264 | eb.consumer(ADDRESS1).handler(adaptor1); 265 | 266 | HandlerReceiverAdaptor> adaptor2 = streamAdaptor(); 267 | eb.consumer(ADDRESS2).handler(adaptor2); 268 | 269 | // Set up a periodic timer to send messages to these addresses 270 | 271 | long start = System.currentTimeMillis(); 272 | 273 | vertx.setPeriodic(10, tid -> { 274 | eb.send(ADDRESS1, "wibble"); 275 | eb.send(ADDRESS2, "flibble"); 276 | }); 277 | 278 | for (int i = 0; i < 10; i++) { 279 | 280 | Message received1 = adaptor1.receive(); 281 | assertEquals("wibble", received1.body()); 282 | 283 | Message received2 = adaptor2.receive(); 284 | assertEquals("flibble", received2.body()); 285 | 286 | } 287 | 288 | long end = System.currentTimeMillis(); 289 | assertTrue(end - start >= 100); 290 | 291 | // Try a receive with timeout 292 | 293 | Message received1 = adaptor1.receive(1000); 294 | assertEquals("wibble", received1.body()); 295 | 296 | // And timing out 297 | 298 | HandlerReceiverAdaptor> adaptor3 = streamAdaptor(); 299 | eb.consumer(ADDRESS3).handler(adaptor3); 300 | 301 | Message received3 = adaptor3.receive(100); 302 | 303 | assertNull(received3); 304 | 305 | // Try underlying receivePort 306 | 307 | ReceivePort> channel = adaptor1.receivePort(); 308 | assertNotNull(channel); 309 | received1 = channel.receive(); 310 | assertEquals("wibble", received1.body()); 311 | 312 | 313 | complete(); 314 | } 315 | 316 | @Override 317 | @Suspendable 318 | public void stop() { 319 | 320 | try { 321 | 322 | testContext(); 323 | 324 | } catch (AssertionError e) { 325 | e.printStackTrace(); 326 | fail("tests failed"); 327 | } 328 | 329 | } 330 | 331 | } 332 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------