├── .gitignore ├── .idea ├── codeStyleSettings.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml └── copyright │ ├── Orbit_Copyright.xml │ └── profiles_settings.xml ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── TODO.md ├── async ├── async-stub.jar ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ea │ │ │ └── async │ │ │ ├── Async.java │ │ │ └── instrumentation │ │ │ ├── Agent.java │ │ │ ├── FrameAnalyzer.java │ │ │ ├── InitializeAsync.java │ │ │ ├── Main.java │ │ │ ├── Premain.java │ │ │ └── Transformer.java │ └── resources │ │ └── com │ │ └── ea │ │ └── async │ │ └── instrumentation │ │ └── async-stub.jar │ └── test │ └── java │ ├── NoPackageAsync.java │ └── com │ └── ea │ └── async │ ├── Task.java │ ├── instrumentation │ ├── AnalyserTest.java │ ├── ConstantTest.java │ ├── ConstructorReplacementTest.java │ ├── DevDebug.java │ ├── ErrorReportingTest.java │ ├── InitRemovalTest.java │ ├── TransformerMainErrorTest.java │ ├── TransformerMainTest.java │ └── TransformerTest.java │ └── test │ ├── AConstNullTest.java │ ├── ArrayVarsTest.java │ ├── BaseTest.java │ ├── BaseTestTest.java │ ├── BasicInstrTest.java │ ├── BasicTest.java │ ├── CompletionStageTest.java │ ├── ExceptionTest.java │ ├── FrameTest.java │ ├── FunctionCallTest.java │ ├── HowItShouldWorkTest.java │ ├── JoinTest.java │ ├── LambdaTest.java │ ├── LocalVarsTest.java │ ├── LoopTest.java │ ├── MultipleAwaitTest.java │ ├── NoPackageTest.java │ ├── NullThenBasicValueTest.java │ ├── PrimitiveTest.java │ ├── RuntimeInstrTest.java │ ├── SmallestExceptionTest.java │ ├── SmallestTest.java │ ├── StaticTest.java │ ├── SynchronizedTest.java │ ├── TaskTest.java │ ├── TryWithResourcesTest.java │ └── UnorthodoxFrameTest.java ├── gradle-plugin ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── ea │ │ └── async │ │ └── gradle │ │ └── plugin │ │ └── AsyncPlugin.java │ └── resources │ └── META-INF │ └── gradle-plugins │ └── com.ea.async.gradle.plugin.properties ├── maven-plugin ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── ea │ │ └── async │ │ └── maven │ │ └── plugin │ │ ├── AbstractAsyncMojo.java │ │ ├── MainMojo.java │ │ └── TestMojo.java │ └── test │ ├── java │ └── MojoTest.java │ └── project-to-test │ ├── pom.xml │ └── src │ ├── main │ └── java │ │ └── Main.java │ └── test │ └── java │ └── test │ └── AsyncTest.java ├── pom.xml └── updateDocs.groovy /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | *.versionsBackup 3 | dependency-reduced-pom.xml 4 | target/ 5 | 6 | # Gradle 7 | .gradle 8 | out/ 9 | build/ 10 | 11 | # IntelliJ 12 | *.iml 13 | .idea/* 14 | !.idea/copyright/ 15 | !.idea/codeStyles/ 16 | !.idea/codeStyleSettings.xml 17 | 18 | # Eclipse 19 | .project/ 20 | .classpath/ 21 | .settings/ 22 | .factorypath/ 23 | .apt_generated/ 24 | 25 | # Netbeans 26 | nbproject/private/ 27 | nbbuild/ 28 | dist/ 29 | nbdist/ 30 | .nb-gradle/ 31 | 32 | # Logging 33 | **/log/** 34 | 35 | # Mac 36 | .DS_Store 37 | 38 | # Windows 39 | thumbs.db 40 | Desktop.ini 41 | $RECYCLE.BIN/ -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/copyright/Orbit_Copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false 3 | jdk: 4 | - openjdk8 5 | - openjdk11 6 | - openjdk12 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thanks for your interest! 2 | 3 | In order to clarify the intellectual property license granted for contributions to EA open source projects you must sign the [Contributor License Agreement (CLA)](https://go.ea.com/cla). 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 - 2016 Electronic Arts Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 13 | its contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EA Async 2 | ============ 3 | 4 | [![Release](https://img.shields.io/github/release/electronicarts/ea-async.svg)](https://github.com/electronicarts/ea-async/releases) 5 | [![Maven Central](https://img.shields.io/maven-central/v/com.ea.async/ea-async-parent.svg)](http://repo1.maven.org/maven2/com/ea/async/) 6 | [![Javadocs](https://img.shields.io/maven-central/v/com.ea.async/ea-async.svg?label=Javadocs)](http://www.javadoc.io/doc/com.ea.async/ea-async) 7 | [![Build Status](https://img.shields.io/travis/electronicarts/ea-async.svg)](https://travis-ci.org/electronicarts/ea-async) 8 | 9 | EA Async implements Async-Await methods in the JVM. 10 | It allows programmers to write asynchronous code in a sequential fashion. 11 | 12 | It is heavily inspired by Async-Await on the .NET CLR, see [Asynchronous Programming with Async and Await](https://msdn.microsoft.com/en-us/library/hh191443.aspx) for more information. 13 | 14 | Who should use it? 15 | ------ 16 | 17 | EA Async should be used to write non-blocking asynchronous code that makes heavy use of CompletableFutures or CompletionStage. 18 | It improves scalability by freeing worker threads while your code awaits other processes; 19 | And improves productivity by making asynchronous code simpler and more readable. 20 | 21 | Developer & License 22 | ====== 23 | This project was developed by [Electronic Arts](http://www.ea.com) and is licensed under the [BSD 3-Clause License](LICENSE). 24 | 25 | Examples 26 | ======= 27 | #### With EA Async 28 | 29 | ```java 30 | import static com.ea.async.Async.await; 31 | import static java.util.concurrent.CompletableFuture.completedFuture; 32 | 33 | public class Store 34 | { 35 | public CompletableFuture buyItem(String itemTypeId, int cost) 36 | { 37 | if(!await(bank.decrement(cost))) { 38 | return completedFuture(false); 39 | } 40 | await(inventory.giveItem(itemTypeId)); 41 | return completedFuture(true); 42 | } 43 | } 44 | ``` 45 | In this example `Bank.decrement` returns `CompletableFuture` and `Inventory.giveItem` returns `CompletableFuture` 46 | 47 | EA Async rewrites the calls to `Async.await` making your methods non-blocking. 48 | 49 | The methods look blocking but are actually transformed into asynchronous methods that use 50 | CompletableFutures to continue the execution as intermediary results arrive. 51 | 52 | #### Without EA Async 53 | 54 | This is how the first example looks without EA Async. It is a bit less readable. 55 | 56 | ```java 57 | import static java.util.concurrent.CompletableFuture.completedFuture; 58 | 59 | public class Store 60 | { 61 | public CompletableFuture buyItem(String itemTypeId, int cost) 62 | { 63 | return bank.decrement(cost) 64 | .thenCompose(result -> { 65 | if(!result) { 66 | return completedFuture(false); 67 | } 68 | return inventory.giveItem(itemTypeId).thenApply(res -> true); 69 | }); 70 | } 71 | } 72 | ``` 73 | This is a small example... A method with a few more CompletableFutures can look very convoluted. 74 | 75 | EA Async abstracts away the complexity of the CompletableFutures. 76 | 77 | #### With EA Async (2) 78 | 79 | So you like CompletableFutures? 80 | Try converting this method to use only CompletableFutures without ever blocking (so no joining): 81 | 82 | ```java 83 | import static com.ea.async.Async.await; 84 | import static java.util.concurrent.CompletableFuture.completedFuture; 85 | 86 | public class Store 87 | { 88 | public CompletableFuture buyItem(String itemTypeId, int cost) 89 | { 90 | if(!await(bank.decrement(cost))) { 91 | return completedFuture(false); 92 | } 93 | try { 94 | await(inventory.giveItem(itemTypeId)); 95 | return completedFuture(true); 96 | } catch (Exception ex) { 97 | await(bank.refund(cost)); 98 | throw new AppException(ex); 99 | } 100 | } 101 | } 102 | ``` 103 | 104 | Got it? Send it [to us](https://github.com/electronicarts/ea-async/issues/new). It probably looks ugly... 105 | 106 | Getting started 107 | --------------- 108 | 109 | EA Async currently supports JDK 8-10. 110 | 111 | It works with Java and Scala and should work with most JVM languages. 112 | The only requirement to use EA Async is that must be used only inside methods that return `CompletableFuture`, `CompletionStage`, or subclasses of `CompletableFuture`. 113 | 114 | ### Using with maven 115 | 116 | ```xml 117 | 118 | com.ea.async 119 | ea-async 120 | 1.2.3 121 | 122 | ``` 123 | 124 | ### Gradle 125 | 126 | ``` 127 | 'com.ea.async:ea-async:1.2.3' 128 | ``` 129 | 130 | ### Instrumenting your code 131 | 132 | #### Option 1 - JVM parameter 133 | 134 | Start your application with an extra JVM parameter: `-javaagent:ea-async-1.2.3.jar` 135 | ``` 136 | java -javaagent:ea-async-1.2.3.jar -cp your_claspath YourMainClass args... 137 | ``` 138 | 139 | It's recommended to add this as a default option to launchers in IntelliJ projects that use ea-async. 140 | 141 | #### Option 2 - Runtime 142 | On your main class or as early as possible, call at least once: 143 | ``` 144 | Async.init(); 145 | ``` 146 | Provided that your JVM has the capability enabled, this will start a runtime instrumentation agent. 147 | If you forget to invoke this function, the first call to `await` will initialize the system (and print a warning). 148 | 149 | This is a solution for testing and development, it has the least amount of configuration. 150 | It might interfere with JVM debugging. This alternative is present as a fallback. 151 | 152 | #### Option 3 - Run instrumentation tool 153 | 154 | The ea-async-1.2.3.jar is a runnable jar that can pre-instrument your files. 155 | 156 | Usage: 157 | 158 | ```bash 159 | java -cp YOUR_PROJECT_CLASSPATH -jar ea-async-1.2.3.jar classDirectory 160 | ``` 161 | 162 | Example: 163 | 164 | ```bash 165 | java -cp guava.jar;commons-lang.jar -jar ea-async-1.2.3.jar target/classes 166 | ``` 167 | 168 | After that all the files in target/classes will have been instrumented. 169 | There will be no references to `Async.await` and `Async.init` left in those classes. 170 | 171 | 172 | #### Option 4 - Build time instrumentation, with Maven - Preferred 173 | 174 | Use the [ea-async-maven-plugin](maven-plugin). It will instrument your classes in compile time and 175 | remove all references to `Async.await` and `Async.init()`. 176 | 177 | With build time instrumentation your project users won't need to have EA Async in their classpath unless they also choose to use it. 178 | This means that EA Async does not need to be a transitive dependency. 179 | 180 | This is the best option for libraries and maven projects. 181 | 182 | ```xml 183 | 184 | 185 | 186 | com.ea.async 187 | ea-async-maven-plugin 188 | 1.2.3 189 | 190 | 191 | 192 | instrument 193 | instrument-test 194 | 195 | 196 | 197 | 198 | 199 | 200 | ``` 201 | 202 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | Maven plugin 3 | --------------- 4 | 5 | * Implement or remove inclusion and exclusion options. 6 | 7 | Gradle plugin 8 | --------------- 9 | 10 | * Create a gradle plugin 11 | 12 | IDE integration 13 | --------------- 14 | 15 | * Intellij IDEA plugin: compile time instrumentation 16 | * Eclipse plugin: compile time instrumentation 17 | 18 | 19 | Other features 20 | ----------------- 21 | 22 | * Instrument methods that return Object but where all `return` keywords are used with some class derived from CompletionStage. 23 | This would help with lambdas. 24 | 25 | * Check the generic return type of a function besides the erased type. 26 | 27 | * Unlikely: Instrument methods that don't return task but are called with a wrapper? 28 | Probably not a good idea. 29 | 30 | ```java 31 | 32 | void someMethod() { 33 | int a = 1; 34 | Task res = async(()-> a + await(bla1()) + await(bla2())); 35 | // Equivalent to: 36 | // Task res = async(()-> Task.fromValue(a + await(bla1()) + await(bla2()))); 37 | doSomething(res); 38 | } 39 | 40 | void someMethod() { 41 | int a = 1; 42 | Task res = async(()-> { 43 | int x = await(bla1()); 44 | int y = await(bla2()); 45 | return a + x + y; // no task 46 | }); 47 | } 48 | 49 | ``` 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /async/async-stub.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-async/18e6f5edd2151bd8e65900dbec2aea36f90dfb1f/async/async-stub.jar -------------------------------------------------------------------------------- /async/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 29 | 32 | 4.0.0 33 | 34 | com.ea.async 35 | ea-async-parent 36 | 1.2.4-SNAPSHOT 37 | .. 38 | 39 | ea-async 40 | EA Async-Await 41 | 42 | 43 | 7.1 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-compiler-plugin 51 | 52 | 53 | -proc:none 54 | 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-jar-plugin 59 | 60 | 61 | true 62 | 63 | com.ea.async.instrumentation.Premain 64 | com.ea.async.instrumentation.Agent 65 | com.ea.async.instrumentation.Main 66 | true 67 | true 68 | 69 | 70 | 71 | 72 | 73 | maven-shade-plugin 74 | 75 | 76 | package 77 | 78 | shade 79 | 80 | 81 | 82 | 83 | net.bytebuddy:byte-buddy-agent 84 | org.ow2.asm:asm 85 | org.ow2.asm:asm-analysis 86 | org.ow2.asm:asm-util 87 | org.ow2.asm:asm-tree 88 | 89 | 90 | 91 | 92 | org.objectweb. 93 | com.ea.async.shaded.org.objectweb. 94 | 95 | 96 | net.bytebuddy. 97 | com.ea.async.shaded.net.bytebuddy. 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | org.ow2.asm 110 | asm 111 | ${asm.version} 112 | 113 | 114 | org.ow2.asm 115 | asm-util 116 | ${asm.version} 117 | 118 | 119 | org.ow2.asm 120 | asm-analysis 121 | ${asm.version} 122 | 123 | 124 | org.ow2.asm 125 | asm-tree 126 | ${asm.version} 127 | 128 | 129 | org.slf4j 130 | slf4j-api 131 | 1.7.25 132 | 133 | 134 | net.bytebuddy 135 | byte-buddy-agent 136 | 1.9.13 137 | 138 | 139 | org.apache.commons 140 | commons-lang3 141 | 3.7 142 | test 143 | 144 | 145 | junit 146 | junit 147 | test 148 | 149 | 150 | commons-io 151 | commons-io 152 | 2.6 153 | test 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /async/src/main/java/com/ea/async/Async.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async; 30 | 31 | import com.ea.async.instrumentation.InitializeAsync; 32 | 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | import java.util.concurrent.CompletableFuture; 37 | import java.util.concurrent.CompletionStage; 38 | 39 | /** 40 | * This class together with bytecode instrumentation implements the async-await functionality in the JVM. 41 | *

42 | * To use it call Async.await(future) from within methods whose return type is 43 | * CompletionStage, CompletableFuture or subclasses of CompletableFuture. 44 | *

45 | * Async.await(future) won't block. It is semantically equivalent to call future.join() 46 | * But instead of blocking the code in instrumented to become a state machine that evolves as the futures passed 47 | * to await are completed. 48 | *

49 | * This is equivalent to use CompletableFuture composition methods (ex: thenApply, handle, thenCompose). 50 | * The advantage of using await is that the code will resemble sequential blocking code. 51 | *

52 | * Example: 53 | *


 54 |  * import static com.ea.async.Async.await;
 55 |  * import static java.util.concurrent.CompletableFuture.completedFuture;*
 56 |  *
 57 |  * public class Store
 58 |  * {
 59 |  *     public CompletableFuture buyItem(String itemTypeId, int cost)
 60 |  *     {
 61 |  *         if(!await(bank.decrement(cost))) {
 62 |  *             return completedFuture(false);
 63 |  *         }
 64 |  *         await(inventory.giveItem(itemTypeId));
 65 |  *         return completedFuture(true);
 66 |  *     }
 67 |  * }
 68 |  * 
69 | */ 70 | public class Async 71 | { 72 | /** 73 | * Ensure that if no pre instrumentation was done, that the Async runtime instrumentation is running. 74 | *

75 | * Attention! The build time instrumentation will remove calls to this method. 76 | */ 77 | public static void init() 78 | { 79 | InitializeAsync.init(); 80 | } 81 | 82 | private static Logger logger; 83 | 84 | /** 85 | * This method will behave as a CompletableFuture.join() but will actually cause the 86 | * caller to return a promise instead of blocking. 87 | * 88 | * Calls to this method are replaced by the EA Async instrumentation. 89 | * 90 | * @param future a future to wait for. 91 | * @param the future value type. 92 | * @return the return value of the future 93 | * @throws java.util.concurrent.CompletionException wrapping the actual exception if an exception occured. 94 | */ 95 | public static > T await(F future) 96 | { 97 | String warning; 98 | if (!InitializeAsync.isRunning()) 99 | { 100 | warning = "Warning: Illegal call to await, static { Async.init(); } must be added to the main program class and the method invoking await must return a CompletableFuture"; 101 | } 102 | else 103 | { 104 | warning = "Warning: Illegal call to await, the method invoking await must return a CompletableFuture"; 105 | } 106 | LoggerFactory.getLogger(Async.class); 107 | if (logger == null) 108 | { 109 | logger = LoggerFactory.getLogger(Async.class); 110 | } 111 | if (logger.isDebugEnabled()) 112 | { 113 | logger.warn(warning, new Throwable()); 114 | } 115 | else 116 | { 117 | logger.warn(warning); 118 | } 119 | if (future instanceof CompletableFuture) 120 | { 121 | //noinspection unchecked 122 | return ((CompletableFuture) future).join(); 123 | } 124 | return future.toCompletableFuture().join(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /async/src/main/java/com/ea/async/instrumentation/Agent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import java.lang.instrument.Instrumentation; 32 | 33 | /** 34 | * Class called when a java agent is attached to the jvm in runtime. 35 | */ 36 | public class Agent 37 | { 38 | /* 39 | * From https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/instrument/Instrumentation.html 40 | * 41 | * Agent-Class 42 | * 43 | * If an implementation supports a mechanism to start agents sometime 44 | * after the VM has started then this attribute specifies the agent class. 45 | * That is, the class containing the agentmain method. This attribute is 46 | * required, if it is not present the agent will not be started. Note: this 47 | * is a class name, not a file name or path. 48 | */ 49 | public static void agentmain(String agentArgs, Instrumentation inst) 50 | { 51 | Transformer transformer = new Transformer(); 52 | inst.addTransformer(transformer, true); 53 | f1: 54 | for (Class clazz : inst.getAllLoadedClasses()) 55 | { 56 | if (inst.isModifiableClass(clazz) 57 | && !clazz.getName().startsWith("java.") 58 | && !clazz.getName().startsWith("javax.") 59 | && !clazz.getName().startsWith("sun.")) 60 | { 61 | try 62 | { 63 | if (transformer.needsInstrumentation(clazz)) 64 | { 65 | inst.retransformClasses(clazz); 66 | } 67 | } 68 | catch (Exception | Error e) 69 | { 70 | e.printStackTrace(); 71 | } 72 | } 73 | } 74 | System.setProperty(Transformer.EA_ASYNC_RUNNING, "true"); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /async/src/main/java/com/ea/async/instrumentation/Main.java: -------------------------------------------------------------------------------- 1 | package com.ea.async.instrumentation; 2 | 3 | 4 | import org.objectweb.asm.ClassReader; 5 | 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Tool class to perform build time instrumentation. 17 | */ 18 | public class Main 19 | { 20 | private boolean verbose; 21 | private List fileList; 22 | private Path outputDirectory; 23 | private ClassLoader classLoader = getClass().getClassLoader(); 24 | 25 | public static void main(String args[]) throws IOException 26 | { 27 | final int ret = new Main().doMain(args); 28 | if (ret != 0) 29 | { 30 | System.exit(-1); 31 | } 32 | } 33 | 34 | public int doMain(final String[] args) throws IOException 35 | { 36 | outputDirectory = null; 37 | 38 | fileList = new ArrayList<>(); 39 | if (args.length == 0) 40 | { 41 | printUsage(); 42 | return 0; 43 | } 44 | for (int i = 0; i < args.length; i++) 45 | { 46 | final String arg = args[i]; 47 | if ("--help".equals(arg)) 48 | { 49 | printUsage(); 50 | continue; 51 | } 52 | if ("-verbose".equals(arg)) 53 | { 54 | verbose = true; 55 | continue; 56 | } 57 | if ("-d".equals(arg)) 58 | { 59 | if (i + 1 == args.length) 60 | { 61 | error("Invalid usage of the -d option"); 62 | return 1; 63 | } 64 | outputDirectory = Paths.get(args[++i]); 65 | continue; 66 | } 67 | final Path path = Paths.get(arg); 68 | if (Files.isDirectory(path)) 69 | { 70 | Files.walk(path) 71 | .filter(Files::isRegularFile) 72 | .filter(p -> p.toString().endsWith(".class")) 73 | .forEach(fileList::add); 74 | continue; 75 | } 76 | if (Files.isRegularFile(path)) 77 | { 78 | fileList.add(path); 79 | continue; 80 | } 81 | error("Invalid argument or file: " + arg); 82 | return 1; 83 | } 84 | return transform() >= 0 ? 0 : 1; 85 | } 86 | 87 | public int transform() throws IOException 88 | { 89 | final Transformer transformer = new Transformer(); 90 | transformer.setErrorListener(System.err::println); 91 | boolean error = false; 92 | int count = 0; 93 | final Path outputDir = getOutputDirectory(); 94 | for (Path path : fileList) 95 | { 96 | byte[] bytes = null; 97 | try (InputStream in = new FileInputStream(path.toFile())) 98 | { 99 | bytes = transformer.instrument(classLoader, in); 100 | } 101 | catch (Exception e) 102 | { 103 | error("Error instrumenting " + path, e); 104 | error = true; 105 | } 106 | if (bytes != null) 107 | { 108 | if (verbose) 109 | { 110 | info("instrumented: " + path); 111 | } 112 | if (outputDir != null) 113 | { 114 | // writing to the output directory, using the package name as path. 115 | final Path outPath = outputDir.resolve(new ClassReader(bytes).getClassName() + ".class"); 116 | final Path outParent = outPath.getParent(); 117 | if (!Files.exists(outParent)) 118 | { 119 | Files.createDirectories(outParent); 120 | } 121 | Files.write(outPath, bytes); 122 | } 123 | else 124 | { 125 | // replacing the original file 126 | Files.write(path, bytes); 127 | } 128 | count++; 129 | } 130 | } 131 | return error ? -1 : count; 132 | } 133 | 134 | private void error(final String msg, final Exception e) 135 | { 136 | System.err.println(msg); 137 | e.printStackTrace(); 138 | } 139 | 140 | 141 | protected void error(String msg) 142 | { 143 | System.err.println(msg); 144 | } 145 | 146 | protected void info(String msg) 147 | { 148 | System.err.println(msg); 149 | } 150 | 151 | protected void printUsage() 152 | { 153 | System.out.println("usage:"); 154 | System.out.println(" java -cp project-class-path -jar ea-async.jar -d output-directory file1 input-dir1 input-dir2"); 155 | System.out.println("options:"); 156 | System.out.println("-d directory"); 157 | System.out.println(" Set the destination directory for class files. "); 158 | System.out.println(" If not specified the original files will be modified in place"); 159 | System.out.println("-help"); 160 | System.out.println(" Shows this help. "); 161 | } 162 | 163 | public boolean isVerbose() 164 | { 165 | return verbose; 166 | } 167 | 168 | public void setVerbose(final boolean verbose) 169 | { 170 | this.verbose = verbose; 171 | } 172 | 173 | public List getFileList() 174 | { 175 | return fileList; 176 | } 177 | 178 | public void setFileList(final List fileList) 179 | { 180 | this.fileList = fileList; 181 | } 182 | 183 | public Path getOutputDirectory() 184 | { 185 | return outputDirectory; 186 | } 187 | 188 | public void setOutputDirectory(final Path outputDirectory) 189 | { 190 | this.outputDirectory = outputDirectory; 191 | } 192 | 193 | public ClassLoader getClassLoader() 194 | { 195 | return classLoader; 196 | } 197 | 198 | public void setClassLoader(final ClassLoader classLoader) 199 | { 200 | this.classLoader = classLoader; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /async/src/main/java/com/ea/async/instrumentation/Premain.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import java.lang.instrument.Instrumentation; 32 | 33 | /** 34 | * Class called when the jvm option -javaagent is used with the orbit-async jar. 35 | */ 36 | public class Premain 37 | { 38 | /* 39 | * From https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/instrument/Instrumentation.html 40 | * 41 | * Premain-Class 42 | * 43 | * When an agent is specified at JVM launch time this attribute specifies 44 | * the agent class. That is, the class containing the premain method. 45 | * When an agent is specified at JVM launch time this attribute is required. 46 | * If the attribute is not present the JVM will abort. Note: this is a class 47 | * name, not a file name or path. 48 | */ 49 | public static void premain(String agentArgs, Instrumentation inst) 50 | { 51 | inst.addTransformer(new Transformer(), true); 52 | System.setProperty(Transformer.EA_ASYNC_RUNNING, "true"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /async/src/main/resources/com/ea/async/instrumentation/async-stub.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-async/18e6f5edd2151bd8e65900dbec2aea36f90dfb1f/async/src/main/resources/com/ea/async/instrumentation/async-stub.jar -------------------------------------------------------------------------------- /async/src/test/java/NoPackageAsync.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | import java.util.concurrent.CompletableFuture; 30 | 31 | import static com.ea.async.Async.await; 32 | 33 | public class NoPackageAsync 34 | { 35 | 36 | static String concat(int i, long j, float f, double d, Object obj, boolean b) 37 | { 38 | return i + ":" + j + ":" + f + ":" + d + ":" + obj + ":" + b; 39 | } 40 | 41 | public CompletableFuture noPackageMethod(CompletableFuture blocker, int var) 42 | { 43 | return CompletableFuture.completedFuture(concat(var, 10_000_000_000L, 1.5f, 3.5d, await(blocker), true)); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/Task.java: -------------------------------------------------------------------------------- 1 | package com.ea.async; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.concurrent.CompletionStage; 5 | import java.util.function.Function; 6 | 7 | public class Task extends CompletableFuture 8 | { 9 | public static Task fromValue(T value) 10 | { 11 | final Task task = new Task<>(); 12 | task.complete(value); 13 | return task; 14 | } 15 | 16 | public static Task done() 17 | { 18 | final Task task = new Task<>(); 19 | task.complete(null); 20 | return task; 21 | } 22 | 23 | public static Task fromException(final Exception ex) 24 | { 25 | final Task task = new Task<>(); 26 | task.completeExceptionally(ex); 27 | return task; 28 | } 29 | 30 | public static Task from(CompletionStage stage) 31 | { 32 | Task a; 33 | if (stage instanceof Task) 34 | { 35 | a = (Task) stage; 36 | } 37 | else 38 | { 39 | final Task t = new Task<>(); 40 | stage.whenComplete((T v, Throwable ex) -> { 41 | if (ex != null) 42 | { 43 | t.completeExceptionally(ex); 44 | } 45 | else 46 | { 47 | t.complete(v); 48 | } 49 | }); 50 | a = t; 51 | } 52 | return a; 53 | } 54 | 55 | 56 | /** 57 | * Wraps a CompletionStage as a Task or just casts it if it is already a Task. 58 | * 59 | * @param stage the stage to be wrapped or casted to Task 60 | * @return stage cast as Task of a new Task that is dependent on the completion of that stage. 61 | */ 62 | public static Task cast(CompletionStage stage) 63 | { 64 | if (stage instanceof Task) 65 | { 66 | return (Task) stage; 67 | } 68 | 69 | final Task t = new Task<>(); 70 | stage.whenComplete((T v, Throwable ex) -> { 71 | if (ex != null) 72 | { 73 | t.completeExceptionally(ex); 74 | } 75 | else 76 | { 77 | t.complete(v); 78 | } 79 | }); 80 | return t; 81 | } 82 | 83 | 84 | public Task thenCompose(Function> fn) 85 | { 86 | return Task.from(super.thenCompose(fn)); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/instrumentation/ConstantTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import org.junit.Test; 32 | 33 | import static org.junit.Assert.assertEquals; 34 | 35 | public class ConstantTest 36 | { 37 | @Test 38 | public void testSignalingConstant() 39 | { 40 | assertEquals("Signaling constants must match", Transformer.EA_ASYNC_RUNNING, InitializeAsync.EA_ASYNC_RUNNING); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/instrumentation/DevDebug.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import org.objectweb.asm.ClassReader; 32 | import org.objectweb.asm.tree.AbstractInsnNode; 33 | import org.objectweb.asm.tree.ClassNode; 34 | import org.objectweb.asm.tree.MethodNode; 35 | import org.objectweb.asm.tree.analysis.Analyzer; 36 | import org.objectweb.asm.tree.analysis.AnalyzerException; 37 | import org.objectweb.asm.tree.analysis.BasicValue; 38 | import org.objectweb.asm.tree.analysis.Frame; 39 | import org.objectweb.asm.util.Textifier; 40 | import org.objectweb.asm.util.TraceClassVisitor; 41 | import org.objectweb.asm.util.TraceMethodVisitor; 42 | 43 | import java.io.IOException; 44 | import java.io.PrintWriter; 45 | import java.io.StringWriter; 46 | import java.nio.charset.Charset; 47 | import java.nio.file.Files; 48 | import java.nio.file.Path; 49 | import java.nio.file.Paths; 50 | 51 | /** 52 | * For development use only 53 | */ 54 | public class DevDebug 55 | { 56 | public static void printMethod(final ClassNode cn, final MethodNode mv) 57 | { 58 | final PrintWriter pw = new PrintWriter(System.out); 59 | pw.println("method " + mv.name + mv.desc); 60 | Textifier p = new Textifier(); 61 | final TraceMethodVisitor tv = new TraceMethodVisitor(p); 62 | 63 | try 64 | { 65 | Analyzer analyzer2 = new Analyzer(new FrameAnalyzer.TypeInterpreter()); 66 | Frame[] frames2; 67 | try 68 | { 69 | frames2 = analyzer2.analyze(cn.superName, mv); 70 | } 71 | catch (AnalyzerException ex) 72 | { 73 | if (ex.node != null) 74 | { 75 | pw.print("Error at: "); 76 | ex.node.accept(tv); 77 | } 78 | ex.printStackTrace(); 79 | frames2 = null; 80 | } 81 | catch (Exception ex) 82 | { 83 | ex.printStackTrace(); 84 | frames2 = null; 85 | } 86 | 87 | final AbstractInsnNode[] isns2 = mv.instructions.toArray(); 88 | 89 | for (int i = 0; i < isns2.length; i++) 90 | { 91 | Frame frame; 92 | if (frames2 != null && (frame = frames2[i]) != null) 93 | { 94 | p.getText().add("Locals: [ "); 95 | for (int x = 0; x < frame.getLocals(); x++) 96 | { 97 | p.getText().add(String.valueOf(((BasicValue) frame.getLocal(x)).getType())); 98 | p.getText().add(" "); 99 | } 100 | p.getText().add("]\r\n"); 101 | p.getText().add("Stack: [ "); 102 | for (int x = 0; x < frame.getStackSize(); x++) 103 | { 104 | p.getText().add(String.valueOf(((BasicValue) frame.getStack(x)).getType())); 105 | p.getText().add(" "); 106 | } 107 | p.getText().add("]\r\n"); 108 | } 109 | p.getText().add(i + ": "); 110 | isns2[i].accept(tv); 111 | } 112 | p.print(pw); 113 | pw.println(); 114 | pw.flush(); 115 | } 116 | catch (Exception ex) 117 | { 118 | ex.printStackTrace(); 119 | } 120 | } 121 | 122 | 123 | public static void debugSave(final ClassNode classNode, final byte[] bytes) 124 | { 125 | try 126 | { 127 | 128 | Path path = Paths.get("target/classes2/" + classNode.name + ".class"); 129 | Files.createDirectories(path.getParent()); 130 | Files.write(path, bytes); 131 | } 132 | catch (IOException e) 133 | { 134 | e.printStackTrace(); 135 | } 136 | } 137 | 138 | 139 | public static void debugSaveTrace(String name, final byte[] bytes) 140 | { 141 | try 142 | { 143 | StringWriter sw = new StringWriter(); 144 | PrintWriter pw = new PrintWriter(sw); 145 | new ClassReader(bytes).accept(new TraceClassVisitor(pw), 0); 146 | pw.flush(); 147 | 148 | Path path = Paths.get("target/classes2/" + name + ".asmtrace"); 149 | Files.createDirectories(path.getParent()); 150 | Files.write(path, sw.toString().getBytes(Charset.forName("UTF-8"))); 151 | System.out.println("Writing file to " + path.toUri()); 152 | } 153 | catch (IOException e) 154 | { 155 | e.printStackTrace(); 156 | } 157 | } 158 | 159 | public static void debugSaveTrace(String name, ClassNode node) 160 | { 161 | try 162 | { 163 | StringWriter sw = new StringWriter(); 164 | PrintWriter pw = new PrintWriter(sw); 165 | node.accept(new TraceClassVisitor(pw)); 166 | pw.flush(); 167 | 168 | Path path = Paths.get("target/classes2/" + name + ".asmtrace"); 169 | Files.createDirectories(path.getParent()); 170 | Files.write(path, sw.toString().getBytes(Charset.forName("UTF-8"))); 171 | System.out.println("Writing file to " + path.toUri()); 172 | } 173 | catch (IOException e) 174 | { 175 | e.printStackTrace(); 176 | } 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/instrumentation/ErrorReportingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import com.ea.async.Async; 32 | 33 | import com.ea.async.test.BaseTest; 34 | import com.ea.async.Task; 35 | 36 | import org.junit.Test; 37 | import org.objectweb.asm.ClassReader; 38 | import org.objectweb.asm.tree.analysis.AnalyzerException; 39 | 40 | import java.io.IOException; 41 | import java.lang.reflect.InvocationTargetException; 42 | import java.util.concurrent.atomic.AtomicReference; 43 | 44 | import static org.junit.Assert.*; 45 | 46 | public class ErrorReportingTest extends BaseTest 47 | { 48 | public static class InvalidAwaitCall 49 | { 50 | public void invalidAwaitCall(Task task) 51 | { 52 | Async.await(task); 53 | } 54 | } 55 | 56 | @Test 57 | public void testErrorReporting() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, IOException, AnalyzerException 58 | { 59 | ClassReader cr = new ClassReader(InvalidAwaitCall.class.getResourceAsStream(InvalidAwaitCall.class.getName().replaceAll("^.*[.]", "") + ".class")); 60 | assertTrue(mentionsAwait(cr)); 61 | 62 | AtomicReference reference = new AtomicReference<>(); 63 | final Transformer transformer = new Transformer(); 64 | transformer.setErrorListener(t -> reference.set(t)); 65 | 66 | final byte[] bytes = transformer.transform(getClass().getClassLoader(), cr); 67 | assertNotNull(reference.get()); 68 | assertTrue(reference.get().contains("invalidAwaitCall")); 69 | 70 | ClassReader cr2 = new ClassReader(bytes); 71 | assertFalse(mentionsAwait(cr2)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/instrumentation/InitRemovalTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import com.ea.async.Async; 32 | import com.ea.async.test.BaseTest; 33 | 34 | import org.junit.Test; 35 | import org.objectweb.asm.ClassReader; 36 | import org.objectweb.asm.tree.analysis.AnalyzerException; 37 | 38 | import java.io.IOException; 39 | import java.lang.reflect.InvocationTargetException; 40 | 41 | import static org.junit.Assert.assertFalse; 42 | import static org.junit.Assert.assertTrue; 43 | 44 | public class InitRemovalTest extends BaseTest 45 | { 46 | public static class StaticUse 47 | { 48 | public static void callInit() 49 | { 50 | Async.init(); 51 | } 52 | } 53 | 54 | @Test 55 | public void testAwaitInitRemoval() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, IOException, AnalyzerException 56 | { 57 | StaticUse.callInit(); 58 | ClassReader cr = new ClassReader(StaticUse.class.getResourceAsStream(StaticUse.class.getName().replaceAll("^.*[.]", "") + ".class")); 59 | assertTrue(mentionsAwait(cr)); 60 | final byte[] bytes = new Transformer().transform(getClass().getClassLoader(), cr); 61 | ClassReader cr2 = new ClassReader(bytes); 62 | assertFalse(mentionsAwait(cr2)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/instrumentation/TransformerMainErrorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import com.ea.async.test.BaseTest; 32 | 33 | import org.junit.Test; 34 | import org.objectweb.asm.ClassReader; 35 | import org.objectweb.asm.ClassWriter; 36 | import org.objectweb.asm.MethodVisitor; 37 | import org.objectweb.asm.tree.ClassNode; 38 | 39 | import java.io.ByteArrayOutputStream; 40 | import java.io.OutputStreamWriter; 41 | import java.io.PrintStream; 42 | import java.io.StringWriter; 43 | import java.nio.file.Files; 44 | import java.nio.file.Path; 45 | import java.nio.file.Paths; 46 | import java.util.Arrays; 47 | 48 | import static org.junit.Assert.*; 49 | import static org.objectweb.asm.Opcodes.*; 50 | 51 | public class TransformerMainErrorTest extends BaseTest 52 | { 53 | 54 | public static final String COM_EA_ASYNC_TASK = "com/ea/async/Task"; 55 | 56 | // sanity check of the creator 57 | @Test 58 | @SuppressWarnings("unchecked") 59 | public void transformerError() throws Exception 60 | { 61 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 62 | final PrintStream printStream = new PrintStream(out); 63 | final PrintStream err = System.err; 64 | System.setErr(printStream); 65 | try 66 | { 67 | final ClassNode cn = createClassNode(Object.class, cw -> { 68 | MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;)Ljava/lang/Object;", null, new String[]{ "java/lang/Exception" }); 69 | mv.visitCode(); 70 | mv.visitVarInsn(ALOAD, 1); 71 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 72 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 73 | mv.visitInsn(POP); 74 | mv.visitVarInsn(ALOAD, 1); 75 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 76 | mv.visitInsn(ARETURN); 77 | mv.visitMaxs(1, 2); 78 | mv.visitEnd(); 79 | }); 80 | ClassWriter cw = new ClassWriter(0); 81 | cn.accept(cw); 82 | final byte[] bytes = new Transformer().transform(getClass().getClassLoader(), new ClassReader(cw.toByteArray())); 83 | 84 | final Main main = new Main(); 85 | final Path path = Paths.get("target/transformerError/classes2").resolve(cn.name + ".class"); 86 | Files.deleteIfExists(path); 87 | Files.createDirectories(path.getParent()); 88 | Files.write(path, cw.toByteArray()); 89 | 90 | // still not transformed 91 | final byte[] original = Files.readAllBytes(path); 92 | assertFalse(Arrays.equals(bytes, original)); 93 | 94 | final Path path3 = Paths.get("target/transformerError/classes3").resolve(cn.name + ".class"); 95 | Files.deleteIfExists(path3); 96 | // in output dir 97 | main.doMain(new String[]{ "-d", "target/transformerError/classes3", path.toString() }); 98 | printStream.flush(); 99 | assertTrue(new String(out.toByteArray()).startsWith("Invalid use of")); 100 | out.reset(); 101 | assertArrayEquals(bytes, Files.readAllBytes(path3)); 102 | // still unchanged 103 | assertArrayEquals(original, Files.readAllBytes(path)); 104 | 105 | // passing a dir as parameter 106 | final Path path4 = Paths.get("target/transformerError/classes4").resolve(cn.name + ".class"); 107 | Files.deleteIfExists(path4); 108 | main.doMain(new String[]{ "-d", "target/transformerError/classes4", path.getParent().toString() }); 109 | printStream.flush(); 110 | assertTrue(new String(out.toByteArray()).startsWith("Invalid use of")); 111 | out.reset(); 112 | assertTrue("Can't find file: " + path4, Files.exists(path4)); 113 | assertArrayEquals(bytes, Files.readAllBytes(path4)); 114 | // still unchanged 115 | assertArrayEquals(original, Files.readAllBytes(path)); 116 | 117 | // in place 118 | main.doMain(new String[]{ path.toString() }); 119 | printStream.flush(); 120 | assertTrue(new String(out.toByteArray()).startsWith("Invalid use of")); 121 | out.reset(); 122 | assertArrayEquals(bytes, Files.readAllBytes(path)); 123 | assertFalse(Arrays.equals(original, Files.readAllBytes(path))); 124 | } 125 | finally 126 | { 127 | System.setErr(err); 128 | } 129 | 130 | } 131 | 132 | 133 | } 134 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/instrumentation/TransformerMainTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import com.ea.async.Task; 32 | import com.ea.async.test.BaseTest; 33 | 34 | import org.junit.Test; 35 | import org.objectweb.asm.ClassReader; 36 | import org.objectweb.asm.ClassWriter; 37 | import org.objectweb.asm.MethodVisitor; 38 | import org.objectweb.asm.tree.ClassNode; 39 | 40 | import java.io.ByteArrayInputStream; 41 | import java.nio.file.Files; 42 | import java.nio.file.Path; 43 | import java.nio.file.Paths; 44 | import java.util.Arrays; 45 | 46 | import static org.junit.Assert.*; 47 | import static org.objectweb.asm.Opcodes.*; 48 | 49 | public class TransformerMainTest extends BaseTest 50 | { 51 | 52 | public static final String COM_EA_ASYNC_TASK = "com/ea/async/Task"; 53 | 54 | // sanity check of the creator 55 | @Test 56 | @SuppressWarnings("unchecked") 57 | public void transformer() throws Exception 58 | { 59 | final ClassNode cn = createClassNode(AsyncFunction.class, cw -> { 60 | MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;)Lcom/ea/async/Task;", null, new String[]{ "java/lang/Exception" }); 61 | mv.visitCode(); 62 | mv.visitVarInsn(ALOAD, 1); 63 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 64 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 65 | mv.visitInsn(POP); 66 | mv.visitVarInsn(ALOAD, 1); 67 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 68 | mv.visitInsn(ARETURN); 69 | mv.visitMaxs(1, 2); 70 | mv.visitEnd(); 71 | }); 72 | ClassWriter cw = new ClassWriter(0); 73 | cn.accept(cw); 74 | final byte[] bytes = new Transformer().transform(getClass().getClassLoader(), new ClassReader(cw.toByteArray())); 75 | 76 | final Main main = new Main(); 77 | final Path path = Paths.get("target/classes2").resolve(cn.name + ".class"); 78 | Files.deleteIfExists(path); 79 | Files.createDirectories(path.getParent()); 80 | Files.write(path, cw.toByteArray()); 81 | 82 | // still not transformed 83 | final byte[] original = Files.readAllBytes(path); 84 | assertFalse(Arrays.equals(bytes, original)); 85 | 86 | final Path path3 = Paths.get("target/classes3").resolve(cn.name + ".class"); 87 | Files.deleteIfExists(path3); 88 | // in output dir 89 | main.doMain(new String[]{ "-d", "target/classes3", path.toString() }); 90 | assertArrayEquals(bytes, Files.readAllBytes(path3)); 91 | // still unchanged 92 | assertArrayEquals(original, Files.readAllBytes(path)); 93 | 94 | // passing a dir as parameter 95 | final Path path4 = Paths.get("target/classes4").resolve(cn.name + ".class"); 96 | Files.deleteIfExists(path4); 97 | main.doMain(new String[]{ "-d", "target/classes4", path.getParent().toString() }); 98 | assertTrue("Can't find file: " + path4, Files.exists(path4)); 99 | assertArrayEquals(bytes, Files.readAllBytes(path4)); 100 | // still unchanged 101 | assertArrayEquals(original, Files.readAllBytes(path)); 102 | 103 | // in place 104 | main.doMain(new String[]{ path.toString() }); 105 | assertArrayEquals(bytes, Files.readAllBytes(path)); 106 | assertFalse(Arrays.equals(original, Files.readAllBytes(path))); 107 | 108 | 109 | } 110 | 111 | 112 | } 113 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/instrumentation/TransformerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.instrumentation; 30 | 31 | import com.ea.async.test.BaseTest; 32 | import com.ea.async.Task; 33 | 34 | import org.junit.Test; 35 | import org.objectweb.asm.ClassReader; 36 | import org.objectweb.asm.ClassWriter; 37 | import org.objectweb.asm.MethodVisitor; 38 | import org.objectweb.asm.tree.ClassNode; 39 | 40 | import static org.junit.Assert.assertEquals; 41 | import static org.objectweb.asm.Opcodes.*; 42 | 43 | public class TransformerTest extends BaseTest 44 | { 45 | 46 | public static final String COM_EA_ASYNC_TASK = "com/ea/async/Task"; 47 | 48 | // sanity check of the creator 49 | @Test 50 | @SuppressWarnings("unchecked") 51 | public void simpleAsyncMethod() throws Exception 52 | { 53 | final ClassNode cn = createClassNode(AsyncFunction.class, cw -> { 54 | MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;)Lcom/ea/async/Task;", null, new String[]{ "java/lang/Exception" }); 55 | mv.visitCode(); 56 | mv.visitVarInsn(ALOAD, 1); 57 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 58 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 59 | mv.visitInsn(POP); 60 | mv.visitVarInsn(ALOAD, 1); 61 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 62 | mv.visitInsn(ARETURN); 63 | mv.visitMaxs(1, 2); 64 | mv.visitEnd(); 65 | }); 66 | ClassWriter cw = new ClassWriter(0); 67 | cn.accept(cw); 68 | final byte[] bytes = new Transformer().transform(getClass().getClassLoader(), new ClassReader(cw.toByteArray())); 69 | DevDebug.debugSaveTrace(cn.name, bytes); 70 | assertEquals("hello", createClass(AsyncFunction.class, bytes).apply(Task.fromValue("hello")).join()); 71 | } 72 | 73 | @Test 74 | @SuppressWarnings("unchecked") 75 | public void withLocals() throws Exception 76 | { 77 | final ClassNode cn = createClassNode(AsyncFunction.class, cw -> { 78 | MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;)L"+COM_EA_ASYNC_TASK+";", null, new String[]{ "java/lang/Exception" }); 79 | mv.visitCode(); 80 | mv.visitIntInsn(SIPUSH, 1); 81 | mv.visitVarInsn(ISTORE, 2); 82 | 83 | mv.visitInsn(LCONST_0); 84 | mv.visitVarInsn(LSTORE, 3); 85 | mv.visitVarInsn(ALOAD, 1); 86 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 87 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 88 | mv.visitInsn(POP); 89 | mv.visitVarInsn(ALOAD, 1); 90 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 91 | mv.visitInsn(ARETURN); 92 | mv.visitMaxs(2, 5); 93 | mv.visitEnd(); 94 | }); 95 | ClassWriter cw = new ClassWriter(0); 96 | cn.accept(cw); 97 | final byte[] bytes = new Transformer().transform(getClass().getClassLoader(), new ClassReader(cw.toByteArray())); 98 | // DevDebug.debugSaveTrace(cn.name, bytes); 99 | assertEquals("hello", createClass(AsyncFunction.class, bytes).apply(Task.fromValue("hello")).join()); 100 | } 101 | 102 | 103 | @Test(timeout = 10_000L) 104 | @SuppressWarnings("unchecked") 105 | public void withTwoFutures() throws Exception 106 | { 107 | final ClassNode cn = createClassNode(AsyncBiFunction.class, cw -> { 108 | MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)L"+COM_EA_ASYNC_TASK+";", null, new String[]{ "java/lang/Exception" }); 109 | mv.visitCode(); 110 | 111 | mv.visitVarInsn(ALOAD, 1); 112 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 113 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 114 | mv.visitInsn(POP); 115 | 116 | mv.visitVarInsn(ALOAD, 2); 117 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 118 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 119 | mv.visitInsn(POP); 120 | 121 | mv.visitVarInsn(ALOAD, 1); 122 | mv.visitTypeInsn(CHECKCAST, COM_EA_ASYNC_TASK); 123 | mv.visitInsn(ARETURN); 124 | mv.visitMaxs(2, 5); 125 | mv.visitEnd(); 126 | }); 127 | ClassWriter cw = new ClassWriter(0); 128 | cn.accept(cw); 129 | final byte[] bytes = new Transformer().transform(getClass().getClassLoader(), new ClassReader(cw.toByteArray())); 130 | DevDebug.debugSaveTrace(cn.name, bytes); 131 | 132 | assertEquals("hello", createClass(AsyncBiFunction.class, bytes).apply(Task.fromValue("hello"), Task.fromValue("world")).join()); 133 | 134 | final Task rest = createClass(AsyncBiFunction.class, bytes).apply(getBlockedTask("hello"), getBlockedTask("world")); 135 | completeFutures(); 136 | assertEquals("hello", rest.join()); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/AConstNullTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import static com.ea.async.Async.await; 36 | import static org.junit.Assert.assertNull; 37 | 38 | public class AConstNullTest extends BaseTest 39 | { 40 | 41 | @Test 42 | public void nullInitialization() throws Exception 43 | { 44 | final Task res = NullInit.doIt(getBlockedTask()); 45 | completeFutures(); 46 | assertNull(res.join()); 47 | 48 | } 49 | 50 | public static class NullInit 51 | { 52 | public static Task doIt(Task task) 53 | { 54 | String x = null; 55 | try 56 | { 57 | await(task); 58 | return Task.done(); 59 | } 60 | catch (Exception ex) 61 | { 62 | return Task.done(); 63 | } 64 | } 65 | } 66 | 67 | @Test 68 | public void nullInitialization2() throws Exception 69 | { 70 | final Task res = NullInit2.doIt(getBlockedTask()); 71 | completeFutures(); 72 | assertNull(res.join()); 73 | 74 | } 75 | 76 | public static class NullInit2 77 | { 78 | public static Task doIt(Task task) 79 | { 80 | String x = null; 81 | String y = x; 82 | try 83 | { 84 | await(task); 85 | return Task.done(); 86 | } 87 | catch (Exception ex) 88 | { 89 | return Task.done(); 90 | } 91 | } 92 | } 93 | 94 | @Test 95 | public void nullInitialization3() throws Exception 96 | { 97 | final Task res = NullInit3.doIt(getBlockedTask()); 98 | completeFutures(); 99 | assertNull(res.join()); 100 | 101 | } 102 | 103 | public static class NullInit3 104 | { 105 | public static Task doIt(Task task) 106 | { 107 | String x = null; 108 | call0(x, await(task)); 109 | return Task.done(); 110 | } 111 | } 112 | 113 | public static void call0(final Object a, final Object b) 114 | { 115 | } 116 | 117 | 118 | @Test 119 | public void nullInitialization4() throws Exception 120 | { 121 | final Task res = NullInit4.doIt(getBlockedTask()); 122 | completeFutures(); 123 | assertNull(res.join()); 124 | 125 | } 126 | 127 | public static class NullInit4 128 | { 129 | public static Task doIt(Task task) 130 | { 131 | String x = null; 132 | call0(await(task), x); 133 | return Task.done(); 134 | } 135 | } 136 | 137 | 138 | @Test 139 | public void nullInTheStack() throws Exception 140 | { 141 | debugTransform(AConstNullTest.class.getName() + "$NullInTheStack"); 142 | final Task res = NullInTheStack.doIt(getBlockedTask()); 143 | completeFutures(); 144 | assertNull(res.join()); 145 | } 146 | 147 | public static class NullInTheStack 148 | { 149 | public static Task doIt(Task task) 150 | { 151 | call2(null, await(task)); 152 | return Task.done(); 153 | } 154 | 155 | private static void call2(final Object o, final Object p) 156 | { 157 | } 158 | } 159 | 160 | 161 | @Test 162 | public void nullInTheStack2() throws Exception 163 | { 164 | debugTransform(AConstNullTest.class.getName() + "$NullInTheStack2"); 165 | final Task res = NullInTheStack2.doIt(getBlockedTask()); 166 | completeFutures(); 167 | assertNull(res.join()); 168 | } 169 | 170 | public static class NullInTheStack2 171 | { 172 | public static Task doIt(Task task) 173 | { 174 | call2(null, await(task)); 175 | return Task.done(); 176 | } 177 | private static void call2(final String o, final Object p) 178 | { 179 | } 180 | 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/ArrayVarsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import static com.ea.async.Async.await; 36 | import static com.ea.async.Task.fromValue; 37 | import static junit.framework.Assert.assertEquals; 38 | 39 | public class ArrayVarsTest extends BaseTest 40 | { 41 | @Test 42 | public void arrayParams01() 43 | { 44 | class Experiment 45 | { 46 | Task doIt(Object params[]) 47 | { 48 | await(Task.done()); 49 | return fromValue(params[0]); 50 | } 51 | } 52 | assertEquals("x", new Experiment().doIt(new Object[]{"x"}).join()); 53 | } 54 | 55 | @Test 56 | public void arrayParams02() 57 | { 58 | class Experiment 59 | { 60 | Task doIt(Object params[][]) 61 | { 62 | await(Task.done()); 63 | return fromValue(params[0][0]); 64 | } 65 | } 66 | assertEquals("x", new Experiment().doIt(new Object[][]{{"x"}}).join()); 67 | } 68 | 69 | @Test 70 | public void arrayParams03() 71 | { 72 | class Experiment 73 | { 74 | Task doIt(Object params[][][]) 75 | { 76 | await(Task.done()); 77 | return fromValue(params[0][0][0]); 78 | } 79 | } 80 | assertEquals("x", new Experiment().doIt(new Object[][][]{{{"x"}}}).join()); 81 | } 82 | 83 | @Test 84 | public void arrayParams04() 85 | { 86 | class Experiment 87 | { 88 | Task doIt(Object params[][][][]) 89 | { 90 | await(Task.done()); 91 | return fromValue(params[0][0][0][0]); 92 | } 93 | } 94 | assertEquals("x", new Experiment().doIt(new Object[][][][]{{{{"x"}}}}).join()); 95 | } 96 | 97 | 98 | @Test 99 | public void optionalParam() 100 | { 101 | class Experiment 102 | { 103 | Task doIt(Object... params) 104 | { 105 | await(Task.done()); 106 | return fromValue(params[0]); 107 | } 108 | } 109 | assertEquals("x", new Experiment().doIt(new Object[]{"x"}).join()); 110 | } 111 | 112 | 113 | @Test 114 | public void stringArrayParams01() 115 | { 116 | class Experiment 117 | { 118 | Task doIt(String params[]) 119 | { 120 | await(Task.done()); 121 | return fromValue(params[0]); 122 | } 123 | } 124 | assertEquals("x", new Experiment().doIt(new String[]{"x"}).join()); 125 | } 126 | 127 | @Test 128 | public void arrayVar01() 129 | { 130 | class Experiment 131 | { 132 | Task doIt(String x) 133 | { 134 | Object arr[] = new Object[]{x}; 135 | await(Task.done()); 136 | return fromValue(arr[0]); 137 | } 138 | } 139 | assertEquals("x", new Experiment().doIt("x").join()); 140 | } 141 | 142 | 143 | @Test 144 | public void stringVar01() 145 | { 146 | class Experiment 147 | { 148 | Task doIt(String x) 149 | { 150 | String arr[] = new String[]{x}; 151 | await(Task.done()); 152 | return fromValue(arr[0]); 153 | } 154 | } 155 | assertEquals("x", new Experiment().doIt("x").join()); 156 | } 157 | 158 | @Test 159 | public void primitiveArray01() 160 | { 161 | class Experiment 162 | { 163 | Task doIt(int x) 164 | { 165 | int arr[] = new int[]{x}; 166 | await(Task.done()); 167 | return fromValue(arr[0]); 168 | } 169 | } 170 | assertEquals(10, new Experiment().doIt(10).join()); 171 | } 172 | 173 | @Test 174 | public void arraysWithAwait01() 175 | { 176 | class Experiment 177 | { 178 | Task doIt(Object params[]) 179 | { 180 | await(getBlockedFuture()); 181 | return fromValue(params[0]); 182 | } 183 | } 184 | final Task task = new Experiment().doIt(new Object[]{"x"}); 185 | completeFutures(); 186 | assertEquals("x", task.join()); 187 | } 188 | 189 | @Test 190 | public void arraysWithAwait02() 191 | { 192 | class Experiment 193 | { 194 | Task doIt(Object params[]) 195 | { 196 | Object arr[][] = new Object[][]{params}; 197 | await(getBlockedFuture()); 198 | return fromValue(arr[0][0]); 199 | } 200 | } 201 | final Task task = new Experiment().doIt(new Object[]{"x"}); 202 | completeFutures(); 203 | assertEquals("x", task.join()); 204 | } 205 | 206 | 207 | @Test 208 | public void arraysWithAwait03() 209 | { 210 | class Experiment 211 | { 212 | Task doIt(Object params[]) 213 | { 214 | Object arr[][]; 215 | if (params != null) 216 | { 217 | arr = new Object[][]{params}; 218 | await(getBlockedFuture()); 219 | } 220 | else 221 | { 222 | arr = new Object[][]{params, null}; 223 | await(getBlockedFuture()); 224 | } 225 | return fromValue(arr[0][0]); 226 | } 227 | } 228 | final Task task = new Experiment().doIt(new Object[]{"x"}); 229 | completeFutures(); 230 | assertEquals("x", task.join()); 231 | } 232 | 233 | @Test 234 | public void arraysAndIfs() 235 | { 236 | class Experiment 237 | { 238 | Task doIt(int x) 239 | { 240 | Object[][] arr = new Object[][]{{x}}; 241 | if (x == 11) 242 | { 243 | arr = null; 244 | } 245 | // this forces a stack frame map to be created 246 | else 247 | { 248 | 249 | await(getBlockedFuture()); 250 | } 251 | return fromValue(arr[0][0]); 252 | } 253 | } 254 | final Task task = new Experiment().doIt(10); 255 | completeFutures(); 256 | assertEquals(10, task.join()); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/BaseTestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | 32 | import com.ea.async.Task; 33 | 34 | import org.junit.Test; 35 | import org.objectweb.asm.MethodVisitor; 36 | 37 | import java.util.ArrayList; 38 | import java.util.List; 39 | import java.util.concurrent.Callable; 40 | 41 | import static org.junit.Assert.*; 42 | import static org.objectweb.asm.Opcodes.*; 43 | 44 | 45 | public class BaseTestTest extends BaseTest 46 | { 47 | 48 | // sanity check of the creator 49 | @Test 50 | public void testCreateClass() throws Exception 51 | { 52 | assertTrue(createClass(ArrayList.class, cv -> { 53 | }) instanceof List); 54 | assertEquals("hello", createClass(Callable.class, cv -> { 55 | MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "call", "()Ljava/lang/Object;", null, new String[]{ "java/lang/Exception" }); 56 | mv.visitCode(); 57 | mv.visitLdcInsn("hello"); 58 | mv.visitInsn(ARETURN); 59 | mv.visitMaxs(1, 1); 60 | mv.visitEnd(); 61 | }).call()); 62 | } 63 | 64 | 65 | // sanity check of the creator 66 | @Test 67 | public void simpleAsyncMethod() throws Exception 68 | { 69 | final Task task = createClass(AsyncCallable.class, cw -> { 70 | MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "call", "()Lcom/ea/async/Task;", null, new String[]{ "java/lang/Exception" }); 71 | mv.visitCode(); 72 | mv.visitMethodInsn(INVOKESTATIC, "com/ea/async/Task", "done", "()Lcom/ea/async/Task;", false); 73 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 74 | mv.visitInsn(POP); 75 | mv.visitMethodInsn(INVOKESTATIC, "com/ea/async/Task", "done", "()Lcom/ea/async/Task;", false); 76 | mv.visitInsn(ARETURN); 77 | mv.visitMaxs(1, 1); 78 | mv.visitEnd(); 79 | }).call(); 80 | assertTrue(task.isDone()); 81 | } 82 | 83 | 84 | // sanity check of the creator 85 | @Test 86 | @SuppressWarnings("unchecked") 87 | public void simpleBlockingAsyncMethod() throws Exception 88 | { 89 | final Task task = createClass(AsyncFunction.class, cw -> { 90 | MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "apply", "(Ljava/lang/Object;)Lcom/ea/async/Task;", null, new String[]{ "java/lang/Exception" }); 91 | mv.visitCode(); 92 | mv.visitVarInsn(ALOAD, 1); 93 | mv.visitTypeInsn(CHECKCAST, "com/ea/async/Task"); 94 | mv.visitMethodInsn(INVOKESTATIC, ASYNC_NAME, "await", "(Ljava/util/concurrent/CompletableFuture;)Ljava/lang/Object;", false); 95 | mv.visitInsn(POP); 96 | mv.visitVarInsn(ALOAD, 1); 97 | mv.visitTypeInsn(CHECKCAST, "com/ea/async/Task"); 98 | mv.visitInsn(ARETURN); 99 | mv.visitMaxs(1, 2); 100 | mv.visitEnd(); 101 | }).apply(getBlockedTask("hello")); 102 | assertFalse(task.isDone()); 103 | completeFutures(); 104 | assertEquals("hello", task.join()); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/BasicInstrTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import org.junit.Test; 32 | 33 | import java.lang.reflect.InvocationTargetException; 34 | import java.util.concurrent.CompletableFuture; 35 | 36 | import static com.ea.async.Async.await; 37 | import static org.junit.Assert.assertEquals; 38 | 39 | public class BasicInstrTest extends BaseTest 40 | { 41 | private static class Basic 42 | { 43 | 44 | static String concat(int i, long j, float f, double d, Object obj, boolean b) 45 | { 46 | return i + ":" + j + ":" + f + ":" + d + ":" + obj + ":" + b; 47 | } 48 | 49 | public CompletableFuture doSomething(CompletableFuture blocker, int var) 50 | { 51 | return CompletableFuture.completedFuture(concat(var, 10_000_000_000L, 1.5f, 3.5d, await(blocker), true)); 52 | } 53 | } 54 | 55 | @Test 56 | public void testInstrumentation() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 57 | { 58 | CompletableFuture blocker = new CompletableFuture<>(); 59 | final CompletableFuture res = new Basic().doSomething(blocker, 5); 60 | blocker.complete("zzz"); 61 | assertEquals("5:10000000000:1.5:3.5:zzz:true", res.join()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/BasicTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Async; 32 | 33 | import org.junit.Test; 34 | 35 | import java.util.concurrent.CompletableFuture; 36 | 37 | import static com.ea.async.Async.await; 38 | import static org.junit.Assert.assertEquals; 39 | 40 | public class BasicTest extends BaseTest 41 | { 42 | public static class SomethingAsync 43 | { 44 | public CompletableFuture doSomething(CompletableFuture blocker) 45 | { 46 | String res = await(blocker); 47 | return CompletableFuture.completedFuture(":" + res); 48 | } 49 | } 50 | 51 | public static class SomethingWithDataMutation 52 | { 53 | public CompletableFuture doSomething(CompletableFuture blocker) 54 | { 55 | String op = "1"; 56 | String res = "[" + await(blocker) + "]"; 57 | op = op + "2"; 58 | return CompletableFuture.completedFuture(":" + op + res); 59 | } 60 | } 61 | 62 | public static class SomethingWithLocalsAndStack 63 | { 64 | public CompletableFuture doSomething(CompletableFuture blocker) 65 | { 66 | int local = 7; 67 | String res = ":" + Math.max(local, await(blocker).length()); 68 | return CompletableFuture.completedFuture(res); 69 | } 70 | } 71 | 72 | public static class SomethingAsyncWithEx 73 | { 74 | public CompletableFuture doSomething(CompletableFuture blocker) 75 | { 76 | try 77 | { 78 | String res = await(blocker); 79 | return CompletableFuture.completedFuture(":" + res); 80 | } 81 | catch (Exception ex) 82 | { 83 | return CompletableFuture.completedFuture(":" + ex.getCause().getMessage()); 84 | } 85 | } 86 | } 87 | 88 | @Test 89 | public void testDirectPathNonBlocking() throws IllegalAccessException, InstantiationException 90 | { 91 | // test an example where the async function blocks (returns incomplete future) 92 | // this would not work without instrumentation 93 | final SomethingAsync a = new SomethingAsync(); 94 | 95 | CompletableFuture blocker = CompletableFuture.completedFuture("x"); 96 | final CompletableFuture res = a.doSomething(blocker); 97 | assertEquals(":x", res.join()); 98 | } 99 | 100 | @Test(timeout = 2_000) 101 | public void testBlocking() throws IllegalAccessException, InstantiationException 102 | { 103 | final SomethingAsync a = new SomethingAsync(); 104 | CompletableFuture blocker = new CompletableFuture<>(); 105 | final CompletableFuture res = a.doSomething(blocker); 106 | blocker.complete("x"); 107 | assertEquals(":x", res.join()); 108 | } 109 | 110 | 111 | @Test(timeout = 2_000) 112 | public void testBlockingWithStackAndLocal() throws IllegalAccessException, InstantiationException 113 | { 114 | final SomethingWithLocalsAndStack a = new SomethingWithLocalsAndStack(); 115 | 116 | CompletableFuture blocker = new CompletableFuture<>(); 117 | final CompletableFuture res = a.doSomething(blocker); 118 | blocker.complete("0123456789"); 119 | assertEquals(":10", res.join()); 120 | } 121 | 122 | @Test(timeout = 2_000) 123 | public void testBlockingAndException() throws IllegalAccessException, InstantiationException 124 | { 125 | final SomethingAsyncWithEx a = new SomethingAsyncWithEx(); 126 | 127 | CompletableFuture blocker = new CompletableFuture<>(); 128 | final CompletableFuture res = a.doSomething(blocker); 129 | blocker.completeExceptionally(new RuntimeException("Exception")); 130 | assertEquals(":Exception", res.join()); 131 | } 132 | 133 | @Test(timeout = 2_000) 134 | public void testDataFlow() 135 | { 136 | final SomethingWithDataMutation a = new SomethingWithDataMutation(); 137 | 138 | CompletableFuture blocker = new CompletableFuture<>(); 139 | final CompletableFuture res = a.doSomething(blocker); 140 | blocker.complete("x"); 141 | assertEquals(":12[x]", res.join()); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/CompletionStageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import org.junit.Test; 32 | 33 | import java.util.concurrent.CompletableFuture; 34 | import java.util.concurrent.CompletionStage; 35 | 36 | import static com.ea.async.Async.await; 37 | import static java.util.concurrent.CompletableFuture.completedFuture; 38 | import static org.junit.Assert.assertEquals; 39 | 40 | public class CompletionStageTest extends BaseTest 41 | { 42 | 43 | @Test 44 | public void outOfTheWay() 45 | { 46 | class Experiment 47 | { 48 | 49 | CompletionStage doIt(int a, int b) 50 | { 51 | await(getBlockedTask()); 52 | return CompletableFuture.completedFuture(a + b); 53 | } 54 | } 55 | CompletionStage res = new Experiment().doIt(1, 2); 56 | 57 | completeFutures(); 58 | assertEquals(3, (int) res.toCompletableFuture().join()); 59 | } 60 | 61 | 62 | @Test 63 | public void completionStageParam() 64 | { 65 | class Experiment 66 | { 67 | 68 | CompletionStage doIt(CompletionStage stage) 69 | { 70 | String result = await(stage); 71 | return completedFuture(result); 72 | } 73 | } 74 | final CompletableFuture future = new CompletableFuture<>(); 75 | CompletionStage res = new Experiment().doIt(future); 76 | future.complete("test"); 77 | assertEquals("test", res.toCompletableFuture().join()); 78 | } 79 | 80 | @Test 81 | public void completionStageArgument() { 82 | class Experiment 83 | { 84 | 85 | CompletionStage doIt(CompletionStage stage, int b) { 86 | int a = await(stage); 87 | return CompletableFuture.completedFuture(a + b); 88 | } 89 | } 90 | CompletionStage task = getBlockedTask(1); 91 | CompletionStage res = new Experiment().doIt(task, 2); 92 | 93 | completeFutures(); 94 | assertEquals(3, (int) res.toCompletableFuture().join()); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/ExceptionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Async; 32 | import com.ea.async.Task; 33 | 34 | import org.junit.Test; 35 | 36 | import java.lang.reflect.InvocationTargetException; 37 | 38 | import static com.ea.async.Async.await; 39 | import static junit.framework.TestCase.assertNull; 40 | import static org.junit.Assert.assertEquals; 41 | import static org.junit.Assert.assertTrue; 42 | 43 | public class ExceptionTest extends BaseTest 44 | { 45 | 46 | @Test 47 | public void testTryCatch() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 48 | { 49 | final Task res = doTryCatch(); 50 | completeFutures(); 51 | assertEquals((Integer) 10, res.join()); 52 | } 53 | 54 | private Task doTryCatch() 55 | { 56 | try 57 | { 58 | if (await(getBlockedFuture(10)) == 10) 59 | { 60 | throw new IllegalArgumentException(String.valueOf(10)); 61 | } 62 | 63 | } 64 | catch (IllegalArgumentException ex) 65 | { 66 | return Task.fromValue(10); 67 | } 68 | return null; 69 | } 70 | 71 | @Test 72 | public void testFinally() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 73 | { 74 | final Task res = doTestFinally(); 75 | completeFutures(); 76 | assertEquals((Integer) 1337, res.join()); 77 | } 78 | 79 | private Task doTestFinally() 80 | { 81 | try 82 | { 83 | if (await(getBlockedFuture(10)) == 10) 84 | { 85 | throw new IllegalArgumentException(String.valueOf(10)); 86 | } 87 | 88 | } 89 | finally 90 | { 91 | return Task.fromValue(1337); 92 | } 93 | } 94 | 95 | 96 | @Test 97 | public void testTryCatch2() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 98 | { 99 | final Task res = doTryCatch2(); 100 | completeFutures(); 101 | assertTrue(res.isDone()); 102 | } 103 | 104 | private Task doTryCatch2() 105 | { 106 | int c = 1; 107 | try 108 | { 109 | await(getBlockedFuture()); 110 | } 111 | catch (Exception ex) 112 | { 113 | // once this was causing a verification error, now fixed 114 | c = c + 1; 115 | } 116 | return Task.done(); 117 | } 118 | 119 | 120 | @Test 121 | public void testTryCatch3() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 122 | { 123 | final Task res = doTryCatch3(); 124 | completeFutures(); 125 | assertEquals("fail", res.join()); 126 | } 127 | 128 | private Task doTryCatch3() 129 | { 130 | int c = 1; 131 | try 132 | { 133 | await(getBlockedTask()); 134 | await(getBlockedTask()); 135 | await(getBlockedTask()); 136 | await(getBlockedTask()); 137 | await(Task.fromException(new Exception("fail"))); 138 | } 139 | catch (Exception ex) 140 | { 141 | await(getBlockedTask()); 142 | await(getBlockedTask()); 143 | await(getBlockedTask()); 144 | await(getBlockedTask()); 145 | return Task.fromValue(ex.getCause().getMessage()); 146 | } 147 | return Task.done(); 148 | } 149 | 150 | 151 | @Test 152 | public void testTryCatch4() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 153 | { 154 | final Task res = doTryCatch4(); 155 | completeFutures(); 156 | assertEquals("fail", res.join()); 157 | } 158 | 159 | private Task doTryCatch4() 160 | { 161 | int c = 1; 162 | try 163 | { 164 | await(getBlockedTask()); 165 | await(getBlockedTask()); 166 | if (await(getBlockedTask()) == null) 167 | { 168 | throw new Exception("fail"); 169 | } 170 | await(getBlockedTask()); 171 | } 172 | catch (Exception ex) 173 | { 174 | await(getBlockedTask()); 175 | await(getBlockedTask()); 176 | await(getBlockedTask()); 177 | await(getBlockedTask()); 178 | return Task.fromValue(ex.getMessage()); 179 | } 180 | return Task.done(); 181 | } 182 | 183 | 184 | private Object stackAnalysisProblem(final Exception ex) 185 | { 186 | Throwable t = ex; 187 | 188 | while (t.getCause() != null && !(t instanceof IllegalAccessException)) 189 | { 190 | t = t.getCause(); 191 | } 192 | 193 | if (t instanceof IllegalAccessException) 194 | { 195 | IllegalAccessException wex = (IllegalAccessException) t; 196 | } 197 | 198 | return null; 199 | } 200 | 201 | 202 | @Test 203 | public void smallTest() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 204 | { 205 | final Task res = doIt(Task.done()); 206 | completeFutures(); 207 | assertNull(res.join()); 208 | } 209 | 210 | 211 | public Task doIt(Task t) 212 | { 213 | try 214 | { 215 | await(t); 216 | } 217 | catch (Exception ex) 218 | { 219 | await(t); 220 | } 221 | return t; 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/FunctionCallTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import java.util.ArrayList; 36 | import java.util.List; 37 | import java.util.concurrent.CompletableFuture; 38 | 39 | import static com.ea.async.Async.await; 40 | import static org.junit.Assert.assertEquals; 41 | 42 | public class FunctionCallTest extends BaseTest 43 | { 44 | public static class TaskSomethingAsync 45 | { 46 | private List blockers = new ArrayList<>(); 47 | 48 | public Task doSomething() 49 | { 50 | String res1 = await(blocker()); 51 | return Task.fromValue(":" + res1); 52 | } 53 | 54 | private CompletableFuture blocker() 55 | { 56 | final CompletableFuture blocker = new CompletableFuture<>(); 57 | blockers.add(blocker); 58 | return blocker; 59 | } 60 | 61 | public void completeBlockers() 62 | { 63 | for (int i = 0; i < blockers.size(); i++) 64 | { 65 | final CompletableFuture fut = blockers.get(i); 66 | fut.complete("str " + i); 67 | } 68 | } 69 | } 70 | 71 | @Test 72 | public void testBlockingAndException() throws IllegalAccessException, InstantiationException 73 | { 74 | final TaskSomethingAsync a = new TaskSomethingAsync(); 75 | 76 | Task res = a.doSomething(); 77 | a.completeBlockers(); 78 | assertEquals(":str 0", res.join()); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/HowItShouldWorkTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import org.junit.Test; 32 | 33 | import java.util.concurrent.CompletableFuture; 34 | 35 | import static com.ea.async.Async.await; 36 | import static org.junit.Assert.assertEquals; 37 | import static org.junit.Assert.assertFalse; 38 | 39 | public class HowItShouldWorkTest 40 | { 41 | private static class WhatWillBeWritten 42 | { 43 | // @Async 44 | public CompletableFuture doSomething(CompletableFuture blocker) 45 | { 46 | String res = await(blocker); 47 | return CompletableFuture.completedFuture(":" + res); 48 | } 49 | } 50 | 51 | private static class HowItShouldBehave 52 | { 53 | public CompletableFuture doSomething(CompletableFuture blocker) 54 | { 55 | return blocker.thenApply(res -> ":" + res); 56 | } 57 | } 58 | 59 | private static class HowItShouldBeInstrumented 60 | { 61 | public CompletableFuture doSomething(CompletableFuture blocker) 62 | { 63 | if (!blocker.isDone()) 64 | { 65 | return blocker.exceptionally(t -> null) 66 | .thenCompose(t -> this.async$doSomething(blocker, 1, t)); 67 | } 68 | String res = (String) blocker.join(); 69 | return CompletableFuture.completedFuture(":" + res); 70 | } 71 | 72 | public CompletableFuture async$doSomething(CompletableFuture blocker, int async$state, Object async$result) 73 | { 74 | String res; 75 | switch (async$state) 76 | { 77 | case 1: 78 | if (!blocker.isDone()) 79 | { 80 | return blocker.exceptionally(t -> null) 81 | .thenCompose(t -> this.async$doSomething(blocker, 1, t)); 82 | } 83 | res = blocker.join(); 84 | return CompletableFuture.completedFuture(":" + res); 85 | default: 86 | throw new IllegalArgumentException(); 87 | } 88 | } 89 | } 90 | 91 | @Test 92 | public void testMockInstrumentation() 93 | { 94 | CompletableFuture blocker = new CompletableFuture<>(); 95 | final CompletableFuture res = new HowItShouldBeInstrumented().doSomething(blocker); 96 | assertFalse(blocker.isDone()); 97 | assertFalse(res.isDone()); 98 | blocker.complete("x"); 99 | assertEquals(":x", res.join()); 100 | } 101 | 102 | @Test 103 | public void testHowItShouldBehave() 104 | { 105 | CompletableFuture blocker = new CompletableFuture<>(); 106 | final CompletableFuture res = new HowItShouldBehave().doSomething(blocker); 107 | assertFalse(blocker.isDone()); 108 | assertFalse(res.isDone()); 109 | blocker.complete("x"); 110 | assertEquals(":x", res.join()); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/JoinTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import org.junit.Test; 32 | 33 | import java.util.concurrent.CompletableFuture; 34 | 35 | import static com.ea.async.Async.await; 36 | import static org.junit.Assert.assertEquals; 37 | 38 | public class JoinTest extends BaseTest 39 | { 40 | public static class OtherJoinCalls 41 | { 42 | public CompletableFuture doSomething(CompletableFuture blocker) 43 | { 44 | int local = 7; 45 | String res = ":" + Math.max(local, await(blocker).length()) + ":" + join() + ":" + join(2, 3); 46 | return CompletableFuture.completedFuture(res); 47 | } 48 | 49 | public Object join() 50 | { 51 | return 9; 52 | } 53 | 54 | public Object join(int a, int b) 55 | { 56 | return a + b; 57 | } 58 | } 59 | 60 | @Test 61 | public void testOtherJoinMethods() throws IllegalAccessException, InstantiationException 62 | { 63 | OtherJoinCalls a = new OtherJoinCalls(); 64 | 65 | CompletableFuture blocker = new CompletableFuture<>(); 66 | final CompletableFuture res = a.doSomething(blocker); 67 | blocker.complete("0123456789"); 68 | assertEquals(":10:9:5", res.join()); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/LambdaTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import static com.ea.async.Async.await; 36 | import static com.ea.async.Task.fromValue; 37 | import static org.junit.Assert.assertEquals; 38 | 39 | public class LambdaTest extends BaseTest 40 | { 41 | @Test 42 | public void testThenCompose() 43 | { 44 | Task task = getBlockedTask(10) 45 | .thenCompose(x -> fromValue(x + await(getBlockedFuture(20)))); 46 | completeFutures(); 47 | assertEquals((Integer) 30, task.join()); 48 | } 49 | 50 | 51 | @Test 52 | public void testLongLambda() 53 | { 54 | Task task = getBlockedTask(5) 55 | .thenCompose(x -> { 56 | await(getBlockedTask()); 57 | await(getBlockedTask()); 58 | await(getBlockedTask()); 59 | await(getBlockedTask()); 60 | return fromValue(11); 61 | }); 62 | completeFutures(); 63 | assertEquals((Integer) 11, task.join()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/LocalVarsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import java.lang.reflect.InvocationTargetException; 36 | 37 | import static com.ea.async.Async.await; 38 | import static com.ea.async.Task.done; 39 | import static com.ea.async.Task.fromValue; 40 | import static org.junit.Assert.assertEquals; 41 | 42 | public class LocalVarsTest extends BaseTest 43 | { 44 | 45 | @Test 46 | public void testRepeatedLocalVarsNames() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 47 | { 48 | final Task res = done().thenCompose(o -> { 49 | { 50 | String a = "a1"; 51 | } 52 | await(getBlockedTask()); 53 | { 54 | String a = "a2"; 55 | } 56 | return fromValue(10); 57 | }); 58 | completeFutures(); 59 | assertEquals((Integer) 10, res.join()); 60 | } 61 | 62 | @Test 63 | public void testRepeatedLocalVarsNames2() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 64 | { 65 | final Task res = done().thenCompose(o -> { 66 | { 67 | String a = "a1"; 68 | String b = "b1"; 69 | int c = 1; 70 | } 71 | await(getBlockedTask()); 72 | { 73 | String a = "a2"; 74 | String b = "b2"; 75 | int c = 10; 76 | return fromValue((Integer)c); 77 | } 78 | }); 79 | completeFutures(); 80 | assertEquals((Integer) 10, res.join()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/LoopTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import java.util.List; 36 | import java.util.concurrent.CompletableFuture; 37 | import java.util.stream.Collectors; 38 | import java.util.stream.IntStream; 39 | 40 | import static com.ea.async.Async.await; 41 | import static junit.framework.Assert.assertTrue; 42 | import static org.junit.Assert.assertEquals; 43 | import static org.junit.Assert.assertFalse; 44 | 45 | public class LoopTest extends BaseTest 46 | { 47 | 48 | 49 | @Test 50 | public void testForLoop() 51 | { 52 | int count = 5; 53 | final Task task = futureFrom(() -> { 54 | String str = ""; 55 | for (int i = 0; i < count; i++) 56 | { 57 | str += ":" + await(getBlockedFuture(i)); 58 | } 59 | return Task.fromValue(str); 60 | }); 61 | assertFalse(task.isDone()); 62 | completeFutures(); 63 | assertTrue(task.isDone()); 64 | assertEquals(":0:1:2:3:4", task.join()); 65 | } 66 | 67 | @Test 68 | public void testWhileLoop() 69 | { 70 | int count = 5; 71 | final Task task = futureFrom(() -> { 72 | String str = ""; 73 | int i = 0; 74 | while (i < count) 75 | { 76 | str += ":" + await(getBlockedFuture(i)); 77 | i++; 78 | } 79 | return Task.fromValue(str); 80 | }); 81 | assertFalse(task.isDone()); 82 | completeFutures(); 83 | assertTrue(task.isDone()); 84 | assertEquals(":0:1:2:3:4", task.join()); 85 | } 86 | 87 | 88 | @Test 89 | public void testDoLoop() 90 | { 91 | int count = 5; 92 | final Task task = futureFrom(() -> { 93 | String str = ""; 94 | int i = 0; 95 | do 96 | { 97 | str += ":" + await(getBlockedFuture(i)); 98 | i++; 99 | } while (i < count); 100 | return Task.fromValue(str); 101 | }); 102 | assertFalse(task.isDone()); 103 | completeFutures(); 104 | assertTrue(task.isDone()); 105 | assertEquals(":0:1:2:3:4", task.join()); 106 | } 107 | 108 | 109 | @Test 110 | public void testForEach() 111 | { 112 | final List> blockedFuts = IntStream.range(0, 5) 113 | .mapToObj(i -> getBlockedFuture((Integer) i)) 114 | .collect(Collectors.toList()); 115 | final Task task = futureFrom(() -> { 116 | String str = ""; 117 | for (CompletableFuture f : blockedFuts) 118 | { 119 | str += ":" + await(f); 120 | } 121 | return Task.fromValue(str); 122 | }); 123 | assertFalse(task.isDone()); 124 | completeFutures(); 125 | assertTrue(task.isDone()); 126 | assertEquals(":0:1:2:3:4", task.join()); 127 | } 128 | 129 | 130 | } 131 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/MultipleAwaitTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import java.util.ArrayList; 36 | import java.util.List; 37 | import java.util.concurrent.CompletableFuture; 38 | 39 | import static com.ea.async.Async.await; 40 | import static org.junit.Assert.assertEquals; 41 | 42 | public class MultipleAwaitTest extends BaseTest 43 | { 44 | public static class TaskSomethingAsync 45 | { 46 | private List blockers = new ArrayList<>(); 47 | 48 | public Task doSomething() 49 | { 50 | String res1 = await(blocker()); 51 | String res2 = await(blocker()); 52 | return Task.fromValue(res1 + ":" + res2); 53 | } 54 | 55 | public Task doSomething(Task blocker1, Task blocker2) 56 | { 57 | String res1 = await(blocker1); 58 | String res2 = await(blocker2); 59 | return Task.fromValue(res1 + ":" + res2); 60 | //return Task.fromValue(res1 + ":" + res2); 61 | } 62 | 63 | private CompletableFuture blocker() 64 | { 65 | final CompletableFuture blocker = new CompletableFuture<>(); 66 | blockers.add(blocker); 67 | return blocker; 68 | } 69 | 70 | public void completeBlockers() 71 | { 72 | for (int i = 0; i < blockers.size(); i++) 73 | { 74 | final CompletableFuture fut = blockers.get(i); 75 | fut.complete("str " + i); 76 | } 77 | } 78 | } 79 | 80 | @Test 81 | public void testMultipleAwaitsAndMethods() throws IllegalAccessException, InstantiationException 82 | { 83 | final TaskSomethingAsync a = new TaskSomethingAsync(); 84 | 85 | Task res = a.doSomething(); 86 | a.completeBlockers(); 87 | assertEquals("str 0:str 1", res.join()); 88 | } 89 | 90 | 91 | @Test 92 | public void testMultipleAwaitsFromParams() throws IllegalAccessException, InstantiationException 93 | { 94 | final TaskSomethingAsync a = new TaskSomethingAsync(); 95 | Task blocker1 = new Task<>(); 96 | Task blocker2 = new Task<>(); 97 | Task res = a.doSomething(blocker1, blocker2); 98 | blocker1.complete("a"); 99 | blocker2.complete("b"); 100 | assertEquals("a:b", res.join()); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/NoPackageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import org.junit.Test; 32 | 33 | import java.lang.reflect.InvocationTargetException; 34 | import java.lang.reflect.Method; 35 | import java.util.concurrent.CompletableFuture; 36 | 37 | import static org.junit.Assert.assertEquals; 38 | 39 | public class NoPackageTest extends BaseTest 40 | { 41 | @Test 42 | public void testPackageLessClass() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException 43 | { 44 | 45 | Class newClass = Class.forName("NoPackageAsync"); 46 | final Method method = newClass.getMethod("noPackageMethod", CompletableFuture.class, int.class); 47 | 48 | CompletableFuture blocker = new CompletableFuture<>(); 49 | final CompletableFuture res = (CompletableFuture) method.invoke(newClass.newInstance(), blocker, 5); 50 | blocker.complete("zzz"); 51 | assertEquals("5:10000000000:1.5:3.5:zzz:true", res.join()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/NullThenBasicValueTest.java: -------------------------------------------------------------------------------- 1 | package com.ea.async.test; 2 | 3 | import com.ea.async.Task; 4 | 5 | import org.junit.Test; 6 | 7 | import static com.ea.async.Async.await; 8 | import static org.junit.Assert.assertNull; 9 | 10 | public class NullThenBasicValueTest extends BaseTest 11 | { 12 | @Test 13 | public void nullThenBasicValueTest() throws Exception 14 | { 15 | debugTransform(NullThenBasicValueTest.class.getName() + "$NullThenBasicVal"); 16 | final Task res = NullThenBasicVal.doIt(getBlockedTask()); 17 | completeFutures(); 18 | assertNull(res.join()); 19 | } 20 | 21 | public static class NullThenBasicVal 22 | { 23 | public static Task doIt(Task task) 24 | { 25 | String nullString = null; //this variable must be a string and initialized to null 26 | int basicInt = 0; //this variable must be numeric and initialized to anything 27 | 28 | await(task); 29 | return Task.done(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/RuntimeInstrTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import org.junit.Test; 32 | 33 | import java.lang.reflect.InvocationTargetException; 34 | import java.util.concurrent.CompletableFuture; 35 | 36 | import static com.ea.async.Async.await; 37 | import static org.junit.Assert.assertEquals; 38 | 39 | public class RuntimeInstrTest extends BaseTest 40 | { 41 | 42 | private static class Basic 43 | { 44 | static String concat(int i, long j, float f, double d, Object obj, boolean b) 45 | { 46 | return i + ":" + j + ":" + f + ":" + d + ":" + obj + ":" + b; 47 | } 48 | 49 | public CompletableFuture doSomething(CompletableFuture blocker, int var) 50 | { 51 | return CompletableFuture.completedFuture(concat(var, 10_000_000_000L, 1.5f, 3.5d, await(blocker), true)); 52 | } 53 | } 54 | 55 | @Test 56 | public void testInstrumentation() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 57 | { 58 | CompletableFuture blocker = new CompletableFuture<>(); 59 | Basic basic = new Basic(); 60 | final CompletableFuture res = basic.doSomething(blocker, 5); 61 | 62 | blocker.complete("zzz"); 63 | assertEquals("5:10000000000:1.5:3.5:zzz:true", res.join()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/SmallestExceptionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import java.lang.reflect.InvocationTargetException; 36 | 37 | import static com.ea.async.Async.await; 38 | import static org.junit.Assert.assertNull; 39 | 40 | public class SmallestExceptionTest extends BaseTest 41 | { 42 | 43 | @Test 44 | public void testRepeatedLocalVarsNames() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 45 | { 46 | final Task res = doIt(); 47 | completeFutures(); 48 | assertNull(res.join()); 49 | } 50 | 51 | 52 | private Task doIt() 53 | { 54 | try 55 | { 56 | await(getBlockedTask()); 57 | return Task.done(); 58 | } 59 | catch (Exception ex) 60 | { 61 | return Task.done(); 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/SmallestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import java.lang.reflect.InvocationTargetException; 36 | 37 | import static com.ea.async.Async.await; 38 | import static junit.framework.TestCase.assertNull; 39 | 40 | public class SmallestTest extends BaseTest 41 | { 42 | 43 | @Test 44 | public void smallTest() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 45 | { 46 | final Task res = doIt(); 47 | completeFutures(); 48 | assertNull(res.join()); 49 | } 50 | 51 | 52 | private Task doIt() 53 | { 54 | return Task.fromValue(await(getBlockedTask())); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/StaticTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Async; 32 | 33 | import org.junit.Test; 34 | 35 | import java.lang.reflect.InvocationTargetException; 36 | import java.util.concurrent.CompletableFuture; 37 | 38 | import static com.ea.async.Async.await; 39 | import static org.junit.Assert.assertEquals; 40 | 41 | public class StaticTest extends BaseTest 42 | { 43 | public static class StaticUse 44 | { 45 | static String concat(int i, long j, float f, double d, Object obj, boolean b) 46 | { 47 | return i + ":" + j + ":" + f + ":" + d + ":" + obj + ":" + b; 48 | } 49 | 50 | public static CompletableFuture staticMethod(CompletableFuture blocker, int var) 51 | { 52 | return CompletableFuture.completedFuture(concat(var, 10_000_000_000L, 1.5f, 3.5d, await(blocker), true)); 53 | } 54 | } 55 | 56 | @Test 57 | public void testStaticMethodWithPrimitives() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException 58 | { 59 | CompletableFuture blocker = new CompletableFuture<>(); 60 | CompletableFuture res = StaticUse.staticMethod(blocker, 5); 61 | blocker.complete("zzz"); 62 | assertEquals("5:10000000000:1.5:3.5:zzz:true", res.join()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/TaskTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import static com.ea.async.Async.await; 36 | import static org.junit.Assert.assertEquals; 37 | 38 | public class TaskTest extends BaseTest 39 | { 40 | public static class TaskSomethingAsync 41 | { 42 | public Task doSomething(Task blocker) 43 | { 44 | String res = await(blocker); 45 | return Task.fromValue(":" + res); 46 | } 47 | } 48 | 49 | public static class TaskSomethingWithLocalsAndStack 50 | { 51 | public Task doSomething(Task blocker) 52 | { 53 | int local = 7; 54 | String res = ":" + Math.max(local, await(blocker).length()); 55 | return Task.fromValue(res); 56 | } 57 | } 58 | 59 | public static class TaskSomethingAsyncWithException 60 | { 61 | public Task doSomething(Task blocker) 62 | { 63 | try 64 | { 65 | String res = await(blocker); 66 | return Task.fromValue(":" + res); 67 | } 68 | catch (RuntimeException ex) 69 | { 70 | return Task.fromValue(":" + ex.getCause().getMessage()); 71 | } 72 | } 73 | } 74 | 75 | @Test 76 | public void testDirectPathNonBlocking() throws IllegalAccessException, InstantiationException 77 | { 78 | // test an example where the async function blocks (returns incomplete future) 79 | // this would not work without instrumentation 80 | final TaskSomethingAsync a = new TaskSomethingAsync(); 81 | 82 | Task blocker = Task.fromValue("x"); 83 | final Task res = a.doSomething(blocker); 84 | assertEquals(":x", res.join()); 85 | } 86 | 87 | @Test 88 | public void testBlocking() throws IllegalAccessException, InstantiationException 89 | { 90 | final TaskSomethingAsync a = new TaskSomethingAsync(); 91 | 92 | Task blocker = new Task<>(); 93 | final Task res = a.doSomething(blocker); 94 | blocker.complete("x"); 95 | assertEquals(":x", res.join()); 96 | } 97 | 98 | @Test 99 | public void testBlockingWithStackAndLocal() throws IllegalAccessException, InstantiationException 100 | { 101 | final TaskSomethingWithLocalsAndStack a = new TaskSomethingWithLocalsAndStack(); 102 | 103 | Task blocker = new Task<>(); 104 | final Task res = a.doSomething(blocker); 105 | blocker.complete("0123456789"); 106 | assertEquals(":10", res.join()); 107 | } 108 | 109 | @Test 110 | public void testBlockingAndException() throws IllegalAccessException, InstantiationException 111 | { 112 | final TaskSomethingAsyncWithException a = new TaskSomethingAsyncWithException(); 113 | Task blocker = new Task<>(); 114 | final Task res = a.doSomething(blocker); 115 | blocker.completeExceptionally(new RuntimeException("Exception")); 116 | assertEquals(":Exception", res.join()); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /async/src/test/java/com/ea/async/test/TryWithResourcesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.test; 30 | 31 | import com.ea.async.Task; 32 | 33 | import org.junit.Test; 34 | 35 | import java.lang.reflect.InvocationTargetException; 36 | 37 | import static com.ea.async.Async.await; 38 | import static org.junit.Assert.assertEquals; 39 | 40 | /** 41 | * Created by joeh on 2017-04-06. 42 | */ 43 | public class TryWithResourcesTest extends BaseTest 44 | { 45 | private class CloseableResource implements AutoCloseable { 46 | private boolean closed = false; 47 | 48 | @Override 49 | public void close() 50 | { 51 | closed = true; 52 | } 53 | 54 | public boolean isClosed() 55 | { 56 | return closed; 57 | } 58 | } 59 | 60 | @Test 61 | public void testTryWithResources() 62 | { 63 | final Task res = doTestTryWithResources(); 64 | completeFutures(); 65 | assertEquals((Integer) 3456, res.join()); 66 | } 67 | 68 | private Task doTestTryWithResources() 69 | { 70 | try(CloseableResource cr = new CloseableResource()) 71 | { 72 | await(getBlockedFuture()); 73 | if(cr.isClosed()) { 74 | throw new RuntimeException("Closed early"); 75 | } 76 | } 77 | 78 | return Task.fromValue(3456); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /gradle-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 4.0.0 31 | 32 | com.ea.async 33 | ea-async-parent 34 | 1.2.4-SNAPSHOT 35 | .. 36 | 37 | ea-async-gradle-plugin 38 | jar 39 | EA Async-Await Gradle Plugin 40 | Pre-instruments class files to work with the async-await paradigm 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-compiler-plugin 47 | 48 | 49 | maven-clean-plugin 50 | 3.0.0 51 | 52 | false 53 | 54 | 55 | 56 | maven-assembly-plugin 57 | 58 | 59 | jar-with-dependencies 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | gradle 68 | Gradle Releases Repository 69 | https://repo.gradle.org/gradle/libs-releases-local/ 70 | 71 | 72 | 73 | 74 | com.ea.async 75 | ea-async 76 | ${project.version} 77 | 78 | 79 | 80 | org.apache.maven 81 | maven-artifact 82 | 3.5.3 83 | 84 | 85 | 86 | org.apache.maven 87 | maven-core 88 | 3.5.3 89 | 90 | 91 | 92 | 93 | 94 | org.codehaus.groovy 95 | groovy 96 | 2.5.8 97 | provided 98 | 99 | 100 | 101 | org.gradle 102 | gradle-core 103 | 5.6.4 104 | provided 105 | 106 | 107 | 108 | org.gradle 109 | gradle-core-api 110 | 5.6.4 111 | provided 112 | 113 | 114 | 115 | org.gradle 116 | gradle-base-services 117 | 5.6.4 118 | provided 119 | 120 | 121 | 122 | org.gradle 123 | gradle-model-core 124 | 5.6.4 125 | provided 126 | 127 | 128 | 129 | org.gradle 130 | gradle-language-jvm 131 | 5.6.4 132 | provided 133 | 134 | 135 | 136 | org.gradle 137 | gradle-language-java 138 | 5.6.4 139 | provided 140 | 141 | 142 | 143 | org.gradle 144 | gradle-platform-jvm 145 | 5.6.4 146 | provided 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/java/com/ea/async/gradle/plugin/AsyncPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2020 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.gradle.plugin; 30 | 31 | import com.ea.async.instrumentation.Transformer; 32 | 33 | import org.gradle.api.Plugin; 34 | import org.gradle.api.Project; 35 | import org.gradle.api.tasks.compile.JavaCompile; 36 | 37 | import java.io.File; 38 | import java.io.FileInputStream; 39 | import java.io.IOException; 40 | import java.net.MalformedURLException; 41 | import java.net.URL; 42 | import java.net.URLClassLoader; 43 | import java.nio.file.Files; 44 | import java.nio.file.Paths; 45 | import java.util.ArrayList; 46 | import java.util.List; 47 | import java.util.Objects; 48 | 49 | /** 50 | * A plugin that allows easily integrating EA Async instrumentation into the Gradle build process. 51 | */ 52 | public class AsyncPlugin implements Plugin 53 | { 54 | 55 | /** 56 | * Applies the plugin to the project. Prepares Java compilation tasks to be followed up on by instrumentation. 57 | * @param project the Gradle project to which the plugin was applied 58 | */ 59 | @Override 60 | public void apply(final Project project) 61 | { 62 | project.getTasks().withType(JavaCompile.class, task -> 63 | { 64 | // This will be called for every JavaCompile task, whether already existing or added dynamically later 65 | task.doLast("EA Async instrumentation", t -> instrumentCompileResults(task)); 66 | }); 67 | } 68 | 69 | /** 70 | * Rewrites compiled classes output by a Java compilation task. 71 | * Called for each compilation task after it finishes. 72 | * @param task the Java compilation task whose output to instrument 73 | */ 74 | private void instrumentCompileResults(final JavaCompile task) 75 | { 76 | // Set up the Transformer to explode on failure 77 | final Transformer asyncTransformer = new Transformer(); 78 | asyncTransformer.setErrorListener(err -> 79 | { 80 | throw new RuntimeException("Failed to instrument the output of " + task.toString() + ": " + err); 81 | }); 82 | // Create a classloader that can see the same CompletionStage subclasses as the compiler 83 | final List classpathUrls = new ArrayList<>(); 84 | try 85 | { 86 | for (File f : task.getClasspath().plus(task.getOutputs().getFiles()).getFiles()) 87 | { 88 | classpathUrls.add(f.toURI().toURL()); 89 | } 90 | } 91 | catch (MalformedURLException e) 92 | { 93 | throw new RuntimeException("Bad URL when preparing instrumentation of " + task.toString(), e); 94 | } 95 | final ClassLoader classLoader = new URLClassLoader(classpathUrls.toArray(new URL[0])); 96 | // Rewrite the class files in the output directory 97 | instrumentFile(task.getDestinationDir(), task, asyncTransformer, classLoader); 98 | } 99 | 100 | /** 101 | * Recursively instruments the specified file system entry and its descendants. 102 | * @param fsEntry a File in the output directory of a task 103 | * @param task the JavaCompile task whose output is being instrumented 104 | * @param asyncTransformer the transformer used to instrument the classes 105 | * @param classLoader the classloader to supply to the transformer 106 | */ 107 | private void instrumentFile(final File fsEntry, final JavaCompile task, 108 | final Transformer asyncTransformer, final ClassLoader classLoader) 109 | { 110 | if (fsEntry.isDirectory()) 111 | { 112 | // Recurse into subdirectories and files 113 | for (File subentry : Objects.requireNonNull(fsEntry.listFiles())) { 114 | instrumentFile(subentry, task, asyncTransformer, classLoader); 115 | } 116 | } 117 | else if (fsEntry.isFile() && fsEntry.getName().endsWith(".class")) 118 | { 119 | // Instrument a class 120 | byte[] instrumentedClass; 121 | try (FileInputStream fis = new FileInputStream(fsEntry)) 122 | { 123 | instrumentedClass = asyncTransformer.instrument(classLoader, fis); 124 | } 125 | catch (IOException e) 126 | { 127 | throw new RuntimeException("Failed to instrument '" + fsEntry.getPath() + "' from " + task.toString(), e); 128 | } 129 | if (instrumentedClass != null) 130 | { 131 | // Transformer#instrument returns null if no changes were needed 132 | try 133 | { 134 | Files.write(Paths.get(fsEntry.getAbsolutePath()), instrumentedClass); 135 | } 136 | catch (IOException e) 137 | { 138 | throw new RuntimeException("Failed to write '" + fsEntry.getPath() + "'", e); 139 | } 140 | } 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/resources/META-INF/gradle-plugins/com.ea.async.gradle.plugin.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2020 Electronic Arts Inc. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions 6 | # are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | # its contributors may be used to endorse or promote products derived 15 | # from this software without specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | # DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | 29 | implementation-class=com.ea.async.gradle.plugin.AsyncPlugin 30 | -------------------------------------------------------------------------------- /maven-plugin/README.md: -------------------------------------------------------------------------------- 1 | EA Async Maven Plugin 2 | ============ 3 | 4 | EA Async implements async-await methods in the JVM. It allows programmers to write asynchronous code in a sequential fashion. It was developed by [BioWare](http://www.bioware.com), a division of [Electronic Arts](http://www.ea.com). 5 | 6 | The EA Async Maven Plugin executes compile time instrumentation of classes that use EA Async. 7 | 8 | A sample project can be found [here](src/test/project-to-test/pom.xml). 9 | 10 | Documentation 11 | ======= 12 | Documentation is located [here](http://orbit.bioware.com/). 13 | 14 | License 15 | ======= 16 | EA Async is licensed under the [BSD 3-Clause License](../LICENSE). 17 | 18 | Usage 19 | ======= 20 | 21 | Add the EA Async dependency: 22 | 23 | ```xml 24 | 25 | com.ea.async 26 | ea-async 27 | 1.2.3 28 | 29 | ``` 30 | 31 | Add the build plugin that will instrument the uses of `await` 32 | 33 | ```xml 34 | 35 | 36 | 37 | com.ea.async 38 | ea-async-maven-plugin 39 | 1.2.3 40 | 41 | 42 | 43 | instrument 44 | instrument-test 45 | 46 | 47 | 48 | 49 | 50 | 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /maven-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 4.0.0 31 | 32 | com.ea.async 33 | ea-async-parent 34 | 1.2.4-SNAPSHOT 35 | .. 36 | 37 | com.ea.async 38 | ea-async-maven-plugin 39 | maven-plugin 40 | EA Async-Await Maven Plugin 41 | Pre instruments class files to work with the async-await paradigm 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-plugin-plugin 48 | 3.5.1 49 | 50 | 51 | default-descriptor 52 | 53 | descriptor 54 | 55 | process-classes 56 | 57 | 58 | help-descriptor 59 | 60 | helpmojo 61 | 62 | process-classes 63 | 64 | 65 | 66 | 67 | maven-clean-plugin 68 | 3.0.0 69 | 70 | false 71 | 72 | 73 | 74 | 75 | 76 | 77 | com.ea.async 78 | ea-async 79 | ${project.version} 80 | 81 | 82 | 83 | org.apache.maven 84 | maven-artifact 85 | 3.5.3 86 | 87 | 88 | 89 | org.apache.maven 90 | maven-plugin-api 91 | 3.5.3 92 | 93 | 94 | 95 | org.apache.maven 96 | maven-core 97 | 3.5.3 98 | 99 | 100 | 101 | org.codehaus.plexus 102 | plexus-archiver 103 | 3.7.0 104 | 105 | 106 | 107 | org.apache.maven 108 | maven-compat 109 | 3.5.3 110 | test 111 | 112 | 113 | 114 | 115 | org.apache.maven.plugin-tools 116 | maven-plugin-annotations 117 | 3.5.1 118 | provided 119 | 120 | 121 | 122 | org.apache.maven.plugin-testing 123 | maven-plugin-testing-harness 124 | 3.3.0 125 | test 126 | 127 | 128 | 129 | junit 130 | junit 131 | test 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/com/ea/async/maven/plugin/AbstractAsyncMojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.maven.plugin; 30 | 31 | import com.ea.async.instrumentation.Transformer; 32 | 33 | import org.apache.maven.plugin.AbstractMojo; 34 | import org.apache.maven.plugin.MojoExecutionException; 35 | import org.apache.maven.plugins.annotations.Component; 36 | import org.apache.maven.plugins.annotations.Parameter; 37 | import org.apache.maven.project.MavenProject; 38 | import org.codehaus.plexus.archiver.ArchiverException; 39 | import org.codehaus.plexus.components.io.resources.PlexusIoFileResourceCollection; 40 | import org.codehaus.plexus.components.io.resources.PlexusIoResource; 41 | import org.codehaus.plexus.util.IOUtil; 42 | 43 | import java.io.File; 44 | import java.io.FileOutputStream; 45 | import java.io.IOException; 46 | import java.io.InputStream; 47 | import java.net.URLClassLoader; 48 | import java.util.Iterator; 49 | 50 | 51 | public abstract class AbstractAsyncMojo extends AbstractMojo 52 | { 53 | 54 | private static final String[] DEFAULT_EXCLUDES = new String[]{ "**/package.html" }; 55 | 56 | private static final String[] DEFAULT_INCLUDES = new String[]{ "**/**" }; 57 | 58 | /** 59 | * List of files to include. 60 | * Fileset patterns relative to the input directory whose contents 61 | * is being instrumented. 62 | */ 63 | @Parameter 64 | private String[] includes; 65 | 66 | /** 67 | * List of files to include. 68 | * Fileset patterns relative to the input directory whose contents 69 | * is being instrumented. 70 | */ 71 | @Parameter 72 | private String[] excludes; 73 | 74 | /** 75 | * Directory where the instrumented files will be written. 76 | * If not set the files will be overwritten with the new data. 77 | */ 78 | @Parameter(required = false) 79 | private File outputDirectory; 80 | 81 | @Parameter(defaultValue = "${project.build.outputDirectory}", required = true) 82 | protected File classesDirectory; 83 | 84 | /** 85 | * Prints each file being instrumented 86 | */ 87 | @Parameter 88 | protected boolean verbose = false; 89 | 90 | @Component 91 | protected MavenProject project; 92 | 93 | 94 | /** 95 | * Return the specific output directory to instrument. 96 | */ 97 | protected abstract File getClassesDirectory(); 98 | 99 | protected abstract String getType(); 100 | 101 | /** 102 | * Instruments the files. 103 | */ 104 | public void execute() throws MojoExecutionException 105 | { 106 | if (getClassesDirectory() == null || (!getClassesDirectory().exists() || getClassesDirectory().list().length < 1)) 107 | { 108 | getLog().info("Skipping instrumentation of the " + getType()); 109 | } 110 | else 111 | { 112 | instrumentFiles(); 113 | } 114 | } 115 | 116 | private String[] getIncludes() 117 | { 118 | if (includes != null && includes.length > 0) 119 | { 120 | return includes; 121 | } 122 | return DEFAULT_INCLUDES; 123 | } 124 | 125 | private String[] getExcludes() 126 | { 127 | if (excludes != null && excludes.length > 0) 128 | { 129 | return excludes; 130 | } 131 | return DEFAULT_EXCLUDES; 132 | } 133 | 134 | private File getOutputDirectory() 135 | { 136 | if (outputDirectory == null) 137 | { 138 | return getClassesDirectory(); 139 | } 140 | return outputDirectory; 141 | } 142 | 143 | public boolean isVerbose() 144 | { 145 | return verbose; 146 | } 147 | 148 | /** 149 | * Instrument the files that require instrumentation. 150 | */ 151 | public void instrumentFiles() throws MojoExecutionException 152 | { 153 | try 154 | { 155 | File contentDirectory = getClassesDirectory(); 156 | if (!contentDirectory.exists()) 157 | { 158 | getLog().warn(getType() + " directory is empty! " + contentDirectory); 159 | return; 160 | } 161 | final Iterator it = getFiles(contentDirectory); 162 | final Transformer transformer = new Transformer(); 163 | transformer.setErrorListener(error -> getLog().error(error)); 164 | int instrumentedCount = 0; 165 | ClassLoader classLoader = createClassLoader(); 166 | while (it.hasNext()) 167 | { 168 | final PlexusIoResource resource = it.next(); 169 | if (resource.isFile() && resource.getName().endsWith(".class")) 170 | { 171 | byte[] bytes = null; 172 | try (InputStream in = resource.getContents()) 173 | { 174 | bytes = transformer.instrument(classLoader, in); 175 | } 176 | catch (Exception e) 177 | { 178 | getLog().error("Error instrumenting " + resource.getName(), e); 179 | } 180 | if (bytes != null) 181 | { 182 | if (isVerbose()) 183 | { 184 | getLog().info("instrumented: " + resource.getName()); 185 | } 186 | else if (getLog().isDebugEnabled()) 187 | { 188 | getLog().debug("instrumented: " + resource.getName()); 189 | } 190 | IOUtil.copy(bytes, new FileOutputStream(new File(getOutputDirectory(), resource.getName()))); 191 | instrumentedCount++; 192 | } 193 | } 194 | } 195 | getLog().info("Orbit Async " + getType() + " instrumented: " + instrumentedCount); 196 | } 197 | catch (Exception e) 198 | { 199 | throw new MojoExecutionException("Error assembling instrumenting", e); 200 | } 201 | } 202 | 203 | 204 | private Iterator getFiles(final File contentDirectory) throws IOException 205 | { 206 | if (!contentDirectory.isDirectory()) 207 | { 208 | throw new ArchiverException(contentDirectory.getAbsolutePath() + " is not a directory."); 209 | } 210 | 211 | final PlexusIoFileResourceCollection collection = new PlexusIoFileResourceCollection(); 212 | 213 | collection.setIncludes(getIncludes()); 214 | collection.setExcludes(getExcludes()); 215 | collection.setBaseDir(contentDirectory); 216 | collection.setIncludingEmptyDirectories(false); 217 | collection.setPrefix(""); 218 | collection.setUsingDefaultExcludes(true); 219 | 220 | return collection.getResources(); 221 | } 222 | 223 | abstract ClassLoader createClassLoader(); 224 | } 225 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/com/ea/async/maven/plugin/MainMojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.maven.plugin; 30 | 31 | import org.apache.maven.artifact.Artifact; 32 | import org.apache.maven.plugin.MojoExecutionException; 33 | import org.apache.maven.plugins.annotations.Execute; 34 | import org.apache.maven.plugins.annotations.LifecyclePhase; 35 | import org.apache.maven.plugins.annotations.Mojo; 36 | import org.apache.maven.plugins.annotations.ResolutionScope; 37 | 38 | import java.io.File; 39 | import java.net.MalformedURLException; 40 | import java.net.URL; 41 | import java.net.URLClassLoader; 42 | import java.util.ArrayList; 43 | import java.util.List; 44 | import java.util.Set; 45 | 46 | @Mojo(name = "instrument", 47 | defaultPhase = LifecyclePhase.PROCESS_CLASSES, 48 | requiresProject = false, 49 | threadSafe = true, 50 | requiresDependencyResolution = ResolutionScope.RUNTIME) 51 | @Execute(goal = "instrument", phase = LifecyclePhase.PROCESS_CLASSES) 52 | public class MainMojo extends AbstractAsyncMojo 53 | { 54 | 55 | 56 | protected String getType() 57 | { 58 | return "main-classes"; 59 | } 60 | 61 | /** 62 | * Return the main classes directory 63 | */ 64 | protected File getClassesDirectory() 65 | { 66 | return classesDirectory; 67 | } 68 | 69 | @Override 70 | public void execute() throws MojoExecutionException 71 | { 72 | super.execute(); 73 | } 74 | 75 | private List generateClassPath() 76 | { 77 | List classpath = new ArrayList<>(2 + project.getArtifacts().size()); 78 | 79 | classpath.add(classesDirectory.getAbsolutePath()); 80 | 81 | Set classpathArtifacts = project.getArtifacts(); 82 | 83 | for (Artifact artifact : classpathArtifacts) 84 | { 85 | if (artifact.getArtifactHandler().isAddedToClasspath() 86 | && !"test".equalsIgnoreCase(artifact.getScope())) 87 | { 88 | File file = artifact.getFile(); 89 | if (file != null) 90 | { 91 | classpath.add(file.getPath()); 92 | } 93 | } 94 | } 95 | return classpath; 96 | } 97 | 98 | @Override 99 | protected ClassLoader createClassLoader() 100 | { 101 | final URL[] urls = generateClassPath().stream().map(f -> { 102 | try 103 | { 104 | return new File(f).toURI().toURL(); 105 | } 106 | catch (MalformedURLException e) 107 | { 108 | throw new RuntimeException(e); 109 | } 110 | }).toArray(s -> new URL[s]); 111 | return new URLClassLoader(urls); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/com/ea/async/maven/plugin/TestMojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.async.maven.plugin; 30 | 31 | import org.apache.maven.artifact.Artifact; 32 | import org.apache.maven.plugin.MojoExecutionException; 33 | import org.apache.maven.plugins.annotations.Execute; 34 | import org.apache.maven.plugins.annotations.LifecyclePhase; 35 | import org.apache.maven.plugins.annotations.Mojo; 36 | import org.apache.maven.plugins.annotations.Parameter; 37 | import org.apache.maven.plugins.annotations.ResolutionScope; 38 | 39 | import java.io.File; 40 | import java.net.MalformedURLException; 41 | import java.net.URL; 42 | import java.net.URLClassLoader; 43 | import java.util.ArrayList; 44 | import java.util.List; 45 | import java.util.Set; 46 | 47 | @Mojo(name = "instrument-test", 48 | defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES, 49 | requiresProject = false, 50 | threadSafe = true, 51 | executionStrategy = "always", 52 | requiresDirectInvocation = false, 53 | requiresDependencyResolution = ResolutionScope.TEST) 54 | @Execute(goal = "instrument-test", phase = LifecyclePhase.PROCESS_TEST_CLASSES) 55 | public class TestMojo extends AbstractAsyncMojo 56 | { 57 | /** 58 | * If set to true it will bypass instrumenting the unit tests entirely. 59 | */ 60 | @Parameter(property = "maven.test.skip") 61 | private boolean skip; 62 | 63 | /** 64 | * Directory containing the test classes files that should be instrumented 65 | */ 66 | @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true) 67 | private File testClassesDirectory; 68 | 69 | protected String getType() 70 | { 71 | return "test-classes"; 72 | } 73 | 74 | /** 75 | * Return the test-classes directory. 76 | */ 77 | protected File getClassesDirectory() 78 | { 79 | return testClassesDirectory; 80 | } 81 | 82 | public void execute() throws MojoExecutionException 83 | { 84 | if (skip) 85 | { 86 | getLog().info("Skipping the instrumentation of the test classes"); 87 | } 88 | else 89 | { 90 | super.execute(); 91 | } 92 | } 93 | 94 | protected List generateTestClasspath() 95 | { 96 | List classpath = new ArrayList<>(2 + project.getArtifacts().size()); 97 | 98 | classpath.add(testClassesDirectory.getAbsolutePath()); 99 | 100 | classpath.add(classesDirectory.getAbsolutePath()); 101 | 102 | Set classpathArtifacts = project.getArtifacts(); 103 | 104 | for (Artifact artifact : classpathArtifacts) 105 | { 106 | if (artifact.getArtifactHandler().isAddedToClasspath()) 107 | { 108 | File file = artifact.getFile(); 109 | if (file != null) 110 | { 111 | classpath.add(file.getPath()); 112 | } 113 | } 114 | } 115 | return classpath; 116 | } 117 | 118 | @Override 119 | protected ClassLoader createClassLoader() 120 | { 121 | final URL[] urls = generateTestClasspath().stream().map(f -> { 122 | try 123 | { 124 | return new File(f).toURI().toURL(); 125 | } 126 | catch (MalformedURLException e) 127 | { 128 | throw new RuntimeException(e); 129 | } 130 | }).toArray(s -> new URL[s]); 131 | return new URLClassLoader(urls); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /maven-plugin/src/test/java/MojoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | import com.ea.async.maven.plugin.MainMojo; 30 | 31 | import org.apache.maven.plugin.testing.MojoRule; 32 | import org.junit.Ignore; 33 | import org.junit.Rule; 34 | import org.junit.Test; 35 | 36 | import java.io.File; 37 | 38 | import static org.junit.Assert.assertNotNull; 39 | 40 | public class MojoTest 41 | { 42 | @Rule 43 | public MojoRule rule = new MojoRule() 44 | { 45 | @Override 46 | protected void before() throws Throwable 47 | { 48 | } 49 | 50 | @Override 51 | protected void after() 52 | { 53 | } 54 | }; 55 | 56 | @Test 57 | @Ignore 58 | public void testSomething() throws Exception 59 | { 60 | System.out.println(new File(".").getAbsoluteFile()); 61 | MainMojo myMojo = (MainMojo) 62 | rule.lookupEmptyMojo("orbit-async", "src/test/project-to-test/pom.xml"); 63 | assertNotNull(myMojo); 64 | myMojo.execute(); 65 | } 66 | 67 | // TODO: add actual instumentation tests. 68 | } 69 | -------------------------------------------------------------------------------- /maven-plugin/src/test/project-to-test/pom.xml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 4.0.0 31 | 32 | com.ea.async 33 | ea-async-parent 34 | 1.2.4-SNAPSHOT 35 | ../../../.. 36 | 37 | com.ea.async.samples 38 | ea-async-maven-plugin-sample 39 | EA Async-Await Samples: Maven Plugin Sample Usage 40 | 41 | 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-compiler-plugin 46 | 47 | ${project.target.jdk} 48 | ${project.source.jdk} 49 | 50 | 51 | 52 | maven-clean-plugin 53 | 3.0.0 54 | 55 | false 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-deploy-plugin 61 | 2.8.2 62 | 63 | true 64 | 65 | 66 | 67 | 68 | com.ea.async 69 | ea-async-maven-plugin 70 | 1.2.4-SNAPSHOT 71 | 72 | 73 | 74 | 75 | instrument 76 | 77 | instrument-test 78 | 79 | 80 | 81 | 82 | true 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | com.ea.async 92 | ea-async 93 | 1.2.4-SNAPSHOT 94 | 95 | 96 | 97 | junit 98 | junit 99 | test 100 | 101 | 102 | -------------------------------------------------------------------------------- /maven-plugin/src/test/project-to-test/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 16 | its contributors may be used to endorse or promote products derived 17 | from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | import com.ea.async.Async; 32 | 33 | import java.util.concurrent.CompletableFuture; 34 | 35 | import static com.ea.async.Async.await; 36 | import static java.util.concurrent.CompletableFuture.completedFuture; 37 | 38 | public class Main 39 | { 40 | static 41 | { 42 | Async.init(); 43 | } 44 | 45 | 46 | public static void main(String args[]) 47 | { 48 | CompletableFuture futureA = new CompletableFuture<>(); 49 | CompletableFuture futureB = new CompletableFuture<>(); 50 | 51 | System.out.println("Here is the async method we are going to call"); 52 | System.out.println(); 53 | System.out.println(" public static CompletableFuture asyncAdd(CompletableFuture a, CompletableFuture b)"); 54 | System.out.println(" {"); 55 | System.out.println(" return completedFuture(await(a) + await(b));"); 56 | System.out.println(" }"); 57 | System.out.println(); 58 | 59 | System.out.println("Calling the instrumented method, without ea async this would block"); 60 | System.out.println(" result = futureA + futureB"); 61 | System.out.println(); 62 | 63 | CompletableFuture result = asyncAdd(futureA, futureB); 64 | 65 | System.out.println("The method returned a future that is not completed: "); 66 | System.out.println(" result.isDone = " + result.isDone()); 67 | System.out.println(); 68 | 69 | 70 | System.out.println("Now we complete the futures that are blocking the async method"); 71 | 72 | futureA.complete(1); 73 | futureB.complete(2); 74 | 75 | System.out.println(" futureA = " + futureA.join()); 76 | System.out.println(" futureB = " + futureB.join()); 77 | System.out.println(); 78 | 79 | System.out.println("Result is complete because we have completed futureA and futureB"); 80 | System.out.println(" result.isDone =" + result.isDone()); 81 | System.out.println(); 82 | 83 | System.out.println("And here is the result"); 84 | 85 | final Integer resultValue = result.join(); 86 | 87 | System.out.println(" result = " + resultValue); 88 | System.out.println(); 89 | } 90 | 91 | public static CompletableFuture asyncAdd(CompletableFuture a, CompletableFuture b) 92 | { 93 | return completedFuture(await(a) + await(b)); 94 | } 95 | } -------------------------------------------------------------------------------- /maven-plugin/src/test/project-to-test/src/test/java/test/AsyncTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package test; 30 | 31 | import com.ea.async.Async; 32 | 33 | import org.junit.Test; 34 | 35 | import java.util.concurrent.CompletableFuture; 36 | 37 | import static com.ea.async.Async.await; 38 | import static java.util.concurrent.CompletableFuture.completedFuture; 39 | import static org.junit.Assert.*; 40 | 41 | public class AsyncTest 42 | { 43 | static 44 | { 45 | Async.init(); 46 | } 47 | 48 | @Test(timeout = 5_000L) 49 | public void testThenCompose() 50 | { 51 | CompletableFuture futureA = new CompletableFuture<>(); 52 | CompletableFuture futureB = new CompletableFuture<>(); 53 | 54 | // calling the instrumented function 55 | // without async this would block 56 | CompletableFuture result = asyncAdd(futureA, futureB); 57 | 58 | // it is not done because futureA and futureB are not completed 59 | assertFalse(result.isDone()); 60 | 61 | futureA.complete(1); 62 | futureB.complete(2); 63 | 64 | // now the result is complete because we have completed futureA and futureB 65 | assertTrue(result.isDone()); 66 | 67 | // and here is the result 68 | assertEquals((Integer) 3, result.join()); 69 | 70 | } 71 | 72 | public CompletableFuture asyncAdd(CompletableFuture a, CompletableFuture b) 73 | { 74 | return completedFuture(await(a) + await(b)); 75 | } 76 | } -------------------------------------------------------------------------------- /updateDocs.groovy: -------------------------------------------------------------------------------- 1 | import java.nio.charset.StandardCharsets 2 | import java.nio.file.Files 3 | import java.nio.file.Paths 4 | 5 | if (args.length != 1) { 6 | System.err.println("Usage: updateDocVersions "); 7 | return; 8 | } 9 | 10 | def version = args[0] 11 | 12 | Files.walk(Paths.get(".")).forEach({ f -> 13 | def modifiedText = null; 14 | def text = null; 15 | if (f.toString().endsWith(".md")) { 16 | // examples inside .md 17 | text = new String(Files.readAllBytes(f), StandardCharsets.UTF_8); 18 | modifiedText = text.replaceAll("[^<]*", (String) ("" + version + "")) 19 | modifiedText = modifiedText.replaceAll("ea-async-[.0-9a-zA-Z_-]+[.]jar", (String) ("ea-async-" + version + ".jar")) 20 | modifiedText = modifiedText.replaceAll("(com[.]ea[.]async[:]ea-async[:])[^']*[']", (String) ("com.ea.async:ea-async:" + version + "'")) 21 | } 22 | if (f.toString().matches(".*project-to-test[/\\\\]pom[.]xml\$")) { 23 | // sample project 24 | text = new String(Files.readAllBytes(f), StandardCharsets.UTF_8); 25 | modifiedText = text.replaceAll("(ea-async(-maven-plugin)?\\s*[^<]*()", 26 | (String) ("\$1>" + version + "\$3")) 27 | } 28 | if (modifiedText != null && !text.equals(modifiedText)) { 29 | println f 30 | Files.write(f, modifiedText.getBytes(StandardCharsets.UTF_8)); 31 | } 32 | }) 33 | 34 | // this script will run during deployment 35 | //mvn versions:set -DnewVersion=newVer 36 | //mvn clean install 37 | //mvn deploy -PstageRelease -DskipTests=true <--- here 38 | //git add . 39 | //git commit -m "Version newVer" 40 | //git tag -a vnewVer -m "Version newVer" 41 | //git push master --tags 42 | //mvn versions:set -DnewVersion=newVer+1-SNAPSHOT 43 | --------------------------------------------------------------------------------