├── .gitignore ├── LICENSE ├── README.md ├── custom-plugin ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── hotswap │ │ └── agent │ │ └── example │ │ ├── RunPlugin.java │ │ ├── plugin │ │ ├── ExamplePlugin.java │ │ ├── ReloadClassCommand.java │ │ └── ReloadClassService.java │ │ └── service │ │ └── HelloWorldService.java │ └── resources │ ├── examplePlugin.resource │ └── hotswap-agent.properties ├── cxf ├── cxf-jaxrs-spring │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── plugin │ │ │ └── cxf │ │ │ └── spring │ │ │ └── jaxrs │ │ │ ├── Service1.java │ │ │ ├── Service2.java │ │ │ └── ServiceEndpoint.java │ │ └── webapp │ │ ├── META-INF │ │ └── context.xml │ │ └── WEB-INF │ │ ├── beans.xml │ │ └── web.xml └── cxf-jaxrs │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── org │ │ └── hotswap │ │ └── agent │ │ └── example │ │ └── cxf │ │ └── jaxrs │ │ ├── AcceptPerson.java │ │ ├── Person.java │ │ ├── Service1.java │ │ ├── Service2.java │ │ ├── ServiceEndpoint.java │ │ └── StatelessBean.java │ └── webapp │ ├── META-INF │ └── context.xml │ └── WEB-INF │ ├── beans.xml │ └── web.xml ├── deltaspike-hibernate-jsf ├── Dockerfile ├── buildAndRunDebug.sh ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── hotswap │ │ └── agent │ │ └── example │ │ └── deltaspike │ │ ├── ContextListener.java │ │ ├── appl │ │ ├── MasterDetailControllerBase.java │ │ └── UserController.java │ │ ├── beans │ │ ├── ApplicationBean.java │ │ ├── GroupedConvBean1.java │ │ ├── GroupedConvBean2.java │ │ ├── GroupedConvBean3.java │ │ ├── HelloProducer1.java │ │ ├── HelloProducer2.java │ │ ├── JsfViewBean.java │ │ ├── ManagedBean.java │ │ ├── MyConversationGroup.java │ │ ├── OmniViewBean.java │ │ ├── SessionBean.java │ │ └── WindowBean.java │ │ ├── em │ │ ├── EntityManagerFactoryProducer.java │ │ └── EntityManagerProducer.java │ │ ├── enums │ │ ├── UserRole.java │ │ └── UserRoleConverter.java │ │ ├── forms │ │ ├── LoginForm.java │ │ └── UserForm.java │ │ ├── jpa │ │ ├── User.java │ │ └── UserRepository.java │ │ └── jsf │ │ ├── AppJsfModuleConfig.java │ │ ├── Messages.java │ │ └── Pages.java │ ├── resources │ ├── META-INF │ │ ├── beans.xml │ │ ├── openwebbeans │ │ │ └── openwebbeans.properties │ │ └── persistence.xml │ ├── hotswap-agent.properties │ └── messages_en.properties │ └── webapp │ ├── META-INF │ ├── MANIFEST.MF │ └── context.xml │ ├── WEB-INF │ ├── beans.xml │ ├── faces-config.xml │ └── web.xml │ ├── appl │ ├── beans.xhtml │ └── users.xhtml │ ├── errorpages │ ├── error.xhtml │ ├── lowPriviliges.xhtml │ ├── notFound.xhtml │ └── viewExpired.xhtml │ ├── include │ ├── header.xhtml │ └── menu.xhtml │ ├── index.xhtml │ └── resources │ └── css │ └── default.css ├── gae ├── .gitignore ├── .idea │ └── codeStyleSettings.xml ├── LICENSE ├── README.md ├── ear │ ├── appengine-maven-plugin.txt │ ├── pom.xml │ └── src │ │ └── main │ │ └── application │ │ └── META-INF │ │ ├── appengine-application.xml │ │ └── application.xml ├── gae-backend │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── developers │ │ │ ├── BackendServlet.java │ │ │ ├── BackendServletModule.java │ │ │ └── BackendStartupListener.java │ │ └── webapp │ │ ├── WEB-INF │ │ ├── appengine-web.xml │ │ ├── logging.properties │ │ └── web.xml │ │ ├── api │ │ └── 5xx │ │ │ └── index.jsp │ │ └── index.html ├── gae-default │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── google │ │ │ ├── developers │ │ │ ├── DefaultServletModule.java │ │ │ ├── DefaultStartupListener.java │ │ │ ├── Path.java │ │ │ └── UnauthorizedServlet.java │ │ │ └── training │ │ │ └── helloworld │ │ │ ├── Constants.java │ │ │ ├── HelloClass.java │ │ │ └── HelloWorldEndpoints.java │ │ └── webapp │ │ ├── WEB-INF │ │ ├── appengine-web.xml │ │ ├── cron.xml │ │ ├── logging.properties │ │ └── web.xml │ │ └── api │ │ └── 5xx │ │ └── index.jsp ├── pom.xml └── shared │ ├── pom.xml │ └── src │ └── main │ └── java │ └── com │ └── google │ └── developers │ ├── DevelopersSharedFilter.java │ ├── DevelopersSharedModule.java │ ├── DevelopersSharedServletModule.java │ ├── ModuleStartServlet.java │ └── PropertiesContant.java ├── hotswap-agent-examples-servlet-parent ├── README.md └── pom.xml ├── jersey1 ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── hotswap │ │ └── agent │ │ └── exemple │ │ └── jersey │ │ └── Jersey1Resource.java │ └── webapp │ └── WEB-INF │ └── web.xml ├── jersey2-jetty-hk2 ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── hotswap │ │ └── agent │ │ └── example │ │ └── jersey │ │ ├── Jersey2App.java │ │ ├── Jersey2Resource.java │ │ ├── MyApplication.java │ │ ├── MyApplicationBinder.java │ │ ├── TestService.java │ │ ├── TestService2.java │ │ └── TestService3.java │ └── webapp │ └── WEB-INF │ └── web.xml ├── jersey2 ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── hotswap │ │ └── agent │ │ └── exemple │ │ └── jersey │ │ └── Jersey2Resource.java │ └── webapp │ └── WEB-INF │ └── web.xml ├── plain-java ├── README.md ├── pom.xml ├── run-tests.sh └── src │ ├── main │ ├── java-extra │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ ├── HelloAnnotation.java │ │ │ ├── HelloInterface.java │ │ │ ├── HelloWorld.java │ │ │ └── HelloWorldHotswap.java │ ├── java-hotswap │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ ├── HelloAnnotation.java │ │ │ ├── HelloInterface.java │ │ │ └── HelloWorldHotswap.java │ ├── java │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ ├── HelloAnnotation.java │ │ │ ├── HelloInterface.java │ │ │ ├── HelloWorld.java │ │ │ └── HelloWorldHotswap.java │ ├── resources-extra │ │ └── test.properties │ ├── resources-watch │ │ ├── testWatch.properties │ │ └── testWatchReplace.properties │ └── resources │ │ ├── hotswap-agent.properties │ │ ├── test.properties │ │ └── testWatch.properties │ └── test │ └── java │ └── org │ └── hotswap │ └── agent │ └── example │ ├── HelloWorldHotswapTest.java │ └── HelloWorldTest.java ├── plain-servlet ├── README.md ├── pom.xml ├── run-tests.sh └── src │ ├── main │ ├── java-extra │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ ├── HelloWorldBaseServlet.java │ │ │ ├── HelloWorldServlet.java │ │ │ └── HelloWorldServletHotswap.java │ ├── java-hotswap │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ ├── HelloWorldBaseServlet.java │ │ │ └── HelloWorldServletHotswap.java │ ├── java │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ ├── HelloWorldBaseServlet.java │ │ │ ├── HelloWorldServlet.java │ │ │ └── HelloWorldServletHotswap.java │ ├── resources-extra │ │ └── test.properties │ ├── resources-watch │ │ ├── testWatch.properties │ │ └── testWatchReplace.properties │ ├── resources │ │ ├── hotswap-agent.properties │ │ ├── test.properties │ │ └── testWatch.properties │ ├── webapp-extra │ │ └── hello.jsp │ └── webapp │ │ ├── META-INF │ │ └── context.xml │ │ ├── WEB-INF │ │ ├── jboss-web.xml │ │ └── web.xml │ │ └── hello.jsp │ └── test │ └── java │ └── org │ └── hotswap │ └── agent │ └── example │ ├── HelloWorldServletHotswapIT.java │ ├── HelloWorldServletIT.java │ └── HelloWorldServletJspIT.java ├── pom.xml ├── resteasy-app ├── pom.xml ├── resteasy-managment │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── hotswap │ │ │ │ └── agent │ │ │ │ └── example │ │ │ │ └── service │ │ │ │ ├── BaseApplication.java │ │ │ │ └── PersonManagement.java │ │ └── webapp │ │ │ ├── WEB-INF │ │ │ ├── jboss-web.xml │ │ │ └── web.xml │ │ │ ├── index.jsp │ │ │ └── jboss-web.xml │ │ └── test │ │ └── java │ │ └── org │ │ └── hotswap │ │ └── agent │ │ └── example │ │ └── test │ │ └── JSONIgnorePropTest.java └── resteasy-model │ ├── pom.xml │ └── src │ └── main │ └── java │ └── org │ └── hotswap │ └── agent │ └── example │ └── model │ ├── Person.java │ └── PersonModelBase.java ├── run-tests.sh ├── spring-boot-kotlin ├── Dockerfile ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ └── springbootkotlin │ │ │ ├── ExampleApi.kt │ │ │ └── ExampleApplication.kt │ └── resources │ │ └── application.yml │ └── test │ └── resources │ └── application.yml ├── spring-boot ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── hotswap │ │ │ └── agent │ │ │ └── example │ │ │ └── springboot │ │ │ ├── HotswapSpringBoot.java │ │ │ ├── TestPojo.java │ │ │ ├── TestPojo2.java │ │ │ ├── TestRest.java │ │ │ └── TestRest2.java │ └── resources │ │ ├── application.properties │ │ └── hotswap-agent.properties │ └── test │ └── java │ └── org │ └── hotswap │ └── agent │ └── example │ └── springboot │ ├── BasicSpringBootTest.java │ └── RestTest.java └── spring-hibernate ├── README.md ├── pom.xml ├── runtime └── data │ ├── agent-test.hsqldb.lck │ ├── agent-test.hsqldb.properties │ └── agent-test.hsqldb.script └── src ├── main ├── java-extra │ └── org │ │ └── hotswap │ │ └── agent │ │ └── examples │ │ └── plain │ │ ├── HelloWorld.java │ │ └── HelloWorldHotswap.java ├── java-hotswap │ └── org │ │ └── hotswap │ │ └── agent │ │ └── examples │ │ └── service │ │ └── TestRepository.java ├── java │ └── org │ │ └── hotswap │ │ └── agent │ │ └── example │ │ ├── model │ │ └── TestEntity.java │ │ ├── mvc │ │ └── IndexController.java │ │ └── service │ │ ├── TestEntityService.java │ │ └── TestRepository.java ├── resources-extra │ └── test.properties ├── resources-watch │ ├── testWatch.properties │ └── testWatchReplace.properties ├── resources │ ├── META-INF │ │ └── persistence.xml │ ├── examplePlugin.resource │ ├── hotswap-agent.properties │ └── test.resource └── webapp │ ├── META-INF │ └── context.xml │ ├── WEB-INF │ ├── AgentWeb-servlet.xml │ ├── jboss-web.xml │ ├── jetty-env.xml │ ├── jsp │ │ └── test.jsp │ ├── spring │ │ ├── applicationContext-jpa.xml │ │ └── applicationContext-service.xml │ └── web.xml │ └── index.jsp └── test └── java └── org └── hotswap └── agent └── example └── mvc └── IndexControllerIT.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | #IntelliJ 4 | .idea 5 | *.iml 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HotswapAgent example applications 2 | ================================= 3 | 4 | Example applications for HotswapAgent plugins. 5 | 6 | The purpose of an example application is: 7 | * complex automate integration tests (check various configurations before a release, see `run-tests.sh` script) 8 | * to check "real world" plugin usage during plugin development (i.e. inside container) 9 | * to provide working solution for typical application setups 10 | * sandbox to simulate issues for existing or new setups 11 | 12 | Feel free to fork/branch and create an application for your setup (functional, but as simple as possible). 13 | General setups will be merged into the master. 14 | 15 | # plain-java 16 | This example uses only core agent library and runs without any framework support. Check this example 17 | to learn basic agent properties usage (extraClasspath, watchResources, autoHotswap). 18 | 19 | # plain-servlet 20 | Run hotwap agent with a servlet container/J2EE server (Jetty/Tomcat/JBoss). This example does pretty the same 21 | as plain-java, but checks the value as HTTP response strings. This examples checks also that various application 22 | server versions are supported. 23 | 24 | # custom-plugin 25 | Detail explanation and example of how to create custom plugin even inside your application. 26 | 27 | # spring-hibernate 28 | Complex project with typical setup Spring + Spring MVC + Hibernate. 29 | 30 | # seam-hibernate-jsf 31 | 32 | # cdi-hibernate-jsf 33 | -------------------------------------------------------------------------------- /custom-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | jar 7 | 8 | 9 | org.hotswapagent 10 | hotswap-agent-examples-aggregator 11 | 1.4.2-SNAPSHOT 12 | 13 | 14 | org.hotswap.plugin.examples 15 | custom-plugin 16 | 17 | 18 | 19 | org.hotswapagent 20 | hotswap-agent-core 21 | ${project.version} 22 | provided 23 | 24 | 25 | 26 | junit 27 | junit 28 | 4.12 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 39 | 40 | 41 | true 42 | org.hotswap.agent.example.RunPlugin 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /custom-plugin/src/main/java/org/hotswap/agent/example/RunPlugin.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import org.hotswap.agent.example.service.HelloWorldService; 4 | 5 | public class RunPlugin { 6 | public static void main(String[] args) throws InterruptedException { 7 | HelloWorldService helloWorldService = new HelloWorldService(); 8 | while(true) { 9 | System.out.print(helloWorldService.getExamplePluginResourceText()); 10 | System.out.print(","); 11 | System.out.print(helloWorldService.getLoadedClasses()); 12 | System.out.print(","); 13 | System.out.print(helloWorldService.getReloadedClasses()); 14 | System.out.println(";"); 15 | Thread.sleep(1000); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /custom-plugin/src/main/java/org/hotswap/agent/example/plugin/ReloadClassCommand.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.plugin; 2 | 3 | import org.hotswap.agent.command.MergeableCommand; 4 | import org.hotswap.agent.logging.AgentLogger; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * A command to merge multiple reload events into one execution and execute the logic in application classloader. 10 | */ 11 | public class ReloadClassCommand extends MergeableCommand { 12 | private static AgentLogger LOGGER = AgentLogger.getLogger(ReloadClassCommand.class); 13 | ClassLoader appClassLoader; 14 | String className; 15 | Object testEnityService; 16 | 17 | /** 18 | * @param appClassLoader Usually you need the application classloader as a parameter - to know in which 19 | * classloader the class you want to call lives 20 | * @param className reloaded className 21 | * @param testEnityService the target service registered with the plugin - not that we are still in the 22 | * plugin classloader and the service cannot be typed to agentexamples's class. 23 | */ 24 | public ReloadClassCommand(ClassLoader appClassLoader, String className, Object testEnityService) { 25 | this.appClassLoader = appClassLoader; 26 | this.className = className; 27 | this.testEnityService = testEnityService; 28 | } 29 | 30 | @Override 31 | public void executeCommand() { 32 | try { 33 | // Now we have application classloader and the service on which to invoke the method, we can use 34 | // reflection directly 35 | // but for demonstration purpose we invoke a plugin class, that lives in the application classloader 36 | Method setExamplePluginResourceText = appClassLoader.loadClass(ReloadClassService.class.getName()) 37 | .getDeclaredMethod("classReloaded", String.class, Object.class); 38 | setExamplePluginResourceText.invoke(null, className, testEnityService); 39 | } catch (Exception e) { 40 | LOGGER.error("Error invoking {}.reload()", e, ReloadClassService.class.getName()); 41 | } 42 | 43 | } 44 | 45 | /** 46 | * Use equals to group "similar commands". If multiple "equals" commands are scheduled during 47 | * the scheduler timeout, only the last command is executed. If you need information regarding 48 | * all merged commands and/or select which is executed, use MergeableCommand superclass. 49 | */ 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) return true; 53 | if (o == null || getClass() != o.getClass()) return false; 54 | 55 | ReloadClassCommand that = (ReloadClassCommand) o; 56 | 57 | if (!className.equals(that.className)) return false; 58 | 59 | return true; 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return className.hashCode(); 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return "ReloadClassCommand{" + 70 | "className='" + className + '\'' + 71 | ", helloWorldService=" + testEnityService + 72 | '}'; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /custom-plugin/src/main/java/org/hotswap/agent/example/plugin/ReloadClassService.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.plugin; 2 | 3 | import org.hotswap.agent.example.service.HelloWorldService; 4 | 5 | /** 6 | * This class should be used in the application classloader. 7 | *

8 | * Hotswap agent defines plugin classes in BOTH classloaders agent AND application. You need to know for which 9 | * classloader is each class targeted. In this example plugin, this is the only class targeted towards application 10 | * classloader. 11 | */ 12 | public class ReloadClassService { 13 | /** 14 | * Method invoked from ReloadClassCommand using reflection in application classloader. 15 | * 16 | * @param className class name 17 | * @param helloWorldServiceObject object originally from the application, registered in the plugin. It is from 18 | * application classloader and hence cannot be typed in plugin classloader. Now 19 | * we are back in application classloader and can safely cast back to it's type. 20 | */ 21 | public static void classReloaded(String className, Object helloWorldServiceObject) { 22 | 23 | // this is the main purpose of this class. Finally, we can use typed variables and 24 | // use normal code instead of reflection. Imagine more complex code to reload part of your 25 | // framework - it would be inconvenient to use reflection for each invocation. 26 | HelloWorldService helloWorldService = (HelloWorldService) helloWorldServiceObject; 27 | 28 | // call framework method directly 29 | helloWorldService.addReloadedClass(className); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /custom-plugin/src/main/java/org/hotswap/agent/example/service/HelloWorldService.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.service; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | /** 7 | * Example service which is watched for changes and invoked from the plugin. 8 | */ 9 | public class HelloWorldService { 10 | // Add each reloaded class (by hotswap or watcher) 11 | Set reloadedClasses = new HashSet(); 12 | 13 | // count of loaded classes 14 | int loadedClasses; 15 | 16 | // text from examplePlugin.resource, it should be automatically updated after the resource is modified 17 | String examplePluginResourceText; 18 | 19 | public String getExamplePluginResourceText() { 20 | return examplePluginResourceText; 21 | } 22 | 23 | public void setExamplePluginResourceText(String examplePluginResourceText) { 24 | this.examplePluginResourceText = examplePluginResourceText; 25 | } 26 | 27 | public int getLoadedClasses() { 28 | return loadedClasses; 29 | } 30 | 31 | public void setLoadedClasses(int loadedClasses) { 32 | this.loadedClasses = loadedClasses; 33 | } 34 | 35 | // reflection command currently supports only object types 36 | public void setLoadedClasses(Integer loadedClasses) { 37 | this.loadedClasses = loadedClasses; 38 | } 39 | 40 | public void addReloadedClass(String className) { 41 | reloadedClasses.add(className); 42 | } 43 | 44 | public Set getReloadedClasses() { 45 | return reloadedClasses; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /custom-plugin/src/main/resources/examplePlugin.resource: -------------------------------------------------------------------------------- 1 | Change this file and see the result in TestEntityService.helloWorld() -------------------------------------------------------------------------------- /custom-plugin/src/main/resources/hotswap-agent.properties: -------------------------------------------------------------------------------- 1 | pluginPackages=org.hotswap.agent.example.plugin 2 | 3 | watchResources=src/main/resources 4 | 5 | # uncomment to test autohotswap feature 6 | #autoHotswap=true 7 | 8 | LOGGER.org.hotswap.agent=DEBUG 9 | LOGGER.org.hotswap.agent.plugin=TRACE 10 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs-spring/src/main/java/org/hotswap/agent/plugin/cxf/spring/jaxrs/Service1.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.plugin.cxf.spring.jaxrs; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class Service1 { 7 | void doSomething() { 8 | System.out.println("Service1 print"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs-spring/src/main/java/org/hotswap/agent/plugin/cxf/spring/jaxrs/Service2.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.plugin.cxf.spring.jaxrs; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class Service2 { 7 | void doSomething() { 8 | System.out.println("Service2 print"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs-spring/src/main/java/org/hotswap/agent/plugin/cxf/spring/jaxrs/ServiceEndpoint.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.plugin.cxf.spring.jaxrs; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.Produces; 6 | import javax.ws.rs.QueryParam; 7 | import javax.ws.rs.core.MediaType; 8 | import javax.ws.rs.core.Response; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | @Path("/services") 13 | public class ServiceEndpoint { 14 | 15 | @Autowired 16 | private Service1 service1; 17 | 18 | @Autowired 19 | private Service2 service2; 20 | 21 | @Path("/service1") 22 | @GET 23 | @Produces(MediaType.TEXT_PLAIN) 24 | public Response service1(@QueryParam("echo") final String payload) { 25 | service2.doSomething(); 26 | return Response.ok(payload).build(); 27 | } 28 | 29 | // @Path("/service2") 30 | // @GET 31 | // @Produces(MediaType.APPLICATION_JSON) 32 | // public Response service2() { 33 | // service1.doSomething(); 34 | // return Response.ok().build(); 35 | // } 36 | } 37 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs-spring/src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs-spring/src/main/webapp/WEB-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs-spring/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | JAX-RS Simple Service 4 | JAX-RS Simple Service 5 | 6 | contextConfigLocation 7 | WEB-INF/beans.xml 8 | 9 | 10 | org.springframework.web.context.ContextLoaderListener 11 | 12 | 13 | CXFServlet 14 | org.apache.cxf.transport.servlet.CXFServlet 15 | 1 16 | 17 | 18 | CXFServlet 19 | /* 20 | 21 | 22 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/java/org/hotswap/agent/example/cxf/jaxrs/AcceptPerson.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.cxf.jaxrs; 2 | 3 | import javax.xml.bind.annotation.XmlElement; 4 | 5 | public class AcceptPerson { 6 | @XmlElement 7 | String accepted; 8 | 9 | public String getAccepted() { 10 | return accepted; 11 | } 12 | 13 | public void setAccepted(String accepted) { 14 | this.accepted = accepted; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/java/org/hotswap/agent/example/cxf/jaxrs/Person.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.cxf.jaxrs; 2 | 3 | import javax.xml.bind.annotation.XmlElement; 4 | import javax.xml.bind.annotation.XmlRootElement; 5 | 6 | @XmlRootElement 7 | public class Person { 8 | String firstName; 9 | String lastName; 10 | Integer phoneNumber; 11 | String email; 12 | String unknown; 13 | 14 | @XmlElement 15 | public String getFirstName() { 16 | return firstName; 17 | } 18 | 19 | public void setFirstName(String firstName) { 20 | this.firstName = firstName; 21 | } 22 | 23 | @XmlElement 24 | public String getLastName() { 25 | return lastName; 26 | } 27 | 28 | public void setLastName(String lastName) { 29 | this.lastName = lastName; 30 | } 31 | 32 | @XmlElement 33 | public Integer getPhoneNumber() { 34 | return phoneNumber; 35 | } 36 | 37 | public void setPhoneNumber(Integer phoneNumber) { 38 | this.phoneNumber = phoneNumber; 39 | } 40 | 41 | @XmlElement 42 | public String getEmail() { 43 | return email; 44 | } 45 | 46 | public void setEmail(String email) { 47 | this.email = email; 48 | } 49 | public String getUnknown() { 50 | return unknown; 51 | } 52 | 53 | public void setUnknown(String unknown) { 54 | this.unknown = unknown; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/java/org/hotswap/agent/example/cxf/jaxrs/Service1.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.cxf.jaxrs; 2 | 3 | public class Service1 { 4 | void doSomething() { 5 | System.out.println("Service1 print"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/java/org/hotswap/agent/example/cxf/jaxrs/Service2.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.cxf.jaxrs; 2 | 3 | public class Service2 { 4 | void doSomething() { 5 | System.out.println("Service2 print"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/java/org/hotswap/agent/example/cxf/jaxrs/ServiceEndpoint.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.cxf.jaxrs; 2 | 3 | import java.util.UUID; 4 | 5 | import javax.inject.Inject; 6 | import javax.ws.rs.Consumes; 7 | import javax.ws.rs.GET; 8 | import javax.ws.rs.POST; 9 | import javax.ws.rs.Path; 10 | import javax.ws.rs.Produces; 11 | import javax.ws.rs.QueryParam; 12 | import javax.ws.rs.core.MediaType; 13 | import javax.ws.rs.core.Response; 14 | 15 | @Path("/services") 16 | public class ServiceEndpoint { 17 | 18 | @Inject 19 | private Service1 service1; 20 | 21 | @Inject 22 | private Service2 service2; 23 | 24 | @Inject 25 | private StatelessBean statelessBean; 26 | 27 | public ServiceEndpoint() { 28 | super(); 29 | } 30 | 31 | @Path("/service1") 32 | @GET 33 | @Produces(MediaType.TEXT_PLAIN) 34 | public Response service1(@QueryParam("echo") final String payload) { 35 | service2.doSomething(); 36 | return Response.ok(payload).build(); 37 | } 38 | 39 | @Path("/service2") 40 | @GET 41 | @Produces(MediaType.APPLICATION_JSON) 42 | public Response service2() { 43 | service1.doSomething(); 44 | return Response.ok().build(); 45 | } 46 | 47 | @Path("/person") 48 | @POST 49 | @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) 50 | @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) 51 | public AcceptPerson action(Person person) throws Exception { 52 | if (person != null) { 53 | AcceptPerson response = new AcceptPerson(); 54 | response.setAccepted("Done."); 55 | return response; 56 | } 57 | return null; 58 | } 59 | 60 | @GET 61 | @Produces(MediaType.TEXT_PLAIN) 62 | @Path("simple") 63 | public Response getSimple() { 64 | //statistics.updateStatistic(0); 65 | return Response.ok(statelessBean.getHello()).build(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/java/org/hotswap/agent/example/cxf/jaxrs/StatelessBean.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.cxf.jaxrs; 2 | 3 | import javax.ejb.Stateless; 4 | 5 | @Stateless 6 | public class StatelessBean { 7 | 8 | public String getHello() { 9 | return getHelloInt(); 10 | } 11 | 12 | private String getHelloInt() { 13 | return "hello"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/webapp/WEB-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /cxf/cxf-jaxrs/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | JAX-RS Simple Service 4 | JAX-RS Simple Service 5 | 6 | 11 | 12 | 13 | org.jboss.weld.environment.servlet.Listener 14 | 15 | 16 | 17 | CXFServlet 18 | org.apache.cxf.cdi.CXFCdiServlet 19 | 1 20 | 21 | 22 | 23 | 24 | BeanManager 25 | javax.enterprise.inject.spi.BeanManager 26 | 27 | 28 | 29 | CXFServlet 30 | /* 31 | 32 | 33 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM hotswapagent/tomcat 2 | RUN mkdir -p /extra_class_path 3 | RUN mkdir -p /webapp_dir 4 | COPY ./target/deltaspike-hibernate-jsf-0.0.1-SNAPSHOT.war ${DEPLOYMENT_DIR} 5 | ENV JAVA_OPTS="-XXaltjvm=dcevm -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/hotswap-agent/hotswap-agent.jar -Dextra.class.path=/extra_class_path -Dwebapp.dir=/webapp_dir" 6 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/buildAndRunDebug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mvn clean package && docker build -t deltaspike-hibernate-jsf . 3 | docker run -ti --rm -p 8080:8080 -p 8000:8000 -v `pwd`/target/classes:/extra_class_path -v `pwd`/src/main/webapp:/webapp_dir -v /var/run/docker.sock:/var/run/docker.sock deltaspike-hibernate-jsf 4 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/ContextListener.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike; 2 | 3 | import javax.inject.Inject; 4 | import javax.persistence.EntityManagerFactory; 5 | import javax.servlet.ServletContextEvent; 6 | import javax.servlet.ServletContextListener; 7 | 8 | public class ContextListener implements ServletContextListener { 9 | 10 | // @Inject 11 | // private EntityManagerFactory emf; 12 | 13 | @Override 14 | public void contextDestroyed(ServletContextEvent arg0) { 15 | // Do nothing 16 | } 17 | 18 | @Override 19 | public void contextInitialized(ServletContextEvent arg0) { 20 | // initialize entity manager factory on application statup 21 | // emf.createEntityManager(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/appl/MasterDetailControllerBase.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.appl; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.enterprise.context.Conversation; 6 | import javax.inject.Inject; 7 | 8 | import org.primefaces.event.SelectEvent; 9 | 10 | public abstract class MasterDetailControllerBase implements Serializable { 11 | 12 | private static final long serialVersionUID = 5824242841963664386L; 13 | 14 | protected static final int LIST_LEVEL = 1; 15 | 16 | protected static final int DETAIL_LEVEL = 2; 17 | 18 | private int detailLevel = LIST_LEVEL; 19 | 20 | private T detail; 21 | 22 | @Inject 23 | private Conversation conversation; 24 | 25 | public void clearDetail() { 26 | if (!conversation.isTransient()) { 27 | conversation.end(); 28 | } 29 | } 30 | 31 | public void selectNewDetail() { 32 | selectDetail(null); 33 | } 34 | 35 | public void selectDetail(T detail) { 36 | this.detail = detail; 37 | 38 | if (!conversation.isTransient()) { 39 | conversation.end(); 40 | } 41 | conversation.begin(); 42 | 43 | onDetailSelected(detail); 44 | } 45 | 46 | @SuppressWarnings("unchecked") 47 | public void onSelectDetailEvent(SelectEvent event) { 48 | selectDetail((T) event.getObject()); 49 | detailLevel = DETAIL_LEVEL; 50 | } 51 | 52 | public T getSelection() { 53 | return detail; 54 | } 55 | 56 | public void setSelection(T selection) { 57 | // Nothing to do 58 | } 59 | 60 | abstract protected void onDetailSelected(T detail); 61 | 62 | public T getDetail() { 63 | return detail; 64 | } 65 | 66 | protected void setDetail(T detail) { 67 | this.detail = detail; 68 | } 69 | 70 | public int getDetailLevel() { 71 | return detailLevel; 72 | } 73 | 74 | public void setDetailLevel(int detailLevel) { 75 | this.detailLevel = detailLevel; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/ApplicationBean.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.enterprise.context.ApplicationScoped; 6 | import javax.inject.Inject; 7 | import javax.inject.Named; 8 | 9 | @Named 10 | @ApplicationScoped 11 | public class ApplicationBean implements Serializable { 12 | 13 | private static final long serialVersionUID = -8572299300825949098L; 14 | 15 | @Inject 16 | private HelloProducer1 helloProducer1; 17 | 18 | // @Inject 19 | // private HelloProducer2 helloProducer2; 20 | 21 | private int helloCount = 0; 22 | 23 | public String hello() { 24 | helloCount ++; 25 | return "ApplicationBean[helloCount=" + helloCount + "]:" + helloProducer1.hello(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/GroupedConvBean1.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Named; 7 | 8 | import org.apache.deltaspike.core.api.scope.GroupedConversationScoped; 9 | import org.apache.deltaspike.core.spi.scope.conversation.GroupedConversationManager; 10 | 11 | @Named 12 | @GroupedConversationScoped 13 | public class GroupedConvBean1 implements Serializable { 14 | 15 | private static final long serialVersionUID = 3051650311158372971L; 16 | 17 | private static int conversationCount = 0; 18 | 19 | private int conversationId; 20 | 21 | @Inject 22 | private HelloProducer1 helloProducer1; 23 | 24 | @Inject 25 | private HelloProducer2 helloProducer2; 26 | 27 | @Inject 28 | private GroupedConversationManager conversationManager; 29 | 30 | private int helloCount = 0; 31 | 32 | public GroupedConvBean1() { 33 | conversationId = conversationCount; 34 | conversationCount ++; 35 | } 36 | 37 | public String hello() { 38 | helloCount ++; 39 | return "GroupedConvBean1[conversationId=" + conversationId + ",helloCount=" + helloCount + "]:" + helloProducer2.hello(); 40 | } 41 | 42 | public void closeConversation() { 43 | conversationManager.closeConversationGroup(getClass()); 44 | } 45 | 46 | public void closeAllWindowConversations() { 47 | conversationManager.closeConversations(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/GroupedConvBean2.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Named; 7 | 8 | import org.apache.deltaspike.core.api.scope.ConversationGroup; 9 | import org.apache.deltaspike.core.api.scope.GroupedConversationScoped; 10 | import org.apache.deltaspike.core.spi.scope.conversation.GroupedConversationManager; 11 | 12 | @Named 13 | @GroupedConversationScoped 14 | @ConversationGroup(MyConversationGroup.class) 15 | public class GroupedConvBean2 implements Serializable { 16 | 17 | private static final long serialVersionUID = -3305275675889306638L; 18 | 19 | private static int conversationCount = 0; 20 | 21 | private int conversationId; 22 | 23 | @Inject 24 | private HelloProducer1 helloProducer1; 25 | 26 | @Inject 27 | private GroupedConversationManager conversationManager; 28 | 29 | private int helloCount = 0; 30 | 31 | // @Inject 32 | // private HelloProducer2 helloProducer2; 33 | // 34 | // @Inject 35 | // private HelloProducer1 helloProducer3; 36 | 37 | public GroupedConvBean2() { 38 | conversationId = conversationCount; 39 | conversationCount ++; 40 | } 41 | 42 | public String hello() { 43 | helloCount ++; 44 | return "GroupedConvBean2[conversationId=" + conversationId + ",helloCount=" + helloCount + "]:" + helloProducer1.hello(); 45 | } 46 | 47 | public void closeConversation() { 48 | conversationManager.closeConversationGroup(MyConversationGroup.class); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/GroupedConvBean3.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Named; 7 | 8 | import org.apache.deltaspike.core.api.scope.ConversationGroup; 9 | import org.apache.deltaspike.core.api.scope.GroupedConversationScoped; 10 | 11 | @Named 12 | @GroupedConversationScoped 13 | @ConversationGroup(MyConversationGroup.class) 14 | public class GroupedConvBean3 implements Serializable { 15 | 16 | private static final long serialVersionUID = -7175483534416650494L; 17 | 18 | private static int conversationCount = 0; 19 | 20 | private int conversationId; 21 | 22 | @Inject 23 | private HelloProducer1 helloProducer1; 24 | 25 | private int helloCount = 0; 26 | 27 | @Inject 28 | private HelloProducer2 helloProducer2; 29 | // 30 | // @Inject 31 | // private HelloProducer1 helloProducer3; 32 | 33 | public GroupedConvBean3() { 34 | conversationId = conversationCount; 35 | conversationCount ++; 36 | } 37 | 38 | public String hello() { 39 | helloCount ++; 40 | return "GroupedConvBean3[conversationId=" + conversationId + ",helloCount=" + helloCount + "]:" + helloProducer2.hello(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/HelloProducer1.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.enterprise.context.Dependent; 6 | 7 | @Dependent 8 | public class HelloProducer1 implements Serializable { 9 | 10 | private static final long serialVersionUID = 3869560189111153965L; 11 | 12 | public String hello() { 13 | return "HelloProducer1:hello"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/HelloProducer2.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.enterprise.context.SessionScoped; 6 | 7 | @SessionScoped 8 | public class HelloProducer2 implements Serializable { 9 | 10 | private static final long serialVersionUID = 1426463110054473736L; 11 | 12 | public String hello() { 13 | return "HelloProducer2:hello"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/JsfViewBean.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.faces.view.ViewScoped; 6 | import javax.inject.Inject; 7 | import javax.inject.Named; 8 | 9 | @Named 10 | @ViewScoped 11 | public class JsfViewBean implements Serializable { 12 | 13 | private static final long serialVersionUID = -8176648612947203701L; 14 | 15 | private static int idCount = 0; 16 | 17 | private int beanId; 18 | 19 | @Inject 20 | private HelloProducer1 helloProducer1; 21 | 22 | @Inject 23 | private HelloProducer2 helloProducer2; 24 | 25 | private int helloCount = 0; 26 | 27 | public JsfViewBean() { 28 | beanId = idCount; 29 | idCount ++; 30 | } 31 | 32 | public String hello() { 33 | helloCount ++; 34 | return "JsfViewBean[beanId=" + beanId + ",helloCount=" + helloCount + "]:" + helloProducer2.hello(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/ManagedBean.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Named; 7 | 8 | @Named 9 | public class ManagedBean implements Serializable { 10 | 11 | private static final long serialVersionUID = -3776778289861207553L; 12 | 13 | private static int idCount = 0; 14 | 15 | private int beanId; 16 | 17 | @Inject 18 | private HelloProducer1 helloProducer1; 19 | 20 | @Inject 21 | private HelloProducer2 helloProducer2; 22 | 23 | @Inject 24 | private HelloProducer2 helloProducer3; 25 | 26 | private int helloCount = 0; 27 | 28 | public ManagedBean() { 29 | beanId = idCount; 30 | idCount ++; 31 | } 32 | 33 | public String hello() { 34 | helloCount ++; 35 | return "ManagedBean[beanId=" + beanId + ",helloCount=" + helloCount + "]:" + helloProducer3.hello(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/MyConversationGroup.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | public class MyConversationGroup { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/OmniViewBean.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Named; 7 | 8 | import org.omnifaces.cdi.ViewScoped; 9 | 10 | @Named 11 | @ViewScoped 12 | public class OmniViewBean implements Serializable { 13 | 14 | private static final long serialVersionUID = -8176648612947203701L; 15 | 16 | private static int idCount = 0; 17 | 18 | private int beanId; 19 | 20 | @Inject 21 | private HelloProducer1 helloProducer1; 22 | 23 | // @Inject 24 | // private HelloProducer2 helloProducer2; 25 | 26 | private int helloCount = 0; 27 | 28 | public OmniViewBean() { 29 | beanId = idCount; 30 | idCount ++; 31 | } 32 | 33 | public String hello() { 34 | helloCount ++; 35 | return "OmniViewBean[beanId=" + beanId + ",helloCount=" + helloCount + "]:" + helloProducer1.hello(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/SessionBean.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | public class SessionBean implements Serializable { 6 | 7 | private static final long serialVersionUID = 1320916719573569233L; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/beans/WindowBean.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.beans; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.inject.Inject; 6 | import javax.inject.Named; 7 | 8 | import org.apache.deltaspike.core.api.scope.WindowScoped; 9 | 10 | @Named 11 | @WindowScoped 12 | public class WindowBean implements Serializable { 13 | 14 | private static final long serialVersionUID = 6608194853271664609L; 15 | 16 | private static int windowCount = 0; 17 | 18 | private int windowId; 19 | 20 | @Inject 21 | private HelloProducer1 helloProducer1; 22 | 23 | private int helloCount = 0; 24 | 25 | // @Inject 26 | // private HelloProducer2 helloProducer2; 27 | // 28 | // @Inject 29 | // private HelloProducer1 helloProducer3; 30 | // 31 | public WindowBean() { 32 | windowId = windowCount; 33 | windowCount ++; 34 | } 35 | 36 | public String hello() { 37 | helloCount ++; 38 | return "WindowBean[windowId=" + windowId + ",helloCount=" + helloCount + "]:" + helloProducer1.hello(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/em/EntityManagerFactoryProducer.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.em; 2 | 3 | import javax.enterprise.context.ApplicationScoped; 4 | import javax.enterprise.inject.Disposes; 5 | import javax.enterprise.inject.Produces; 6 | import javax.persistence.EntityManagerFactory; 7 | import javax.persistence.Persistence; 8 | 9 | public class EntityManagerFactoryProducer { 10 | @Produces 11 | @ApplicationScoped 12 | public EntityManagerFactory create() { 13 | return Persistence.createEntityManagerFactory("testPU"); 14 | } 15 | 16 | public void destroy(@Disposes EntityManagerFactory factory) { 17 | factory.close(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/em/EntityManagerProducer.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.em; 2 | 3 | import javax.enterprise.context.RequestScoped; 4 | import javax.enterprise.inject.Disposes; 5 | import javax.enterprise.inject.Produces; 6 | import javax.inject.Inject; 7 | import javax.persistence.EntityManager; 8 | import javax.persistence.EntityManagerFactory; 9 | 10 | public class EntityManagerProducer { 11 | 12 | @Inject 13 | private EntityManagerFactory emf; 14 | 15 | @Produces 16 | @RequestScoped 17 | public EntityManager create() { 18 | return emf.createEntityManager(); 19 | } 20 | 21 | public void close(@Disposes EntityManager em) { 22 | if (em.isOpen()) { 23 | em.close(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/enums/UserRole.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.enums; 2 | 3 | public enum UserRole { 4 | 5 | ADMIN("A", "userRole.ADMIN"), 6 | USER("U", "userRole.USER"); 7 | 8 | public static UserRole getByCode(String code) { 9 | if (code != null) { 10 | for (UserRole en : UserRole.values()) { 11 | if (code.equals(en.getCode())) { 12 | return en; 13 | } 14 | } 15 | } 16 | 17 | return null; 18 | } 19 | 20 | final String code; 21 | final String rbKey; 22 | 23 | UserRole(String code, String rbKey) { 24 | this.code = code; 25 | this.rbKey = rbKey; 26 | } 27 | 28 | public String getCode() { 29 | return code; 30 | } 31 | 32 | public String getRbKey() { 33 | return rbKey; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/enums/UserRoleConverter.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.enums; 2 | 3 | import javax.persistence.AttributeConverter; 4 | import javax.persistence.Converter; 5 | 6 | @Converter(autoApply = true) 7 | public class UserRoleConverter implements AttributeConverter { 8 | @Override 9 | public String convertToDatabaseColumn(UserRole attribute) { 10 | return attribute != null ? attribute.getCode() : null; 11 | } 12 | 13 | @Override 14 | public UserRole convertToEntityAttribute(String code) { 15 | return UserRole.getByCode(code); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/forms/LoginForm.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.forms; 2 | 3 | import javax.enterprise.inject.Model; 4 | 5 | import org.hibernate.validator.constraints.NotEmpty; 6 | 7 | @Model 8 | public class LoginForm { 9 | 10 | @NotEmpty 11 | private String userName = "admin"; 12 | 13 | @NotEmpty 14 | private String password = "admin"; 15 | 16 | public String getUserName() { 17 | return userName; 18 | } 19 | 20 | public void setUserName(String userName) { 21 | this.userName = userName; 22 | } 23 | 24 | public String getPassword() { 25 | return password; 26 | } 27 | 28 | public void setPassword(String password) { 29 | this.password = password; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/forms/UserForm.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.forms; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.enterprise.inject.Model; 6 | 7 | import org.hotswap.agent.example.deltaspike.enums.UserRole; 8 | 9 | @Model 10 | public class UserForm implements Serializable { 11 | 12 | private static final long serialVersionUID = 1243968054551528996L; 13 | 14 | private Long userId; 15 | 16 | private String userName; 17 | 18 | private String firstName; 19 | 20 | private String lastName; 21 | 22 | private UserRole role = UserRole.USER; 23 | 24 | private boolean active; 25 | 26 | private String email; 27 | 28 | public boolean isNew() { 29 | return userId == null; 30 | } 31 | 32 | public Long getUserId() { 33 | return userId; 34 | } 35 | 36 | public void setUserId(Long userId) { 37 | this.userId = userId; 38 | } 39 | 40 | public String getUserName() { 41 | return userName; 42 | } 43 | 44 | public void setUserName(String userName) { 45 | this.userName = userName; 46 | } 47 | 48 | public String getFirstName() { 49 | return firstName; 50 | } 51 | 52 | public void setFirstName(String firstName) { 53 | this.firstName = firstName; 54 | } 55 | 56 | public String getLastName() { 57 | return lastName; 58 | } 59 | 60 | public void setLastName(String lastName) { 61 | this.lastName = lastName; 62 | } 63 | 64 | public UserRole getRole() { 65 | return role; 66 | } 67 | 68 | public void setRole(UserRole role) { 69 | this.role = role; 70 | } 71 | 72 | public boolean isActive() { 73 | return active; 74 | } 75 | 76 | public void setActive(boolean active) { 77 | this.active = active; 78 | } 79 | 80 | public String getEmail() { 81 | return email; 82 | } 83 | 84 | public void setEmail(String email) { 85 | this.email = email; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/jpa/User.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.jpa; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import javax.persistence.Column; 7 | import javax.persistence.Entity; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.Id; 10 | import javax.persistence.Table; 11 | 12 | import org.hotswap.agent.example.deltaspike.enums.UserRole; 13 | 14 | @Entity 15 | @Table(name = "USERS") 16 | public class User implements Serializable { 17 | 18 | private static final long serialVersionUID = -1382710855011197405L; 19 | 20 | @Id 21 | @GeneratedValue 22 | @Column(name = "user_id", nullable = false) 23 | private Long userId; 24 | @Column(name = "user_name", nullable = false) 25 | private String userName; 26 | @Column(name = "first_name", nullable = false) 27 | private String firstName; 28 | @Column(name = "last_name", nullable = false) 29 | private String lastName; 30 | @Column(name = "email") 31 | private String email; 32 | @Column(name = "role", nullable = false) 33 | private UserRole role; 34 | @Column(name = "update_date") 35 | private Date updateDate; 36 | 37 | public UserRole getRole() { 38 | return role; 39 | } 40 | 41 | public void setRole(UserRole role) { 42 | this.role = role; 43 | } 44 | 45 | public User() { 46 | } 47 | 48 | public User(Long userId) { 49 | this.userId = userId; 50 | } 51 | 52 | public Long getUserId() { 53 | return userId; 54 | } 55 | 56 | public void setUserId(Long userId) { 57 | this.userId = userId; 58 | } 59 | 60 | public String getUserName() { 61 | return userName; 62 | } 63 | 64 | public void setUserName(String userName) { 65 | this.userName = userName; 66 | } 67 | 68 | public String getFirstName() { 69 | return firstName; 70 | } 71 | 72 | public void setFirstName(String firstName) { 73 | this.firstName = firstName; 74 | } 75 | 76 | public String getLastName() { 77 | return lastName; 78 | } 79 | 80 | public void setLastName(String lastName) { 81 | this.lastName = lastName; 82 | } 83 | 84 | public String getEmail() { 85 | return email; 86 | } 87 | 88 | public void setEmail(String email) { 89 | this.email = email; 90 | } 91 | 92 | public Date getUpdateDate() { 93 | return updateDate; 94 | } 95 | 96 | public void setUpdateDate(Date updateDate) { 97 | this.updateDate = updateDate; 98 | } 99 | 100 | @Override 101 | public int hashCode() { 102 | int hash = 0; 103 | hash += (userId != null ? userId.hashCode() : 0); 104 | return hash; 105 | } 106 | 107 | @Override 108 | public boolean equals(Object object) { 109 | if (!(object instanceof User)) { 110 | return false; 111 | } 112 | User other = (User) object; 113 | if ((this.userId == null && other.userId != null) || (this.userId != null && !this.userId.equals(other.userId))) { 114 | return false; 115 | } 116 | return true; 117 | } 118 | 119 | @Override 120 | public String toString() { 121 | return "org.hotswap.agent.example.deltaspike.jpa.User[userId=" + userId + "]"; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/jpa/UserRepository.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.jpa; 2 | 3 | 4 | import org.apache.deltaspike.data.api.AbstractEntityRepository; 5 | import org.apache.deltaspike.data.api.Repository; 6 | 7 | @Repository 8 | public abstract class UserRepository extends AbstractEntityRepository { 9 | 10 | public abstract User findOptionalByUserName(String userName); 11 | 12 | public abstract User findOptionalByUserId(Long userId); 13 | } 14 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/jsf/AppJsfModuleConfig.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.jsf; 2 | 3 | import javax.enterprise.inject.Specializes; 4 | 5 | import org.apache.deltaspike.jsf.api.config.JsfModuleConfig; 6 | import org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig; 7 | 8 | @Specializes 9 | public class AppJsfModuleConfig extends JsfModuleConfig { 10 | 11 | private static final long serialVersionUID = -3382887706461201688L; 12 | 13 | @Override 14 | public ClientWindowConfig.ClientWindowRenderMode getDefaultWindowMode() { 15 | return ClientWindowConfig.ClientWindowRenderMode.NONE; 16 | } 17 | } -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/jsf/Messages.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.jsf; 2 | 3 | import org.apache.deltaspike.core.api.message.MessageBundle; 4 | import org.apache.deltaspike.core.api.message.MessageTemplate; 5 | 6 | @MessageBundle 7 | public interface Messages { 8 | 9 | @MessageTemplate("login.msg.loginOk") 10 | public String loginOk(); 11 | 12 | @MessageTemplate("login.msg.loginFailed") 13 | public String loginFailed(); 14 | 15 | @MessageTemplate("common.saveOK") 16 | public String saveOK(); 17 | 18 | @MessageTemplate("common.saveFailed") 19 | public String saveFailed(); 20 | 21 | @MessageTemplate("common.deleteOK") 22 | public String deleteOK(); 23 | 24 | @MessageTemplate("common.deleteFailed") 25 | public String deleteFailed(); 26 | } 27 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/java/org/hotswap/agent/example/deltaspike/jsf/Pages.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.deltaspike.jsf; 2 | 3 | import org.apache.deltaspike.core.api.config.view.ViewConfig; 4 | import org.apache.deltaspike.jsf.api.config.view.Folder; 5 | import org.apache.deltaspike.jsf.api.config.view.View; 6 | import org.apache.deltaspike.jsf.api.config.view.View.NavigationMode; 7 | 8 | @Folder(name="/") 9 | public interface Pages extends ViewConfig { 10 | 11 | class Index implements ViewConfig {} 12 | 13 | @View(navigation = NavigationMode.REDIRECT) 14 | public interface Appl extends Pages { 15 | 16 | class Beans implements Appl {}; 17 | class Users implements Appl {} 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/resources/hotswap-agent.properties: -------------------------------------------------------------------------------- 1 | # Logger level 2 | # LOGGER=warning 3 | # LOGGER.org.hotswap.agent.plugin.owb=trace 4 | # LOGGER.org.hotswap.agent.plugin.weld=trace 5 | # LOGGER.org.hotswap.agent.plugin.cdi=debug 6 | # reference -Dextra.class.path=... 7 | autoHotswap=true 8 | extraClassPath=${extra.class.path} 9 | webappDir=${webapp.dir} 10 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/resources/messages_en.properties: -------------------------------------------------------------------------------- 1 | app.title=HotswapAgent - Deltaspike TEST 2 | common.save=Save 3 | common.cancel=Cancel 4 | common.areYouSureToDelete=Are you sure to delete? 5 | common.yes=Yes 6 | common.no=No 7 | menu.home=Home 8 | menu.users=Repository Test (Users) 9 | menu.beans=Context Tests 10 | users=Users 11 | users.userName=User name 12 | users.firstName=First name 13 | users.lastName=Last name 14 | users.email=Email 15 | users.role=Role 16 | users.new=New user 17 | users.userId=User ID 18 | users.user=User 19 | userRole.ADMIN=Admin 20 | userRole.USER=User 21 | error.loginPage=To login page 22 | error.refresh=refresh -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/WEB-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/WEB-INF/faces-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | messages 11 | messages 12 | 13 | 14 | en 15 | en 16 | 17 | 18 | 19 | 20 | 21 | org.omnifaces.context.OmniPartialViewContextFactory 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | deltaspike-hibernate-jsf 4 | 5 | 6 | Faces Servlet 7 | javax.faces.webapp.FacesServlet 8 | 1 9 | 10 | 11 | 12 | Faces Servlet 13 | *.jsf 14 | 15 | 16 | 17 | 18 | org.apache.webbeans.servlet.WebBeansConfigurationListener 19 | 20 | 21 | 22 | 27 | 28 | 29 | BeanManager 30 | javax.enterprise.inject.spi.BeanManager 31 | 32 | 33 | 34 | org.hotswap.agent.example.deltaspike.ContextListener 35 | 36 | 37 | 38 | javax.faces.PROJECT_STAGE 39 | Development 40 | 41 | 42 | 43 | javax.faces.FACELETS_REFRESH_PERIOD 44 | 0 45 | 46 | 47 | 48 | javax.faces.DEFAULT_SUFFIX 49 | .xhtml 50 | 51 | 52 | 53 | primefaces.THEME 54 | blitzer 55 | 56 | 57 | 58 | primefaces.FONT_AWESOME 59 | true 60 | 61 | 62 | 63 | javax.faces.FACELETS_SKIP_COMMENTS 64 | true 65 | 66 | 67 | 68 | javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE 69 | true 70 | 71 | 72 | 73 | woff2 74 | application/x-font-woff2 75 | 76 | 77 | 78 | 10 79 | 80 | 81 | 82 | 500 83 | /errorpages/error.jsf 84 | 85 | 86 | 87 | 404 88 | /errorpages/not-found.jsf 89 | 90 | 91 | 92 | javax.faces.application.ViewExpiredException 93 | /errorpages/view-expired.jsf 94 | 95 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/appl/beans.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/errorpages/error.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | #{messages['pageTitle.error']} 13 | 14 | 15 | 16 | 17 | 18 |

Chyba

19 | 20 | 21 | 22 | #{messages['error.loginPage']} 23 | 24 | #{messages['error.refresh']} 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/errorpages/lowPriviliges.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

#{messages['error.accessDenied']}

18 | 19 | Login page 20 | 21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/errorpages/notFound.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

404

19 | 20 | Login page 21 | 22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/errorpages/viewExpired.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

Sezení ukončeno.

18 | 19 | Login page 20 | 21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/include/header.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | #{messages['app.title']}#{not empty pageTitle ? ' - '.concat(pageTitle) : ''} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | 24 | 25 | 26 | 27 |
28 |
29 | 30 | 31 | 32 |
33 |
34 | 35 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/include/menu.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/index.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /deltaspike-hibernate-jsf/src/main/webapp/resources/css/default.css: -------------------------------------------------------------------------------- 1 | .ui-widget, .ui-widget .ui-widget { 2 | font-size: 90%; 3 | } 4 | 5 | .login-panel { 6 | position: absolute; 7 | top: 0; 8 | bottom: 0; 9 | left: 0; 10 | right: 0; 11 | display: flex; 12 | justify-content: space-around; 13 | align-items: center; 14 | flex-wrap: wrap; 15 | } -------------------------------------------------------------------------------- /gae/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .idea 3 | .project 4 | .settings/ 5 | target/ 6 | *.iml 7 | -------------------------------------------------------------------------------- /gae/.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 36 | 38 | -------------------------------------------------------------------------------- /gae/README.md: -------------------------------------------------------------------------------- 1 | [Issue 12426 - googleappengine - Passing JVM options to devserver - Google App Engine - Google Project Hosting](https://code.google.com/p/googleappengine/issues/detail?id=12426) 2 | 3 | [java.lang.NoClassDefFoundError: org/hotswap/agent/config/PluginManager - GAE devserver · Issue #99 · HotswapProjects/HotswapAgent](https://github.com/HotswapProjects/HotswapAgent/issues/99) 4 | 5 | How to test multi-module app? 6 | 7 | ``` 8 | git clone https://github.com/HotswapProjects/HotswapAgentExamples 9 | cd HotswapAgentExamples/gae 10 | mvn 11 | cd ear 12 | mvn 13 | ``` 14 | 15 | How to test normal (single/default module) app? 16 | ``` 17 | git clone https://github.com/HotswapProjects/HotswapAgentExamples 18 | cd HotswapAgentExamples/gae 19 | mvn 20 | cd gae-default 21 | mvn 22 | ``` 23 | -------------------------------------------------------------------------------- /gae/ear/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | com.google.developers 6 | gae-parent 7 | 0.0.1-SNAPSHOT 8 | 9 | 10 | 4.0.0 11 | 12 | gae-ear 13 | 14 | ear 15 | 16 | gae-ear 17 | 18 | http://developers.google.com/ 19 | 20 | 21 | 22 | 3.1.0 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-ear-plugin 32 | 2.10 33 | 34 | 5 35 | lib 36 | war 37 | 38 | true 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | maven-help-plugin 47 | 48 | 49 | org.codehaus.mojo 50 | versions-maven-plugin 51 | 52 | 53 | com.google.appengine 54 | appengine-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | 63 | 64 | 65 | local 66 | 67 | true 68 | 69 | 70 | appengine:devserver 71 | 72 | 73 | 74 | dev 75 | 76 | clean appengine:update 77 | 78 | 79 | 80 | beta 81 | 82 | clean appengine:update 83 | 84 | 85 | 86 | 87 | 88 | 89 | com.google.developers 90 | gae-default 91 | 0.0.1-SNAPSHOT 92 | war 93 | 94 | 95 | com.google.developers 96 | gae-backend 97 | 0.0.1-SNAPSHOT 98 | war 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /gae/ear/src/main/application/META-INF/appengine-application.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ${appengine.app.id} 6 | 7 | 8 | -------------------------------------------------------------------------------- /gae/ear/src/main/application/META-INF/application.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | GAE multi-module sample 6 | GAE multi-module sample 7 | 8 | 9 | gae-default-0.0.1-SNAPSHOT.war 10 | default 11 | 12 | 13 | 14 | 15 | gae-backend-0.0.1-SNAPSHOT.war 16 | backend 17 | 18 | 19 | lib 20 | 21 | -------------------------------------------------------------------------------- /gae/gae-backend/src/main/java/com/google/developers/BackendServlet.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.inject.Singleton; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServlet; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.io.IOException; 10 | 11 | /** 12 | * this is a batch process entry point 13 | *

14 | * Created by renfeng on 7/5/15. 15 | */ 16 | @Singleton 17 | public class BackendServlet extends HttpServlet { 18 | 19 | @Override 20 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 21 | /* 22 | * TODO long task 23 | */ 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /gae/gae-backend/src/main/java/com/google/developers/BackendServletModule.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.inject.servlet.ServletModule; 4 | 5 | public class BackendServletModule extends ServletModule { 6 | 7 | @Override 8 | protected void configureServlets() { 9 | serve("/cron/long-task").with(BackendServlet.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /gae/gae-backend/src/main/java/com/google/developers/BackendStartupListener.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | import com.google.inject.Stage; 6 | import com.google.inject.servlet.GuiceServletContextListener; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import javax.servlet.ServletContextEvent; 11 | 12 | public class BackendStartupListener extends GuiceServletContextListener { 13 | 14 | private static final Logger logger = LoggerFactory 15 | .getLogger(BackendStartupListener.class); 16 | 17 | private Injector injector; 18 | 19 | @Override 20 | public void contextInitialized(ServletContextEvent sce) { 21 | 22 | /* 23 | * TODO switch to production 24 | */ 25 | injector = Guice.createInjector(Stage.DEVELOPMENT, 26 | new DevelopersSharedModule(), 27 | new DevelopersSharedServletModule(), 28 | new BackendServletModule()); 29 | logger.info("created injector"); 30 | 31 | super.contextInitialized(sce); 32 | 33 | return; 34 | } 35 | 36 | @Override 37 | protected Injector getInjector() { 38 | return injector; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /gae/gae-backend/src/main/webapp/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ${appengine.app.id} 8 | 9 | 10 | 11 | ${appengine.module.backend} 12 | 13 | ${appengine.app.version} 14 | 15 | 16 | true 17 | 18 | 19 | B2 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ${appengine.module.instances} 29 | 30 | 1m 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /gae/gae-backend/src/main/webapp/WEB-INF/logging.properties: -------------------------------------------------------------------------------- 1 | # A default java.util.logging configuration. 2 | # (All App Engine logging is through java.util.logging by default). 3 | # 4 | # To use this configuration, copy it into your application's WEB-INF 5 | # folder and add the following to your appengine-web.xml: 6 | # 7 | # 8 | # 9 | # 10 | # 11 | 12 | # Set the default logging level for all loggers to WARNING 13 | .level = WARNING 14 | 15 | # Set up logging of HTTP requests and responses (uncomment "level" to show) 16 | #com.google.api.client.http.level = CONFIG 17 | com.google.api.client.http.level = FINE 18 | 19 | # TODO maven filtering 20 | # http://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html 21 | com.google..developers.level = ALL 22 | 23 | # http://www.slf4j.org/api/org/slf4j/bridge/SLF4JBridgeHandler.html 24 | # FINEST -> TRACE 25 | # FINER -> DEBUG 26 | # FINE -> DEBUG 27 | # INFO -> INFO 28 | # WARNING -> WARN 29 | # SEVERE -> ERROR 30 | -------------------------------------------------------------------------------- /gae/gae-backend/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | ${project.name} (${buildNumber}) 8 | 9 | 10 | 11 | 12 | guiceFilter 13 | ${guice.filter} 14 | 15 | 16 | guiceFilter 17 | /* 18 | 19 | 20 | 21 | com.google.developers.BackendStartupListener 22 | 23 | 24 | 25 | java.lang.Exception 26 | /api/5xx/ 27 | 28 | 29 | 30 | 31 | 32 | 33 | everything 34 | /* 35 | 36 | 37 | CONFIDENTIAL 38 | 39 | 40 | 41 | 42 | 43 | admin 44 | 45 | /admin/* 46 | 47 | 48 | /cron/* 49 | 50 | 51 | /_ah/queue/* 52 | 53 | 54 | /_ah/mail/* 55 | 56 | 57 | /_ah/bounce 58 | 59 | 60 | /appstats/* 61 | 62 | 63 | 64 | admin 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /gae/gae-backend/src/main/webapp/api/5xx/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" trimDirectiveWhitespaces="true" 2 | contentType="application/json; charset=UTF-8" pageEncoding="UTF-8" 3 | isErrorPage="true" 4 | import="com.google.inject.Injector,com.google.api.client.json.JsonFactory,com.google.api.client.json.JsonGenerator"%> 5 | <% 6 | Injector injector = (Injector) application 7 | .getAttribute("com.google.inject.Injector"); 8 | String m = pageContext.getException().getLocalizedMessage(); 9 | JsonFactory jsonFactory = injector.getInstance(JsonFactory.class); 10 | JsonGenerator generator = jsonFactory.createJsonGenerator(out); 11 | generator.writeStartObject(); 12 | generator.writeFieldName("error"); 13 | generator.writeString(m); 14 | generator.writeEndObject(); 15 | generator.flush(); 16 | %> -------------------------------------------------------------------------------- /gae/gae-backend/src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | hello -------------------------------------------------------------------------------- /gae/gae-default/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | gae-parent 6 | com.google.developers 7 | 0.0.1-SNAPSHOT 8 | 9 | 10 | 4.0.0 11 | 12 | gae-default 13 | 14 | war 15 | 16 | gae-default 17 | 18 | default module for gae 19 | 20 | https://developers.google.com/ 21 | 22 | 23 | 2.2.1 24 | 25 | 26 | 27 | 28 | +FrankR 29 | Frank R. 30 | renfeng.cn@gmail.com 31 | https://plus.google.com/+FrankR 32 | GDG Suzhou 33 | http://developers.dushu.hu 34 | +8 35 | 36 | Organizer 37 | 38 | 39 | 40 | 41 | 42 | scm:git:https://github.com/renfeng/HotswapAgentExamples/commit/${buildNumber} 43 | 44 | 45 | 46 | GDG Suzhou 47 | http://developers.dushu.hu/ 48 | 49 | 50 | 51 | ${project.build.directory}/${project.build.finalName}/WEB-INF/classes 52 | gae-default 53 | 54 | 55 | 56 | 57 | 58 | 59 | maven-help-plugin 60 | 61 | 62 | org.codehaus.mojo 63 | versions-maven-plugin 64 | 65 | 66 | org.codehaus.mojo 67 | buildnumber-maven-plugin 68 | 69 | 70 | maven-war-plugin 71 | 72 | 73 | com.google.appengine 74 | appengine-maven-plugin 75 | 76 | 77 | 78 | 79 | 80 | 81 | 84 | 85 | 86 | local 87 | 88 | true 89 | 90 | 91 | appengine:devserver 92 | 93 | 94 | 95 | dev 96 | 97 | clean install appengine:update 98 | 99 | 100 | 101 | beta 102 | 103 | clean install appengine:update 104 | 105 | 106 | 107 | 108 | 109 | 110 | com.google.developers 111 | gae-shared 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/java/com/google/developers/DefaultServletModule.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.api.server.spi.SystemServiceServlet; 4 | import com.google.inject.Singleton; 5 | import com.google.inject.servlet.ServletModule; 6 | import com.google.training.helloworld.HelloWorldEndpoints; 7 | 8 | import java.util.HashMap; 9 | 10 | public class DefaultServletModule extends ServletModule implements Path { 11 | 12 | @Override 13 | protected void configureServlets() { 14 | 15 | /* 16 | * /api/401/;jsessionid=37fycpy88nx7 17 | */ 18 | serve("/api/401/*").with(UnauthorizedServlet.class); 19 | 20 | /* 21 | * A servlet is a singleton, and is allowed to be registered only once. 22 | */ 23 | 24 | { 25 | HashMap params = new HashMap<>(); 26 | 27 | /* 28 | * comma delimited fqn of classes 29 | */ 30 | params.put("services", HelloWorldEndpoints.class.getCanonicalName()); 31 | 32 | serve("/_ah/spi/*").with(SystemServiceServlet.class, params); 33 | bind(SystemServiceServlet.class).in(Singleton.class); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/java/com/google/developers/DefaultStartupListener.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | import com.google.inject.Stage; 6 | import com.google.inject.servlet.GuiceServletContextListener; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import javax.servlet.ServletContextEvent; 11 | 12 | /** 13 | * loader for the web application 14 | * 15 | * @author renfeng 16 | */ 17 | public class DefaultStartupListener extends GuiceServletContextListener { 18 | 19 | private static final Logger logger = LoggerFactory 20 | .getLogger(DefaultStartupListener.class); 21 | 22 | /* 23 | * removed static keyword 24 | */ 25 | private Injector injector; 26 | 27 | /* 28 | * XXX for deferred task - which i would gave up because of lack of logging 29 | * output in eclipse junit, and unreadable payload on appengine.google.com 30 | */ 31 | 32 | @Override 33 | public void contextInitialized(ServletContextEvent sce) { 34 | 35 | /* 36 | * TODO switch to production 37 | */ 38 | logger.info("created injector"); 39 | injector = Guice.createInjector(Stage.DEVELOPMENT, 40 | new DevelopersSharedModule(), 41 | new DevelopersSharedServletModule(), 42 | new DefaultServletModule()); 43 | 44 | super.contextInitialized(sce); 45 | } 46 | 47 | @Override 48 | protected Injector getInjector() { 49 | return injector; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /gae/gae-default/src/main/java/com/google/developers/Path.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | public interface Path { 4 | 5 | String EVENTS_API_URL = "/api/events/"; 6 | 7 | String CHECK_IN_PAGE_URL = "/authenticated/check-in/"; 8 | String TICKET_PAGE_URL = "/authenticated/ticket/"; 9 | String CAMPAIGN_PAGE_URL = "/authenticated/campaign/"; 10 | String EVENT_BRITE_PAGE_URL = "/authenticated/eventbrite/"; 11 | 12 | String OAUTH2ENTRY_PAGE_URL = "/authenticated/oauth2entry"; 13 | String OAUTH2CALLBACK_PAGE_URL = "/authenticated/oauth2callback"; 14 | String OAUTH2REVOKE_PAGE_URL = "/authenticated/oauth2revoke"; 15 | } 16 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/java/com/google/developers/UnauthorizedServlet.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.api.client.json.JsonFactory; 4 | import com.google.api.client.json.JsonGenerator; 5 | import com.google.inject.Inject; 6 | import com.google.inject.Singleton; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | 14 | @Singleton 15 | public class UnauthorizedServlet extends HttpServlet { 16 | 17 | private final JsonFactory jsonFactory; 18 | 19 | @Inject 20 | public UnauthorizedServlet(JsonFactory jsonFactory) { 21 | this.jsonFactory = jsonFactory; 22 | } 23 | 24 | protected void unauthorized(HttpServletRequest req, HttpServletResponse resp) 25 | throws IOException { 26 | 27 | String userAgent = req.getHeader("User-Agent"); 28 | 29 | resp.setHeader("Content-Type", "text/javascript"); 30 | resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 31 | 32 | JsonGenerator generator = jsonFactory.createJsonGenerator(resp.getWriter()); 33 | generator.writeStartObject(); 34 | generator.writeFieldName("error"); 35 | generator.writeString("Login required."); 36 | generator.writeFieldName("q"); 37 | generator.writeString(req.getQueryString()); 38 | generator.writeFieldName("agent"); 39 | generator.writeString(userAgent); 40 | generator.writeEndObject(); 41 | generator.flush(); 42 | } 43 | 44 | @Override 45 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 46 | throws ServletException, IOException { 47 | unauthorized(req, resp); 48 | } 49 | 50 | @Override 51 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) 52 | throws ServletException, IOException { 53 | unauthorized(req, resp); 54 | } 55 | } -------------------------------------------------------------------------------- /gae/gae-default/src/main/java/com/google/training/helloworld/Constants.java: -------------------------------------------------------------------------------- 1 | package com.google.training.helloworld; 2 | 3 | import com.google.api.server.spi.Constant; 4 | 5 | /** 6 | * Contains the client IDs and scopes for allowed clients consuming your API. 7 | */ 8 | public class Constants { 9 | public static final String WEB_CLIENT_ID = "replace this with your web client ID"; 10 | public static final String ANDROID_CLIENT_ID = "replace this with your Android client ID"; 11 | public static final String IOS_CLIENT_ID = "replace this with your iOS client ID"; 12 | public static final String ANDROID_AUDIENCE = WEB_CLIENT_ID; 13 | public static final String API_EXPLORER_CLIENT_ID = Constant.API_EXPLORER_CLIENT_ID; 14 | public static final String EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email"; 15 | } 16 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/java/com/google/training/helloworld/HelloClass.java: -------------------------------------------------------------------------------- 1 | package com.google.training.helloworld; 2 | 3 | public class HelloClass { 4 | public String message = "Hello World"; 5 | 6 | public HelloClass () { 7 | } 8 | 9 | public HelloClass (String name) { 10 | this.message = "Hello " + name + "!"; 11 | } 12 | 13 | public String getMessage() { 14 | return message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/java/com/google/training/helloworld/HelloWorldEndpoints.java: -------------------------------------------------------------------------------- 1 | package com.google.training.helloworld; 2 | 3 | import com.google.api.server.spi.config.Api; 4 | import com.google.api.server.spi.config.ApiMethod; 5 | import com.google.api.server.spi.config.ApiMethod.HttpMethod; 6 | import com.google.api.server.spi.config.Named; 7 | 8 | /** 9 | * Defines endpoint functions APIs. 10 | */ 11 | @Api(name = "helloworldendpoints", version = "v1", 12 | scopes = {Constants.EMAIL_SCOPE}, 13 | clientIds = {Constants.WEB_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID}, 14 | description = "API for hello world endpoints.") 15 | public class HelloWorldEndpoints { 16 | 17 | // Declare this method as a method available externally through Endpoints 18 | @ApiMethod(name = "sayHello", path = "sayHello", 19 | httpMethod = HttpMethod.GET) 20 | public HelloClass sayHello() { 21 | return new HelloClass(); 22 | } 23 | 24 | // Declare this method as a method available externally through Endpoints 25 | @ApiMethod(name = "sayHelloByName", path = "sayHelloByName", 26 | httpMethod = HttpMethod.GET) 27 | public HelloClass sayHelloByName(@Named("name") String name) { 28 | return new HelloClass(name); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/webapp/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ${appengine.app.id} 8 | 9 | 10 | 11 | 12 | ${appengine.app.version} 13 | 14 | 15 | true 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | true 30 | 31 | 32 | 33 | 34 | 35 | channel_presence 36 | 37 | mail 38 | mail_bounce 39 | 40 | xmpp_message 41 | xmpp_presence 42 | xmpp_subscribe 43 | xmpp_error 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/webapp/WEB-INF/cron.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | 15 | /cron/long-task 16 | 17 | 21 | 22 | every 3 hours 23 | 24 | 25 | 28 | ${appengine.module.backend} 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/webapp/WEB-INF/logging.properties: -------------------------------------------------------------------------------- 1 | # A default java.util.logging configuration. 2 | # (All App Engine logging is through java.util.logging by default). 3 | # 4 | # To use this configuration, copy it into your application's WEB-INF 5 | # folder and add the following to your appengine-web.xml: 6 | # 7 | # 8 | # 9 | # 10 | # 11 | 12 | # Set the default logging level for all loggers to WARNING 13 | .level = WARNING 14 | 15 | # Set up logging of HTTP requests and responses (uncomment "level" to show) 16 | #com.google.api.client.http.level = CONFIG 17 | com.google.api.client.http.level = FINE 18 | 19 | # TODO maven filtering 20 | # http://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html 21 | com.google.developers.level = ALL 22 | 23 | # http://www.slf4j.org/api/org/slf4j/bridge/SLF4JBridgeHandler.html 24 | # FINEST -> TRACE 25 | # FINER -> DEBUG 26 | # FINE -> DEBUG 27 | # INFO -> INFO 28 | # WARNING -> WARN 29 | # SEVERE -> ERROR 30 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | ${project.name} (${buildNumber}) 8 | 9 | 10 | appengine.app.id 11 | ${appengine.app.id} 12 | 13 | 14 | 15 | guiceFilter 16 | com.google.inject.servlet.GuiceFilter 17 | 18 | 19 | guiceFilter 20 | /* 21 | 22 | 23 | 24 | 25 | 26 | 27 | com.google.developers.DefaultStartupListener 28 | 29 | 30 | 31 | java.lang.Exception 32 | /api/5xx/ 33 | 34 | 35 | 36 | 37 | 48 | 49 | 50 | 51 | admin 52 | 53 | /admin/* 54 | 55 | 56 | /cron/* 57 | 58 | 59 | /task/* 60 | 61 | 62 | /_ah/mail/* 63 | 64 | 65 | /_ah/bounce 66 | 67 | 68 | 69 | admin 70 | 71 | 72 | 73 | 74 | 75 | authenticated 76 | /authenticated/* 77 | 78 | 84 | 85 | * 86 | 87 | 88 | 89 | 90 | gdg-index.html 91 | index.html 92 | index.jsp 93 | 94 | 95 | -------------------------------------------------------------------------------- /gae/gae-default/src/main/webapp/api/5xx/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" trimDirectiveWhitespaces="true" 2 | contentType="application/json; charset=UTF-8" pageEncoding="UTF-8" 3 | isErrorPage="true" 4 | import="com.google.inject.Injector,com.google.api.client.json.JsonFactory,com.google.api.client.json.JsonGenerator"%> 5 | <% 6 | Injector injector = (Injector) application 7 | .getAttribute("com.google.inject.Injector"); 8 | String m = pageContext.getException().getLocalizedMessage(); 9 | JsonFactory jsonFactory = injector.getInstance(JsonFactory.class); 10 | JsonGenerator generator = jsonFactory.createJsonGenerator(out); 11 | generator.writeStartObject(); 12 | generator.writeFieldName("error"); 13 | generator.writeString(m); 14 | generator.writeEndObject(); 15 | generator.flush(); 16 | %> -------------------------------------------------------------------------------- /gae/shared/src/main/java/com/google/developers/DevelopersSharedFilter.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.appengine.api.modules.ModulesService; 4 | import com.google.appengine.api.modules.ModulesServiceFactory; 5 | import com.google.inject.servlet.GuiceFilter; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import javax.servlet.FilterChain; 10 | import javax.servlet.ServletException; 11 | import javax.servlet.ServletRequest; 12 | import javax.servlet.ServletResponse; 13 | import java.io.IOException; 14 | 15 | public class DevelopersSharedFilter extends GuiceFilter { 16 | 17 | // private static final Logger logger = LoggerFactory 18 | // .getLogger(DevelopersSharedFilter.class); 19 | 20 | @Override 21 | public void doFilter(ServletRequest servletRequest, 22 | ServletResponse servletResponse, FilterChain filterChain) 23 | throws IOException, ServletException { 24 | 25 | ModulesService modulesApi = ModulesServiceFactory.getModulesService(); 26 | String instanceHostname = modulesApi.getCurrentInstanceId() + "." 27 | + modulesApi.getCurrentVersion() + "." 28 | + modulesApi.getCurrentModule(); 29 | Logger logger = LoggerFactory.getLogger(instanceHostname); 30 | logger.info(logger.getName()); 31 | 32 | logger.info("begin guice filter"); 33 | super.doFilter(servletRequest, servletResponse, filterChain); 34 | logger.info("end guice filter"); 35 | 36 | return; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /gae/shared/src/main/java/com/google/developers/DevelopersSharedModule.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.api.client.extensions.appengine.datastore.AppEngineDataStoreFactory; 4 | import com.google.api.client.http.HttpTransport; 5 | import com.google.api.client.http.javanet.NetHttpTransport; 6 | import com.google.api.client.json.JsonFactory; 7 | import com.google.api.client.json.jackson2.JacksonFactory; 8 | import com.google.api.client.util.store.DataStoreFactory; 9 | import com.google.inject.Binder; 10 | import com.google.inject.Module; 11 | import com.google.inject.Singleton; 12 | 13 | import java.text.DateFormat; 14 | import java.text.SimpleDateFormat; 15 | import java.util.ResourceBundle; 16 | 17 | public class DevelopersSharedModule implements Module { 18 | 19 | public static final String REFRESH_TOKEN = getMessage("refreshToken"); 20 | public static final String CLIENT_ID = getMessage("clientId"); 21 | public static final String CLIENT_SECRET = getMessage("clientSecret"); 22 | 23 | @Override 24 | public void configure(Binder binder) { 25 | 26 | // binder.bind(HttpTransport.class).toInstance(new UrlFetchTransport()); 27 | binder.bind(HttpTransport.class).toInstance(new NetHttpTransport()); 28 | 29 | /* 30 | * TODO HH? 31 | */ 32 | binder.bind(DateFormat.class).toInstance( 33 | new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'Z'")); 34 | 35 | binder.bind(JsonFactory.class).toInstance( 36 | JacksonFactory.getDefaultInstance()); 37 | 38 | /* 39 | * Global instance of the {@link DataStoreFactory}. The best practice is 40 | * to make it a single globally shared instance across your application. 41 | */ 42 | binder.bind(DataStoreFactory.class).toInstance( 43 | AppEngineDataStoreFactory.getDefaultInstance()); 44 | binder.bind(AppEngineDataStoreFactory.class).in(Singleton.class); 45 | } 46 | 47 | public static String getMessage(String key) { 48 | /* 49 | * http://docs.oracle.com/javase/tutorial/i18n/intro/steps.html 50 | */ 51 | ResourceBundle bundle = ResourceBundle.getBundle("message"); 52 | return bundle.getString(key); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /gae/shared/src/main/java/com/google/developers/DevelopersSharedServletModule.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.inject.servlet.ServletModule; 4 | 5 | public class DevelopersSharedServletModule extends ServletModule { 6 | 7 | @Override 8 | protected void configureServlets() { 9 | 10 | /* 11 | * TODO /_ah/stop (not documented?) 12 | */ 13 | serve("/_ah/start").with(ModuleStartServlet.class); 14 | 15 | // serve("/appstats/*").with(AppstatsServlet.class); 16 | // bind(AppstatsServlet.class).in(Singleton.class); 17 | 18 | /* 19 | * url handlers in non-default module require a workaround 20 | * https://code.google.com/p/googleappengine/issues/detail?id=9859 21 | */ 22 | 23 | // filter("/*").through(AppstatsFilter.class); 24 | // filter("/*").through(ObjectifyFilter.class); 25 | // bind(ObjectifyFilter.class).in(Singleton.class); 26 | 27 | return; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /gae/shared/src/main/java/com/google/developers/ModuleStartServlet.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | import com.google.appengine.api.LifecycleManager; 4 | import com.google.inject.Inject; 5 | import com.google.inject.Singleton; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | 15 | @Singleton 16 | public class ModuleStartServlet extends HttpServlet implements 17 | LifecycleManager.ShutdownHook { 18 | 19 | private static final Logger logger = LoggerFactory 20 | .getLogger(ModuleStartServlet.class); 21 | 22 | @Inject 23 | public ModuleStartServlet() { 24 | } 25 | 26 | @Override 27 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 28 | throws ServletException, IOException { 29 | 30 | logger.info("module start"); 31 | LifecycleManager.getInstance().setShutdownHook(this); 32 | // ModulesService modulesApi = 33 | // ModulesServiceFactory.getModulesService(); 34 | // if ("0".equals(modulesApi.getCurrentInstanceId())) { 35 | // 36 | // logger.info("module start"); 37 | // LifecycleManager.getInstance().setShutdownHook(this); 38 | // 39 | // } 40 | 41 | return; 42 | } 43 | 44 | @Override 45 | public void shutdown() { 46 | 47 | logger.info("module shutdown"); 48 | // LifecycleManager.getInstance().interruptAllRequests(); 49 | 50 | return; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /gae/shared/src/main/java/com/google/developers/PropertiesContant.java: -------------------------------------------------------------------------------- 1 | package com.google.developers; 2 | 3 | /** 4 | * Created by renfeng on 7/20/15. 5 | */ 6 | public interface PropertiesContant { 7 | 8 | String KEY_VALUE_DELIMITER = "="; 9 | String COMMENT_LINE_START = "#"; 10 | } 11 | -------------------------------------------------------------------------------- /hotswap-agent-examples-servlet-parent/README.md: -------------------------------------------------------------------------------- 1 | Setup of application servers 2 | ============================ 3 | 4 | ### Jetty9 5 | 6 | 7 | ### JBoss7 8 | 9 | 10 | ### Tomcat7 11 | -------------------------------------------------------------------------------- /jersey1/README.md: -------------------------------------------------------------------------------- 1 | Run this sample with: 2 | > 'mvn clean package jetty:run -Pjetty9-run' 3 | 4 | Then open: 5 | > http://localhost:8080/rest/jersey1/hello -------------------------------------------------------------------------------- /jersey1/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hotswap-agent-examples-aggregator 7 | org.hotswapagent 8 | 1.4.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | jersey1 13 | 14 | 15 | 16 | com.sun.jersey 17 | jersey-server 18 | 1.18.3 19 | 20 | 21 | com.sun.jersey 22 | jersey-servlet 23 | 1.18.3 24 | 25 | 26 | org.eclipse.jetty 27 | jetty-server 28 | 9.4.17.v20190418 29 | provided 30 | 31 | 32 | 33 | 34 | 35 | jetty9-run 36 | 37 | 38 | 39 | org.eclipse.jetty 40 | jetty-maven-plugin 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /jersey1/src/main/java/org/hotswap/agent/exemple/jersey/Jersey1Resource.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.exemple.jersey; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | 6 | /** 7 | * Jersey resource. 8 | */ 9 | @Path("/jersey1") 10 | public class Jersey1Resource { 11 | 12 | /** 13 | * Access this resource throw an HTTP request on /rest/jersey1/hello URI. 14 | * 15 | * @return 'Hello from Jersey1!' string 16 | */ 17 | @GET 18 | @Path("/hello") 19 | public String hello() { 20 | return "Hello from Jersey 1!"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jersey1/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | jersey 6 | com.sun.jersey.spi.container.servlet.ServletContainer 7 | 8 | com.sun.jersey.config.property.packages 9 | org.hotswap.agent.exemple.jersey 10 | 11 | 12 | 13 | jersey 14 | /rest/* 15 | 16 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/README.md: -------------------------------------------------------------------------------- 1 | run main method in Jersey2App 2 | 3 | Then open: 4 | > http://localhost:8080/hello 5 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hotswap-agent-examples-aggregator 7 | org.hotswapagent 8 | 1.4.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | jersey2-jetty-hk2 13 | 14 | 15 | 16 | maven2-repository.java.net 17 | Java.net Repository for Maven 18 | https://maven.java.net/content/groups/public/ 19 | default 20 | 21 | 22 | 23 | 24 | 25 | 26 | javax.servlet 27 | javax.servlet-api 28 | 3.1.0 29 | 30 | 31 | 32 | org.glassfish.jersey.core 33 | jersey-server 34 | 2.25 35 | 36 | 37 | 38 | org.glassfish.jersey.containers 39 | jersey-container-servlet-core 40 | 2.25 41 | 42 | 43 | 44 | org.eclipse.jetty 45 | jetty-server 46 | 9.4.17.v20190418 47 | 48 | 49 | 50 | org.eclipse.jetty 51 | jetty-servlet 52 | 9.3.20.v20170531 53 | 54 | 55 | 56 | 57 | org.glassfish.hk2 58 | hk2-metadata-generator 59 | 2.4.0 60 | 61 | 62 | 63 | 64 | 65 | 66 | jetty9-run 67 | 68 | 69 | 70 | org.eclipse.jetty 71 | jetty-maven-plugin 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/java/org/hotswap/agent/example/jersey/Jersey2App.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.jersey; 2 | 3 | import org.eclipse.jetty.server.Server; 4 | import org.eclipse.jetty.servlet.ServletContextHandler; 5 | import org.eclipse.jetty.servlet.ServletHolder; 6 | import org.glassfish.jersey.servlet.ServletContainer; 7 | 8 | public class Jersey2App { 9 | public static void main(String[] args) throws Exception { 10 | 11 | MyApplication config = new MyApplication(); 12 | ServletHolder jerseyServlet 13 | = new ServletHolder(new ServletContainer(config)); 14 | 15 | Server server = new Server(8080); 16 | ServletContextHandler context 17 | = new ServletContextHandler(server, "/"); 18 | context.addServlet(jerseyServlet, "/*"); 19 | 20 | server.start(); 21 | server.join(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/java/org/hotswap/agent/example/jersey/Jersey2Resource.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.jersey; 2 | 3 | import javax.inject.Inject; 4 | import javax.ws.rs.GET; 5 | import javax.ws.rs.Path; 6 | 7 | /** 8 | * Jersey resource. 9 | */ 10 | @Path("/") 11 | public class Jersey2Resource { 12 | 13 | @Inject 14 | TestService testService; 15 | 16 | @Inject 17 | TestService2 testService2; 18 | 19 | /** 20 | * Access this resource throw an HTTP request on /rest/jersey1/hello URI. 21 | * 22 | * @return 'Hello from Jersey1!' string 23 | */ 24 | @GET 25 | @Path("/hello") 26 | public String hello() { 27 | return testService2.sayHello(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/java/org/hotswap/agent/example/jersey/MyApplication.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.jersey; 2 | 3 | import org.glassfish.jersey.server.ResourceConfig; 4 | 5 | public class MyApplication extends ResourceConfig { 6 | public MyApplication() { 7 | register(new MyApplicationBinder()); 8 | packages(true, "org.hotswap.agent.example.jersey"); 9 | }} 10 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/java/org/hotswap/agent/example/jersey/MyApplicationBinder.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.jersey; 2 | 3 | import org.glassfish.hk2.utilities.binding.AbstractBinder; 4 | 5 | public class MyApplicationBinder extends AbstractBinder { 6 | @Override 7 | protected void configure() { 8 | bind(TestService.class).to(TestService.class); 9 | bind(TestService2.class).to(TestService2.class); 10 | bind(TestService3.class).to(TestService3.class); 11 | } 12 | } -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/java/org/hotswap/agent/example/jersey/TestService.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.jersey; 2 | 3 | import org.jvnet.hk2.annotations.Service; 4 | 5 | @Service 6 | public class TestService { 7 | public String sayHello() { 8 | return "hello"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/java/org/hotswap/agent/example/jersey/TestService2.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.jersey; 2 | 3 | import javax.inject.Inject; 4 | 5 | import org.jvnet.hk2.annotations.Service; 6 | 7 | @Service 8 | public class TestService2 { 9 | 10 | // @Inject 11 | // TestService3 service3; 12 | 13 | public String sayHello() { 14 | return "hello2"; 15 | // return service3.sayHello(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/java/org/hotswap/agent/example/jersey/TestService3.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.jersey; 2 | 3 | import org.jvnet.hk2.annotations.Service; 4 | 5 | @Service 6 | public class TestService3 { 7 | public String sayHello() { 8 | return "hello3"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /jersey2-jetty-hk2/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Jersey2App 6 | org.glassfish.jersey.servlet.ServletContainer 7 | 8 | jersey.config.server.provider.packages 9 | org.hotswap.agent.exemple.jersey 10 | 11 | 12 | 13 | Jersey2App 14 | /rest/* 15 | 16 | -------------------------------------------------------------------------------- /jersey2/README.md: -------------------------------------------------------------------------------- 1 | Run this sample with: 2 | > 'mvn clean package jetty:run -Pjetty9-run' 3 | 4 | Then open: 5 | > http://localhost:8080/rest/jersey2/hello -------------------------------------------------------------------------------- /jersey2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | hotswap-agent-examples-aggregator 7 | org.hotswapagent 8 | 1.4.2-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | jersey2 13 | 14 | 15 | 16 | org.glassfish.jersey.core 17 | jersey-server 18 | 2.14 19 | 20 | 21 | org.glassfish.jersey.containers 22 | jersey-container-servlet-core 23 | 2.14 24 | 25 | 26 | org.eclipse.jetty 27 | jetty-server 28 | 9.4.17.v20190418 29 | provided 30 | 31 | 32 | 33 | 34 | 35 | jetty9-run 36 | 37 | 38 | 39 | org.eclipse.jetty 40 | jetty-maven-plugin 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /jersey2/src/main/java/org/hotswap/agent/exemple/jersey/Jersey2Resource.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.exemple.jersey; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | 6 | /** 7 | * Jersey resource. 8 | */ 9 | @Path("/jersey2") 10 | public class Jersey2Resource { 11 | 12 | /** 13 | * Access this resource throw an HTTP request on /rest/jersey1/hello URI. 14 | * 15 | * @return 'Hello from Jersey1!' string 16 | */ 17 | @GET 18 | @Path("/hello") 19 | public String hello() { 20 | return "Hello from Jersey 2!"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jersey2/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Jersey2App 6 | org.glassfish.jersey.servlet.ServletContainer 7 | 8 | jersey.config.server.provider.packages 9 | org.hotswap.agent.exemple.jersey 10 | 11 | 12 | 13 | Jersey2App 14 | /rest/* 15 | 16 | -------------------------------------------------------------------------------- /plain-java/README.md: -------------------------------------------------------------------------------- 1 | Plain java example 2 | ================== 3 | 4 | Example of application setup with plain Java (without any framework) and core HotswapAgent features. 5 | 6 | Unit tests include: 7 | 8 | * extraClasspath property - load classes and resources from alternative location 9 | * watchResources property - load a resource from alternative location only after it is modified 10 | * autoHotswap property - change class definition at runtime after .class file is modified 11 | 12 | Maven-antrun is used to compile/copy files from java-extra, java-hotswap and resources-extra folders into 13 | target folders to simulate extraClasspath/watchResources directories. 14 | 15 | This example depends only on hotswap-agent-core (runs with `-XXaltjvm=dcevm -javaagent:hotswap-agent-core.jar`). 16 | 17 | ### extraClasspath 18 | 19 | 1. Class `org.hotswap.agent.example.HelloWorld` is located in both src/main/java and src/main/java-extra, 20 | on project assembly (`mvn package`) it becomes target/classes and target/extra. 21 | 1. The agent is configured to add extra classpath directory target/extra 22 | (hotswap-agent.properties contains property `extraClasspath=target/extra`). 23 | 1. Class definition from target/extra should hence precede definition from target/classes 24 | 1. HelloWorld.hello() should return "Hello World Extra". 25 | 26 | Similarly for resources - directory resources/extra becomes target/extra and file test.properties should 27 | be loaded from target/extra instead of target/classes. 28 | 29 | ### watchResources 30 | Some resources may be modified during assembly process from src/main/resources to target/classes (e.g. maven resource 31 | filtering) and hence it is not possible to use extraClasspath to watch directly src/main/resources. Use instead 32 | watchProperties to return resource from the directory after a change only. It is up the user to modify only resources 33 | without filtering. 34 | 35 | In this example target/classes/testWatch.properties contains "Hello World" and target/watch/testWatch.properties 36 | contains "This should never happen - before change contents should be read from target/classes." As the string 37 | suggests, although the hotswap-agent.properties setup contains `watchResources=target/watch, original file 38 | should be returned. Only after the test "manually" replaces target/watch/testWatch.properties with 39 | target/watch/testWatchReplace.properties (and hence IS modified), new value "Hello World Watch" is returned. 40 | 41 | ### autoHotswap 42 | If hotswap-agent.properties setup contains `autoHotswap=true`, all class files on classpath (original + 43 | extraClasspath) are watched for changes (note that only plain .class files on local filesystem and not in JAR can 44 | be watched). If the filesystem triggers a change, JVM hotswap is automatically launched for the file. 45 | 46 | HelloWorldHotswapTest loads the class `org.hotswap.agent.example.HelloWorldHotswap` bytecode, renames 47 | it to HelloWorld and replaces HelloWorldHotswap.class file in target/classes. This triggers the change 48 | and new class version is introduced. HelloWorld.hello() will then return new value "Hello World Hotswap". 49 | -------------------------------------------------------------------------------- /plain-java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.hotswapagent 9 | hotswap-agent-examples-aggregator 10 | 1.4.2-SNAPSHOT 11 | 12 | 13 | org.hotswap.examples 14 | plain-java 15 | 16 | 17 | 18 | 19 | org.apache.maven.plugins 20 | maven-antrun-plugin 21 | 1.7 22 | 23 | 24 | generate-sources 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | run 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.hotswapagent 67 | hotswap-agent-core 68 | ${project.version} 69 | provided 70 | 71 | 72 | 73 | junit 74 | junit 75 | 4.12 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /plain-java/run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # simple script to run test 3 | # this should be replaced by build sever in the future 4 | 5 | # fail with first failed test 6 | set -e 7 | 8 | # run clean install (with all integration tests) 9 | function test { 10 | echo "Running tests for plain Java" 11 | mvn clean install 12 | } 13 | 14 | test -------------------------------------------------------------------------------- /plain-java/src/main/java-extra/org/hotswap/agent/example/HelloAnnotation.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Test annotation. 10 | */ 11 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface HelloAnnotation { 14 | public String value() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /plain-java/src/main/java-extra/org/hotswap/agent/example/HelloInterface.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Interface to test anonymous classes. 5 | */ 6 | public interface HelloInterface { 7 | String hello(String dummy); 8 | } 9 | -------------------------------------------------------------------------------- /plain-java/src/main/java-extra/org/hotswap/agent/example/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class. 5 | */ 6 | @HelloAnnotation("hello extra") 7 | public class HelloWorld { 8 | public static String hello() { 9 | return "Hello World Extra"; 10 | } 11 | 12 | @HelloAnnotation("hello extra") 13 | public String hello(@HelloAnnotation("par extra") String par) { 14 | return "Hello Extra " + par; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /plain-java/src/main/java-extra/org/hotswap/agent/example/HelloWorldHotswap.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class to be replaced by hotswap. 5 | */ 6 | @HelloAnnotation("hello extra") 7 | public class HelloWorldHotswap { 8 | public static String hello() { 9 | return "Hello World Extra"; 10 | } 11 | 12 | // create new annonymous class before HelloInterface. HotswapperPlugin should kick in. 13 | public void dummy() { 14 | new Cloneable() {}; 15 | } 16 | 17 | @HelloAnnotation("hello extra") 18 | public String hello(final @HelloAnnotation("par extra") String par) { 19 | HelloInterface anonymous = new HelloInterface() { 20 | @Override 21 | public String hello(String dummy) { 22 | return "Hello Extra " + par; 23 | } 24 | }; 25 | return anonymous.hello(null); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /plain-java/src/main/java-hotswap/org/hotswap/agent/example/HelloAnnotation.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Test annotation. 10 | */ 11 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface HelloAnnotation { 14 | public String value() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /plain-java/src/main/java-hotswap/org/hotswap/agent/example/HelloInterface.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Interface to test anonymous classes. 5 | */ 6 | public interface HelloInterface { 7 | String hello(String dummy); 8 | } 9 | -------------------------------------------------------------------------------- /plain-java/src/main/java-hotswap/org/hotswap/agent/example/HelloWorldHotswap.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import java.lang.Cloneable; 4 | 5 | /** 6 | * Hello world class. 7 | */ 8 | @HelloAnnotation("hello hotswap") 9 | public class HelloWorldHotswap { 10 | public static String hello() { 11 | return helloPrivate(); 12 | } 13 | 14 | @HelloAnnotation("hello hotswap") 15 | public String hello(final @HelloAnnotation("par hotswap") String par) { 16 | HelloInterface anonymous = new HelloInterface() { 17 | @Override 18 | @HelloAnnotation("hello hotswap") 19 | public String hello(final @HelloAnnotation("par hotswap") String dummy) { 20 | return "Hello Hotswap " + par; 21 | } 22 | }; 23 | return anonymous.hello(null); 24 | } 25 | 26 | // chage ordering of annonymous classes. HotswapperPlugin should kick in. 27 | public void dummy() { 28 | new Cloneable() {}; 29 | } 30 | 31 | private static String helloPrivate() { 32 | return "Hello World Hotswap"; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /plain-java/src/main/java/org/hotswap/agent/example/HelloAnnotation.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Test annotation. 10 | */ 11 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface HelloAnnotation { 14 | public String value() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /plain-java/src/main/java/org/hotswap/agent/example/HelloInterface.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Interface to test anonymous classes. 5 | */ 6 | public interface HelloInterface { 7 | String hello(String dummy); 8 | } 9 | -------------------------------------------------------------------------------- /plain-java/src/main/java/org/hotswap/agent/example/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class to be replaced by extraClasspath. 5 | */ 6 | @HelloAnnotation("hello") 7 | public class HelloWorld { 8 | public static String hello() { 9 | return "Hello World"; 10 | } 11 | 12 | @HelloAnnotation("hello") 13 | public String hello(@HelloAnnotation("par") String par) { 14 | return "Hello " + par; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /plain-java/src/main/java/org/hotswap/agent/example/HelloWorldHotswap.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class to be replaced by hotswap. 5 | */ 6 | @HelloAnnotation("hello") 7 | public class HelloWorldHotswap { 8 | public static String hello() { 9 | return "Hello World"; 10 | } 11 | 12 | // create new annonymous class before HelloInterface. HotswapperPlugin should kick in. 13 | public void dummy() { 14 | new Cloneable() {}; 15 | } 16 | 17 | @HelloAnnotation("hello") 18 | public String hello(final @HelloAnnotation("par") String par) { 19 | HelloInterface anonymous = new HelloInterface() { 20 | @Override 21 | public String hello(String dummy) { 22 | return "Hello " + par; 23 | } 24 | }; 25 | return anonymous.hello(null); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /plain-java/src/main/resources-extra/test.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World Extra -------------------------------------------------------------------------------- /plain-java/src/main/resources-watch/testWatch.properties: -------------------------------------------------------------------------------- 1 | hello=This should never happen - before change contents should be read from target/classes. -------------------------------------------------------------------------------- /plain-java/src/main/resources-watch/testWatchReplace.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World Watch -------------------------------------------------------------------------------- /plain-java/src/main/resources/hotswap-agent.properties: -------------------------------------------------------------------------------- 1 | extraClasspath=target/extra 2 | watchResources=target/watch 3 | autoHotswap=true 4 | 5 | LOGGER=debug 6 | -------------------------------------------------------------------------------- /plain-java/src/main/resources/test.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World -------------------------------------------------------------------------------- /plain-java/src/main/resources/testWatch.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World -------------------------------------------------------------------------------- /plain-java/src/test/java/org/hotswap/agent/example/HelloWorldTest.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import org.hotswap.agent.util.test.WaitHelper; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import java.io.IOException; 8 | import java.lang.reflect.Method; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | import java.nio.file.StandardCopyOption; 13 | import java.util.ResourceBundle; 14 | 15 | /** 16 | * Test loading classes and resources according to extraClasspath property. 17 | */ 18 | public class HelloWorldTest { 19 | @Test 20 | public void extraClassPathClassStaticTest() { 21 | Assert.assertEquals("Assert class from target/extra is used.", "Hello World Extra", HelloWorld.hello()); 22 | } 23 | 24 | @Test 25 | public void extraClassPathClassTest() { 26 | Assert.assertEquals("Assert class from target/extra is used.", "Hello Extra par", new HelloWorld().hello("par")); 27 | } 28 | 29 | @Test 30 | public void extraClassPathAnnotationTest() throws Exception { 31 | Class clazz = HelloWorld.class; 32 | 33 | HelloAnnotation clazzAnnotation = (HelloAnnotation) clazz.getAnnotation(HelloAnnotation.class); 34 | Assert.assertEquals("hello extra", clazzAnnotation.value()); 35 | 36 | Method helloMethod = clazz.getDeclaredMethod("hello", String.class); 37 | HelloAnnotation methodAnnotation = (HelloAnnotation) helloMethod.getAnnotation(HelloAnnotation.class); 38 | Assert.assertEquals("hello extra", methodAnnotation.value()); 39 | HelloAnnotation paramAnnotation = (HelloAnnotation) helloMethod.getParameterAnnotations()[0][0]; 40 | Assert.assertEquals("par extra", paramAnnotation.value()); 41 | } 42 | 43 | @Test 44 | public void extraClassPathResourceTest() { 45 | String hello = ResourceBundle.getBundle("test").getString("hello"); 46 | Assert.assertEquals("Assert resource from target/extra is used.", "Hello World Extra", hello); 47 | } 48 | 49 | @Test 50 | public void extraClassPathWatchResourceTest() throws IOException, InterruptedException { 51 | // check before change 52 | String hello = ResourceBundle.getBundle("testWatch").getString("hello"); 53 | Assert.assertEquals("Assert original resource from target/classes is used.", "Hello World", hello); 54 | 55 | // replace the file in watched dir 56 | Path source = Paths.get("target/watch/testWatchReplace.properties"); 57 | Path target = Paths.get("target/watch/testWatch.properties"); 58 | Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); 59 | Thread.sleep(2000); 60 | 61 | // wait for the hotswap 62 | boolean result = WaitHelper.waitForCommand(new WaitHelper.Command() { 63 | @Override 64 | public boolean result() throws Exception { 65 | ResourceBundle.clearCache(); 66 | String hello = ResourceBundle.getBundle("testWatch").getString("hello"); 67 | return "Hello World Watch".equals(hello); 68 | } 69 | }); 70 | 71 | // check that agentexamples works 72 | Assert.assertTrue("Assert modified target/watch/testWatch.properties is used.", result); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /plain-servlet/README.md: -------------------------------------------------------------------------------- 1 | Plain servlet example 2 | ===================== 3 | 4 | Example of application setup inside servlet containser / J2EE application server (without any 5 | additional framework) and HotswapAgent including all plugins. 6 | 7 | Unit tests include: 8 | 9 | * extraClasspath property - load classes and resources from alternative location 10 | * watchResources property - load a resource from alternative location only after it is modified 11 | * autoHotswap property - change class definition at runtime after .class file is modified 12 | 13 | Maven-antrun is used to compile/copy files from java-extra, java-hotswap and resources-extra folders into 14 | target folders to simulate extraClasspath/watchResources directories. 15 | 16 | This example does pretty the same as plain-java, but checks the value as HTTP response strings. 17 | See plain-java/README.md for description of used hotswap-agent.properties. 18 | 19 | This example depends on hotswap-agent.jar (runs with `-XXaltjvm=dcevm -javaagent:hotswap-agent.jar`) to 20 | check that all plugins are 21 | 22 | Application server support 23 | ========================== 24 | See run-test.sh for list of tested servers. 25 | -------------------------------------------------------------------------------- /plain-servlet/run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # simple script to run various containers setup 3 | # this should be replaced by build sever in the future 4 | 5 | # fail with first failed test 6 | set -e 7 | 8 | # run clean install (with all integration tests) 9 | function test { 10 | echo "Running with container $1" 11 | mvn -Dhotswapagent.jar=$2 clean verify -P $1 12 | } 13 | 14 | if [ -z "$HOT_SWAP_AGENT"]; then 15 | echo "HOT_SWAP_AGENT is not set, pls. specify where the HotSwapAgent jar location" 16 | exit 1 17 | fi 18 | 19 | # Older versions of Jetty works as well, but are configured only with embedded configuration, which does not support jvmargs 20 | # it cannot be launched automatically (set -javaagent). To launch the test, set MAVEN_OPTS and run manually. 21 | test jetty7 ${HOT_SWAP_AGENT} 22 | test jetty8 ${HOT_SWAP_AGENT} 23 | test jetty9 ${HOT_SWAP_AGENT} 24 | 25 | # Tomcat should be Ok. 26 | test tomcat6 ${HOT_SWAP_AGENT} 27 | test tomcat7 ${HOT_SWAP_AGENT} 28 | test tomcat8 ${HOT_SWAP_AGENT} 29 | test tomcat9 ${HOT_SWAP_AGENT} 30 | 31 | # Almost all hotswap agent properties do not work :-( 32 | #test jboss5x 33 | # JBoss 8 is OSGI based and catalina WebappLoader is not used anymore 34 | #test jboss8 35 | 36 | # GlassFish is based on OSGI, need to first resolve 37 | #test glassfish3 38 | #test glassfish4 39 | 40 | # Need to download manually and setup, did not try yet 41 | # test weblogic12x -------------------------------------------------------------------------------- /plain-servlet/src/main/java-extra/org/hotswap/agent/example/HelloWorldBaseServlet.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import javax.servlet.*; 4 | import java.io.IOException; 5 | import java.util.ResourceBundle; 6 | 7 | /** 8 | * Base servlet with template method and several resources. 9 | */ 10 | public abstract class HelloWorldBaseServlet implements Servlet { 11 | 12 | /** 13 | * Template method to return Hello World text modifications. 14 | */ 15 | protected abstract String getHello(); 16 | 17 | /** 18 | * Return basic resource, it should be handled from target/extra directory. 19 | */ 20 | protected String getHelloResource() { 21 | ResourceBundle.clearCache(); 22 | return ResourceBundle.getBundle("test").getString("hello"); 23 | } 24 | 25 | /** 26 | * Return content of testWatch.properties. It should be resolved to target/classes until 27 | * resources-watch/testWatch.properties is modified, then it should return the new value. 28 | */ 29 | protected String getHelloResourceWatch() { 30 | ResourceBundle.clearCache(); 31 | return ResourceBundle.getBundle("testWatch").getString("hello"); 32 | } 33 | 34 | @Override 35 | public void init(ServletConfig config) throws ServletException { 36 | 37 | } 38 | 39 | @Override 40 | public ServletConfig getServletConfig() { 41 | return null; 42 | } 43 | 44 | @Override 45 | public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { 46 | String param = req.getParameter("method"); 47 | if ("helloResource".equals(param)) { 48 | res.getWriter().write(getHelloResource()); 49 | } else if ("helloResourceWatch".equals(param)) { 50 | res.getWriter().write(getHelloResourceWatch()); 51 | } else { 52 | // default hello world 53 | res.getWriter().write(getHello()); 54 | } 55 | } 56 | 57 | 58 | @Override 59 | public String getServletInfo() { 60 | return null; 61 | } 62 | 63 | @Override 64 | public void destroy() { 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /plain-servlet/src/main/java-extra/org/hotswap/agent/example/HelloWorldServlet.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Simple Hello World - this should override the default. 5 | */ 6 | public class HelloWorldServlet extends HelloWorldBaseServlet { 7 | @Override 8 | protected String getHello() { 9 | return "Hello World Extra"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /plain-servlet/src/main/java-extra/org/hotswap/agent/example/HelloWorldServletHotswap.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class to be replaced by hotswap. 5 | */ 6 | public class HelloWorldServletHotswap extends HelloWorldBaseServlet { 7 | @Override 8 | protected String getHello() { 9 | return "Hello World Extra"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /plain-servlet/src/main/java-hotswap/org/hotswap/agent/example/HelloWorldBaseServlet.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import javax.servlet.*; 4 | import java.io.IOException; 5 | import java.util.ResourceBundle; 6 | 7 | /** 8 | * Base servlet with template method and several resources. 9 | */ 10 | public abstract class HelloWorldBaseServlet implements Servlet { 11 | 12 | /** 13 | * Template method to return Hello World text modifications. 14 | */ 15 | protected abstract String getHello(); 16 | 17 | /** 18 | * Return basic resource, it should be handled from target/extra directory. 19 | */ 20 | protected String getHelloResource() { 21 | ResourceBundle.clearCache(); 22 | return ResourceBundle.getBundle("test").getString("hello"); 23 | } 24 | 25 | /** 26 | * Return content of testWatch.properties. It should be resolved to target/classes until 27 | * resources-watch/testWatch.properties is modified, then it should return the new value. 28 | */ 29 | protected String getHelloResourceWatch() { 30 | ResourceBundle.clearCache(); 31 | return ResourceBundle.getBundle("testWatch").getString("hello"); 32 | } 33 | 34 | @Override 35 | public void init(ServletConfig config) throws ServletException { 36 | 37 | } 38 | 39 | @Override 40 | public ServletConfig getServletConfig() { 41 | return null; 42 | } 43 | 44 | @Override 45 | public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { 46 | String param = req.getParameter("method"); 47 | if ("helloResource".equals(param)) { 48 | res.getWriter().write(getHelloResource()); 49 | } else if ("helloResourceWatch".equals(param)) { 50 | res.getWriter().write(getHelloResourceWatch()); 51 | } else { 52 | // default hello world 53 | res.getWriter().write(getHello()); 54 | } 55 | } 56 | 57 | 58 | @Override 59 | public String getServletInfo() { 60 | return null; 61 | } 62 | 63 | @Override 64 | public void destroy() { 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /plain-servlet/src/main/java-hotswap/org/hotswap/agent/example/HelloWorldServletHotswap.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class - this will be used to hotswap the package in extra. 5 | */ 6 | public class HelloWorldServletHotswap extends HelloWorldBaseServlet { 7 | @Override 8 | protected String getHello() { 9 | return "Hello World Hotswap"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /plain-servlet/src/main/java/org/hotswap/agent/example/HelloWorldBaseServlet.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import javax.servlet.*; 4 | import java.io.IOException; 5 | import java.util.ResourceBundle; 6 | 7 | /** 8 | * Base servlet with template method and several resources. 9 | */ 10 | public abstract class HelloWorldBaseServlet implements Servlet { 11 | 12 | protected HelloWorldBaseServlet() { 13 | } 14 | 15 | /** 16 | * Template method to return Hello World text modifications. 17 | */ 18 | protected abstract String getHello(); 19 | 20 | /** 21 | * Return basic resource, it should be handled from target/extra directory. 22 | */ 23 | protected String getHelloResource() { 24 | ResourceBundle.clearCache(); 25 | return ResourceBundle.getBundle("test").getString("hello"); 26 | } 27 | 28 | /** 29 | * Return content of testWatch.properties. It should be resolved to target/classes until 30 | * resources-watch/testWatch.properties is modified, then it should return the new value. 31 | */ 32 | protected String getHelloResourceWatch() { 33 | ResourceBundle.clearCache(); 34 | return ResourceBundle.getBundle("testWatch").getString("hello"); 35 | } 36 | 37 | @Override 38 | public void init(ServletConfig config) throws ServletException { 39 | 40 | } 41 | 42 | @Override 43 | public ServletConfig getServletConfig() { 44 | return null; 45 | } 46 | 47 | @Override 48 | public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { 49 | String param = req.getParameter("method"); 50 | if ("helloResource".equals(param)) { 51 | res.getWriter().write(getHelloResource()); 52 | } else if ("helloResourceWatch".equals(param)) { 53 | res.getWriter().write(getHelloResourceWatch()); 54 | } else { 55 | // default hello world 56 | res.getWriter().write(getHello()); 57 | } 58 | } 59 | 60 | 61 | @Override 62 | public String getServletInfo() { 63 | return null; 64 | } 65 | 66 | @Override 67 | public void destroy() { 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /plain-servlet/src/main/java/org/hotswap/agent/example/HelloWorldServlet.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Simple Hello World to be replaced by extra 5 | */ 6 | public class HelloWorldServlet extends HelloWorldBaseServlet { 7 | 8 | @Override 9 | protected String getHello() { 10 | return "Hello World"; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /plain-servlet/src/main/java/org/hotswap/agent/example/HelloWorldServletHotswap.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class to be replaced by hotswap. 5 | */ 6 | public class HelloWorldServletHotswap extends HelloWorldBaseServlet { 7 | @Override 8 | protected String getHello() { 9 | return "Hello Worlda"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /plain-servlet/src/main/resources-extra/test.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World Extra -------------------------------------------------------------------------------- /plain-servlet/src/main/resources-watch/testWatch.properties: -------------------------------------------------------------------------------- 1 | hello=This should never happen - before change contents should be read from target/classes. -------------------------------------------------------------------------------- /plain-servlet/src/main/resources-watch/testWatchReplace.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World Watch -------------------------------------------------------------------------------- /plain-servlet/src/main/resources/hotswap-agent.properties: -------------------------------------------------------------------------------- 1 | # ${basedir} will be replaced by Maven true.. option 2 | extraClasspath=${basedir}/target/extra 3 | watchResources=${basedir}/target/watch 4 | 5 | # webapp-extra will be copied into target directory during maven build. 6 | # for manual tests from IDE change this to ${basedir}/src/main/webapp-extra 7 | webappDir=${basedir}/target/webapp-extra 8 | 9 | LOGGER=debug 10 | -------------------------------------------------------------------------------- /plain-servlet/src/main/resources/test.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World -------------------------------------------------------------------------------- /plain-servlet/src/main/resources/testWatch.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World -------------------------------------------------------------------------------- /plain-servlet/src/main/webapp-extra/hello.jsp: -------------------------------------------------------------------------------- 1 | Hello World Extra -------------------------------------------------------------------------------- /plain-servlet/src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /plain-servlet/src/main/webapp/WEB-INF/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | /plain-servlet 4 | 5 | -------------------------------------------------------------------------------- /plain-servlet/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | HelloWorld 6 | org.hotswap.agent.example.HelloWorldServlet 7 | 8 | 9 | HelloWorld 10 | /hello 11 | 12 | 13 | 14 | HelloWorldHotswap 15 | org.hotswap.agent.example.HelloWorldServletHotswap 16 | 17 | 18 | HelloWorldHotswap 19 | /helloHotswap 20 | 21 | 22 | -------------------------------------------------------------------------------- /plain-servlet/src/main/webapp/hello.jsp: -------------------------------------------------------------------------------- 1 | Hello World -------------------------------------------------------------------------------- /plain-servlet/src/test/java/org/hotswap/agent/example/HelloWorldServletHotswapIT.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import org.apache.http.HttpResponse; 4 | import org.apache.http.client.methods.HttpGet; 5 | import org.apache.http.client.methods.HttpUriRequest; 6 | import org.apache.http.impl.client.HttpClientBuilder; 7 | import org.apache.http.util.EntityUtils; 8 | import org.hotswap.agent.util.test.WaitHelper; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | import java.io.IOException; 13 | import java.nio.file.Files; 14 | import java.nio.file.Path; 15 | import java.nio.file.Paths; 16 | import java.nio.file.StandardCopyOption; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | 20 | /** 21 | * Test autoHotswap of classes after change 22 | */ 23 | public class HelloWorldServletHotswapIT { 24 | 25 | @Test 26 | public void extraClassPathHotswapTest() throws IOException, InterruptedException { 27 | final HttpUriRequest request = new HttpGet(HelloWorldServletIT.ENDPOINT + "helloHotswap"); 28 | 29 | // replace the class file in extraClasspath (classloader looks into this directory) 30 | // autoHotswap should discover this change and reload the class 31 | String helloWorldFile = HelloWorldServletHotswap.class.getName().replace(".", "/") + ".class"; 32 | Path source = Paths.get("target/hotswap/" + helloWorldFile); 33 | Path target = Paths.get("target/extra/" + helloWorldFile); 34 | Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); 35 | 36 | // wait for the hotswap 37 | boolean result = WaitHelper.waitForCommand(new WaitHelper.Command() { 38 | @Override 39 | public boolean result() throws Exception { 40 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 41 | String result = EntityUtils.toString(httpResponse.getEntity()); 42 | 43 | return "Hello World Hotswap".equals(result); 44 | } 45 | }, 2000); 46 | 47 | // check that agentexamples works 48 | Assert.assertTrue("Assert hotswapped class in extra is used.", result); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /plain-servlet/src/test/java/org/hotswap/agent/example/HelloWorldServletIT.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import org.apache.http.HttpResponse; 4 | import org.apache.http.HttpStatus; 5 | import org.apache.http.client.methods.HttpGet; 6 | import org.apache.http.client.methods.HttpUriRequest; 7 | import org.apache.http.impl.client.HttpClientBuilder; 8 | import org.apache.http.util.EntityUtils; 9 | import org.hotswap.agent.util.test.WaitHelper; 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | 13 | import java.io.IOException; 14 | import java.nio.file.Files; 15 | import java.nio.file.Path; 16 | import java.nio.file.Paths; 17 | import java.nio.file.StandardCopyOption; 18 | import java.util.ResourceBundle; 19 | 20 | import static org.junit.Assert.assertEquals; 21 | 22 | public class HelloWorldServletIT { 23 | public static final String ENDPOINT = "http://localhost:8080/plain-servlet/"; 24 | 25 | @Test 26 | public void testUpAndRunning() throws Exception { 27 | HttpUriRequest request = new HttpGet(ENDPOINT + "hello"); 28 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 29 | 30 | assertEquals(HttpStatus.SC_OK, httpResponse.getStatusLine().getStatusCode()); 31 | } 32 | 33 | @Test 34 | public void testHello() throws Exception { 35 | HttpUriRequest request = new HttpGet(ENDPOINT + "hello"); 36 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 37 | 38 | assertEquals("Hello World Extra", EntityUtils.toString(httpResponse.getEntity())); 39 | } 40 | 41 | @Test 42 | public void testHelloResourceExtraPath() throws Exception { 43 | HttpUriRequest request = new HttpGet(ENDPOINT + "hello?method=helloResource"); 44 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 45 | 46 | assertEquals("Hello World Extra", EntityUtils.toString(httpResponse.getEntity())); 47 | } 48 | 49 | @Test 50 | public void extraClassPathWatchResourceTest() throws IOException, InterruptedException { 51 | final HttpUriRequest request = new HttpGet(ENDPOINT + "hello?method=helloResourceWatch"); 52 | 53 | // check before change 54 | String hello = ResourceBundle.getBundle("testWatch").getString("hello"); 55 | Assert.assertEquals("Assert original resource from target/classes is used.", "Hello World", hello); 56 | 57 | // replace the file in watched dir 58 | Path source = Paths.get("target/watch/testWatchReplace.properties"); 59 | Path target = Paths.get("target/watch/testWatch.properties"); 60 | Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); 61 | 62 | // wait for the hotswap 63 | boolean result = WaitHelper.waitForCommand(new WaitHelper.Command() { 64 | @Override 65 | public boolean result() throws Exception { 66 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 67 | 68 | String hello = EntityUtils.toString(httpResponse.getEntity()); 69 | System.err.println(hello); 70 | return "Hello World Watch".equals(hello); 71 | } 72 | }, 4000); 73 | 74 | // check that agentexamples works 75 | Assert.assertTrue("Assert modified target/watch/testWatch.properties is used.", result); 76 | } 77 | } -------------------------------------------------------------------------------- /plain-servlet/src/test/java/org/hotswap/agent/example/HelloWorldServletJspIT.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | import org.apache.http.HttpResponse; 4 | import org.apache.http.HttpStatus; 5 | import org.apache.http.client.methods.HttpGet; 6 | import org.apache.http.client.methods.HttpUriRequest; 7 | import org.apache.http.impl.client.HttpClientBuilder; 8 | import org.apache.http.util.EntityUtils; 9 | import org.junit.Test; 10 | 11 | import java.io.IOException; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | /** 16 | * Test webapp property. 17 | */ 18 | public class HelloWorldServletJspIT { 19 | 20 | @Test 21 | public void extraWebappDirHotswapTest() throws IOException, InterruptedException { 22 | final HttpUriRequest request = new HttpGet(HelloWorldServletIT.ENDPOINT + "hello.jsp"); 23 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 24 | 25 | assertEquals(HttpStatus.SC_OK, httpResponse.getStatusLine().getStatusCode()); 26 | 27 | assertEquals("Hello World Extra", EntityUtils.toString(httpResponse.getEntity())); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.hotswapagent 6 | resteasy-parent 7 | 1.4.2-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | resteasy-managment 12 | war 13 | 14 | resteasy-managment 15 | 16 | 17 | 18 | 19 | ${project.groupId} 20 | resteasy-model 21 | 1.4.2-SNAPSHOT 22 | 23 | 24 | 25 | org.json 26 | json 27 | 28 | 29 | 30 | javax.servlet 31 | javax.servlet-api 32 | 33 | 34 | 35 | commons-dbutils 36 | commons-dbutils 37 | 38 | 39 | javax 40 | javaee-web-api 41 | 42 | 43 | 44 | org.jboss.resteasy 45 | resteasy-jackson-provider 46 | 3.0.9.Final 47 | test 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | src/main/resources 56 | true 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/src/main/java/org/hotswap/agent/example/service/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.service; 2 | import java.util.Collections; 3 | import java.util.Set; 4 | import javax.ws.rs.ApplicationPath; 5 | import javax.ws.rs.core.Application; 6 | 7 | @ApplicationPath("/Services") 8 | public class BaseApplication extends Application { 9 | 10 | @Override 11 | public Set> getClasses() { 12 | return Collections.emptySet(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/src/main/java/org/hotswap/agent/example/service/PersonManagement.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.service; 2 | 3 | import java.util.Date; 4 | import javax.ws.rs.GET; 5 | import javax.ws.rs.Path; 6 | import javax.ws.rs.Produces; 7 | import javax.ws.rs.core.MediaType; 8 | import org.hotswap.agent.example.model.Person; 9 | 10 | /** 11 | * 12 | * @author christoforosl 13 | */ 14 | @Path("/PersonManagement") 15 | @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8") 16 | public class PersonManagement { 17 | 18 | @GET 19 | @Path("Person") 20 | public Person getPerson() { 21 | 22 | final org.hotswap.agent.example.model.Person ret = new Person(); 23 | ret.setBirthDate(new Date()); 24 | ret.setFirstName("hotswap ZZZ"); 25 | ret.setLastName("test"); 26 | ret.setPersonId(1000L); 27 | 28 | return ret; 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/src/main/webapp/WEB-INF/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | /resteasy-test 4 | 5 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 30 5 | 6 | 7 | 8 | resteasy-test 9 | 10 | resteasy.scan 11 | false 12 | 13 | 14 | resteasy.resources 15 | org.hotswap.agent.example.service.PersonManagement 16 | 17 | 18 | 19 | resteasy-servlet 20 | 21 | org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher 22 | 23 | 24 | 25 | resteasy-servlet 26 | /* 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | RestEasy Services 7 | 8 | 9 |

RestEasy Services

10 | 11 | 12 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/src/main/webapp/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | /HotSwapAgentTest 4 | 5 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-managment/src/test/java/org/hotswap/agent/example/test/JSONIgnorePropTest.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.test; 2 | 3 | import java.util.Date; 4 | 5 | import org.codehaus.jackson.map.ObjectMapper; 6 | import org.hotswap.agent.example.model.Person; 7 | import org.junit.Test; 8 | 9 | /** 10 | * 11 | * @author christoforosl 12 | */ 13 | public class JSONIgnorePropTest { 14 | 15 | @Test 16 | public void ignoredProperties() throws Exception { 17 | 18 | ObjectMapper mapper = new ObjectMapper(); 19 | 20 | Person e = new Person(); 21 | e.setBirthDate(new Date()); 22 | 23 | String s = mapper.writeValueAsString(e); 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-model/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.hotswapagent 8 | resteasy-parent 9 | 1.4.2-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | resteasy-model 14 | jar 15 | 16 | JDK_1.7 17 | 18 | resteasy-model 19 | Project containing all Domain Model objects 20 | -------------------------------------------------------------------------------- /resteasy-app/resteasy-model/src/main/java/org/hotswap/agent/example/model/Person.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.model; 2 | 3 | import org.codehaus.jackson.annotate.JsonProperty; 4 | 5 | public class Person extends PersonModelBase { 6 | 7 | @JsonProperty 8 | public String getP2() { 9 | return "P2!!"; 10 | } 11 | public String getFullName() { 12 | 13 | return this.getFirstName()+ " - " + this.getLastName(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # simple script to run all tests and all versions. It fails with first failure 3 | # this should be replaced by build sever in the future 4 | 5 | # fail with first failed test 6 | set -e 7 | 8 | function test { 9 | echo "Running with Java $1" 10 | export JAVA_HOME=$1 11 | 12 | echo "Resolved version: " `"$JAVA_HOME/bin/java" -version` 13 | 14 | mvn -Dhotswapagent.jar=$2 clean package 15 | 16 | # run tests 17 | cd plain-java; ./run-tests.sh; cd .. 18 | cd spring-boot; ./run-tests.sh; cd .. 19 | 20 | # TODO 21 | # custom-plugin 22 | # cd plain-servlet; ./run-tests.sh; cd .. 23 | # spring-hibernate 24 | # ... 25 | } 26 | 27 | if [ -z "$JAVA_HOME" ]; then 28 | echo "JAVA_HOME is not set" 29 | exit 1 30 | fi 31 | 32 | if [ -z "$HOT_SWAP_AGENT"]; then 33 | echo "HOT_SWAP_AGENT is not set, pls. specify where the HotSwapAgent jar location" 34 | exit 1 35 | fi 36 | 37 | test $JAVA_HOME $HOT_SWAP_AGENT 38 | -------------------------------------------------------------------------------- /spring-boot-kotlin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-slim 2 | 3 | MAINTAINER Jiří Bubník 4 | 5 | VOLUME /tmp 6 | WORKDIR /app/tsm 7 | ADD target/tsm-dms*.jar /app/tsm/tsm-dms.jar 8 | EXPOSE 8082/tcp 9 | ENTRYPOINT ["java","-XX:MaxRAM=300m","-Djava.security.egd=file:/dev/./urandom","-jar","tsm-dms.jar", "--spring.profiles.active=kubernetes"] 10 | -------------------------------------------------------------------------------- /spring-boot-kotlin/README.md: -------------------------------------------------------------------------------- 1 | # Example applicatin of Spring Boot REST API with Kotlin 2 | -------------------------------------------------------------------------------- /spring-boot-kotlin/src/main/java/org/hotswap/agent/example/springbootkotlin/ExampleApi.kt: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springbootkotlin 2 | 3 | import org.springframework.web.bind.annotation.* 4 | 5 | @RestController 6 | @RequestMapping(value = ["/example"]) 7 | class ExampleApi { 8 | 9 | @GetMapping("/{test}") 10 | @ResponseBody 11 | fun test(@PathVariable test: String) : String = "hello " + test 12 | } 13 | -------------------------------------------------------------------------------- /spring-boot-kotlin/src/main/java/org/hotswap/agent/example/springbootkotlin/ExampleApplication.kt: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springbootkotlin 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | 6 | @SpringBootApplication 7 | class ExampleApplication 8 | 9 | fun main(args: Array) { 10 | runApplication(*args) 11 | } 12 | -------------------------------------------------------------------------------- /spring-boot-kotlin/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotswapProjects/HotswapAgentExamples/6b313ca4e24087f5a05d46f63ddece51cf1e9418/spring-boot-kotlin/src/main/resources/application.yml -------------------------------------------------------------------------------- /spring-boot-kotlin/src/test/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotswapProjects/HotswapAgentExamples/6b313ca4e24087f5a05d46f63ddece51cf1e9418/spring-boot-kotlin/src/test/resources/application.yml -------------------------------------------------------------------------------- /spring-boot/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | hotswap-agent-examples-aggregator 6 | org.hotswapagent 7 | 1.4.2-SNAPSHOT 8 | 9 | 10 | 4.0.0 11 | 12 | org.hotswapagent.example 13 | spring-boot 14 | 0.0.1-SNAPSHOT 15 | jar 16 | 17 | spring-boot 18 | Example project for Spring Boot 19 | 20 | 21 | UTF-8 22 | UTF-8 23 | 1.8 24 | 2.7.11 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-dependencies 32 | ${spring.boot.version} 33 | pom 34 | import 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-web 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-webflux 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-starter-test 58 | test 59 | 60 | 61 | 62 | org.hotswapagent 63 | hotswap-agent-spring-plugin 64 | 1.4.2-SNAPSHOT 65 | test 66 | 67 | 68 | 69 | junit 70 | junit 71 | 72 | 73 | 74 | 75 | 76 | 77 | org.springframework.boot 78 | spring-boot-maven-plugin 79 | ${spring.boot.version} 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /spring-boot/src/main/java/org/hotswap/agent/example/springboot/HotswapSpringBoot.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springboot; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.context.annotation.FilterType; 7 | 8 | @SpringBootApplication 9 | @ComponentScan(excludeFilters={ 10 | @ComponentScan.Filter(type= FilterType.REGEX, pattern=".*2$")}) 11 | public class HotswapSpringBoot { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(HotswapSpringBoot.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /spring-boot/src/main/java/org/hotswap/agent/example/springboot/TestPojo.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springboot; 2 | 3 | public class TestPojo { 4 | public int version() { return 0; } 5 | } 6 | -------------------------------------------------------------------------------- /spring-boot/src/main/java/org/hotswap/agent/example/springboot/TestPojo2.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springboot; 2 | 3 | public class TestPojo2 { 4 | public int version() { return 1; } 5 | 6 | public void test() { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /spring-boot/src/main/java/org/hotswap/agent/example/springboot/TestRest.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springboot; 2 | 3 | import org.springframework.web.bind.annotation.*; 4 | 5 | @RestController 6 | public class TestRest { 7 | @GetMapping(value = "/hello") 8 | @ResponseBody 9 | public String hello() { 10 | return "hello"; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring-boot/src/main/java/org/hotswap/agent/example/springboot/TestRest2.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springboot; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.ResponseBody; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | public class TestRest2 { 10 | @GetMapping(value = "/hello2") 11 | @ResponseBody 12 | public String hello() { 13 | return "hello2"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /spring-boot/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotswapProjects/HotswapAgentExamples/6b313ca4e24087f5a05d46f63ddece51cf1e9418/spring-boot/src/main/resources/application.properties -------------------------------------------------------------------------------- /spring-boot/src/main/resources/hotswap-agent.properties: -------------------------------------------------------------------------------- 1 | LOGGER=debug 2 | -------------------------------------------------------------------------------- /spring-boot/src/test/java/org/hotswap/agent/example/springboot/BasicSpringBootTest.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springboot; 2 | 3 | import org.hotswap.agent.plugin.hotswapper.HotSwapper; 4 | import org.hotswap.agent.plugin.spring.scanner.ClassPathBeanDefinitionScannerAgent; 5 | import org.hotswap.agent.util.test.WaitHelper; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.context.ApplicationContext; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | import static org.junit.Assert.assertNotNull; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | @RunWith(SpringRunner.class) 18 | @SpringBootTest 19 | public class BasicSpringBootTest { 20 | @Autowired 21 | ApplicationContext applicationContext; 22 | 23 | @Test 24 | public void contextLoads() { 25 | assertNotNull(applicationContext); 26 | } 27 | 28 | @Test 29 | public void addMethodDidNotChangeSpringBeanNames() throws Exception { 30 | TestPojo test = applicationContext.getAutowireCapableBeanFactory().createBean(TestPojo.class); 31 | assertEquals(0, applicationContext.getBeanNamesForType(TestPojo.class).length); 32 | 33 | swapClasses(TestPojo.class, TestPojo2.class); 34 | 35 | 36 | assertEquals(0, applicationContext.getBeanNamesForType(TestPojo.class).length); 37 | } 38 | 39 | 40 | public static void swapClasses(Class original, Class swap) throws Exception { 41 | ClassPathBeanDefinitionScannerAgent.reloadFlag = true; 42 | HotSwapper.swapClasses(original, swap.getName()); 43 | assertTrue(WaitHelper.waitForCommand(new WaitHelper.Command() { 44 | @Override 45 | public boolean result() throws Exception { 46 | return !ClassPathBeanDefinitionScannerAgent.reloadFlag; 47 | } 48 | })); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /spring-boot/src/test/java/org/hotswap/agent/example/springboot/RestTest.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.springboot; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | import org.springframework.test.web.reactive.server.WebTestClient; 9 | 10 | import static org.hotswap.agent.example.springboot.BasicSpringBootTest.swapClasses; 11 | 12 | @RunWith(SpringRunner.class) 13 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 14 | public class RestTest { 15 | @Autowired 16 | private WebTestClient webClient; 17 | 18 | @Test 19 | public void exampleTest() throws Exception { 20 | this.webClient.get().uri("/hello").exchange().expectStatus().isOk() 21 | .expectBody(String.class).isEqualTo("hello"); 22 | 23 | swapClasses(TestRest.class, TestRest2.class); 24 | 25 | this.webClient.get().uri("/hello").exchange().expectStatus().is4xxClientError(); 26 | 27 | this.webClient.get().uri("/hello2").exchange().expectStatus().isOk() 28 | .expectBody(String.class).isEqualTo("hello2"); 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /spring-hibernate/README.md: -------------------------------------------------------------------------------- 1 | Spring + Hibernate + Spring MVC 2 | =============================== 3 | 4 | Example of application setup with: 5 | * Spring 35.3.26 6 | * Hibernate Entity Manager 5.4.33 7 | * Spring WebMVC 8 | 9 | You need to specify java startup properties with dcevm and javaagent: 10 |
java -javaagent:HotswapAgent.jar
11 | 12 | It is preconfigured with maven jetty plugin, run: 13 | * mvn clean package 14 | * mvn jetty:run 15 | * launch web browser on http://localhost:8080/ 16 | 17 | The application is preconfigured for automatic hotswap deployment (see autoHotswap property in hotswap-agent.properties). 18 | If you specify java startup parameters, all changes to class file will be automatically reloaded: 19 |
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
20 | If you start the application in debug mode, autoHotswap will be disabled and you should use IDE hotswap feature instead. 21 | 22 | To enable debug of Hotswap reload on JVM level, add -Xlog:redefine+class*=debug java startup parameter: 23 |
java -javaagent:..\HotswapAgent\target\HotswapAgent.jar -Xlog:redefine+class*=debug
24 | -------------------------------------------------------------------------------- /spring-hibernate/runtime/data/agent-test.hsqldb.lck: -------------------------------------------------------------------------------- 1 | HSQLLOCKFQ2 H -------------------------------------------------------------------------------- /spring-hibernate/runtime/data/agent-test.hsqldb.properties: -------------------------------------------------------------------------------- 1 | #HSQL Database Engine 2.2.8 2 | #Sat May 31 09:32:53 CEST 2014 3 | version=2.2.8 4 | modified=yes 5 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/java-extra/org/hotswap/agent/examples/plain/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class. 5 | */ 6 | public class HelloWorld { 7 | public static String hello() { 8 | return "Hello World Extra"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/java-extra/org/hotswap/agent/examples/plain/HelloWorldHotswap.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example; 2 | 3 | /** 4 | * Hello world class to be replaced by hotswap. 5 | */ 6 | public class HelloWorldHotswap { 7 | public static String hello() { 8 | return "Hello World Extra"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/java-hotswap/org/hotswap/agent/examples/service/TestRepository.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.service; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | /** 6 | * Hello world repository to be replaced by hotswap 7 | */ 8 | @Repository 9 | public class TestRepository { 10 | public String helloWorld() { 11 | return "Hello world Hotswap"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/java/org/hotswap/agent/example/model/TestEntity.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.model; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | 7 | /** 8 | * Test entity 9 | */ 10 | @Entity 11 | public class TestEntity { 12 | @Id 13 | @GeneratedValue 14 | private Long id; 15 | 16 | private String name; 17 | 18 | //@Transient 19 | private String value; 20 | 21 | public TestEntity() { 22 | // Uncomment and reorder to test AnonymousClassPatchPlugin 23 | // new Exception() {}; 24 | // new Serializable() {}; 25 | // new Cloneable() {}; 26 | } 27 | 28 | public TestEntity(String value) { 29 | } 30 | 31 | 32 | public Long getId() { 33 | return id; 34 | } 35 | 36 | public void setId(Long id) { 37 | this.id = id; 38 | } 39 | 40 | public String getValue() { 41 | return value; 42 | } 43 | 44 | public void setValue(String value) { 45 | this.value = value; 46 | } 47 | 48 | public String getName() { 49 | return name; 50 | } 51 | 52 | public void setName(String name) { 53 | this.name = name; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "TestEntity{" + 59 | "id=" + id + 60 | ", name='" + name + '\'' + 61 | ", value='" + value + '\'' + 62 | '}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/java/org/hotswap/agent/example/mvc/IndexController.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.mvc; 2 | 3 | import org.hotswap.agent.example.model.TestEntity; 4 | import org.hotswap.agent.example.service.TestEntityService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.ModelMap; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.Writer; 14 | 15 | /** 16 | * Simple Spring MVC controller. 17 | * 18 | * Note, that Spring MVC is not fully supported for reload (e.g. endpoint mapping). 19 | */ 20 | @Controller 21 | @RequestMapping 22 | public class IndexController { 23 | 24 | @Autowired 25 | TestEntityService testEntityService; 26 | 27 | @Autowired 28 | ApplicationContext applicationContext; 29 | 30 | @RequestMapping("/hello") 31 | public void helloWorld(Writer writer) throws IOException { 32 | writer.write("Hello World"); 33 | } 34 | 35 | @RequestMapping("/helloRepository") 36 | public void helloWorldRepository(Writer writer) throws IOException { 37 | // applicationContext.getBean instead of autowired service, because Spring MVC bean is sometimes 38 | // not reloaded - will be part of Spring MVC plugin 39 | writer.write(applicationContext.getBean(TestEntityService.class).helloWorld3()); 40 | } 41 | 42 | /** 43 | * Experiment with entities and Hibernate. 44 | */ 45 | @RequestMapping("/hibernate") 46 | public String printHello(ModelMap model) { 47 | TestEntity a = new TestEntity("Hello world"); 48 | testEntityService.addTestEntity(a); 49 | model.addAttribute("entities", testEntityService.loadTestEntities()); 50 | return "test"; 51 | } 52 | 53 | /** 54 | * Check reload resource behaviour - before and after change, 55 | */ 56 | @RequestMapping("/reloadResource") 57 | public void printHello(Writer writer) throws IOException { 58 | InputStream is = getClass().getResourceAsStream("/test.resource"); 59 | java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); 60 | writer.write(s.next()); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /spring-hibernate/src/main/java/org/hotswap/agent/example/service/TestEntityService.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.service; 2 | 3 | import org.hotswap.agent.example.model.TestEntity; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.transaction.annotation.Transactional; 7 | 8 | import javax.persistence.EntityManager; 9 | import javax.persistence.PersistenceContext; 10 | import java.util.List; 11 | 12 | /** 13 | * Experiment with this service in debug mode to check Spring reloading. 14 | * 15 | * @author Jiri Bubnik 16 | */ 17 | @Service 18 | @Transactional 19 | public class TestEntityService { 20 | 21 | @Autowired 22 | TestRepository testRepository; 23 | 24 | @PersistenceContext 25 | EntityManager entityManager; 26 | 27 | 28 | public void addTestEntity(TestEntity entity) { 29 | entityManager.persist(entity); 30 | } 31 | 32 | @SuppressWarnings("unchecked") 33 | public List loadTestEntities() { 34 | return entityManager.createQuery("select e from TestEntity e").getResultList(); 35 | } 36 | 37 | public String helloWorld() { 38 | return "Hello World"; 39 | } 40 | 41 | public String helloWorld3() { 42 | return "Hello World2"; 43 | } 44 | 45 | // return text from repository and ExamplePlugin values. 46 | public String helloWorldRepository() { 47 | return testRepository.helloWorld(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/java/org/hotswap/agent/example/service/TestRepository.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.service; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | /** 6 | * Hello world repository. 7 | */ 8 | @Repository 9 | public class TestRepository { 10 | public String helloWorld() { 11 | return "Hello world"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/resources-extra/test.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World Extra -------------------------------------------------------------------------------- /spring-hibernate/src/main/resources-watch/testWatch.properties: -------------------------------------------------------------------------------- 1 | hello=This should never happen - before change contents should be read from target/classes. -------------------------------------------------------------------------------- /spring-hibernate/src/main/resources-watch/testWatchReplace.properties: -------------------------------------------------------------------------------- 1 | hello=Hello World Watch -------------------------------------------------------------------------------- /spring-hibernate/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | org.hibernate.ejb.HibernatePersistence 5 | jdbc/ToDoDB 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/resources/examplePlugin.resource: -------------------------------------------------------------------------------- 1 | Change this file and see the result in TestEntityService.helloWorld() -------------------------------------------------------------------------------- /spring-hibernate/src/main/resources/hotswap-agent.properties: -------------------------------------------------------------------------------- 1 | watchResources=src/main/resources 2 | #J:/HotswapAgent/src/integration-test/resources 3 | 4 | # uncomment to test autohotswap feature 5 | #autoHotswap=true 6 | 7 | LOGGER.org.hotswap.agent=DEBUG 8 | #LOGGER.org.hotswap.agent.plugin=TRACE 9 | #LOGGER.org.hotswap.agent.watch=TRACE 10 | #LOGGER.org.hotswap.agent.command=TRACE 11 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/resources/test.resource: -------------------------------------------------------------------------------- 1 | This value should be replaced in target/classes, but not replaced in src/main/resources. 2 | Use this example to test watchResources configuration property. Before the file is changed, it loads 3 | value from target/classes and should replace the value with application name. After the file is changed, 4 | it is served from src/main/resources and it is not replaced. 5 | 6 | VALUE: '${name}' -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/WEB-INF/AgentWeb-servlet.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/WEB-INF/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | other 4 | /spring-hibernate 5 | 6 | jdbc/ToDoDB 7 | java:/jdbc/ToDoDB 8 | javax.sql.DataSource 9 | 10 | 11 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/WEB-INF/jetty-env.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | jdbc/ToDoDB 8 | 9 | 10 | 11 | jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 12 | 13 | sa 14 | sa 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/WEB-INF/jsp/test.jsp: -------------------------------------------------------------------------------- 1 | Hello World! 2 | 3 | ${entities} -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/WEB-INF/spring/applicationContext-jpa.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/WEB-INF/spring/applicationContext-service.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | DcevmAgent test 5 | DcevmAgent 6 | 7 | 8 | 9 | contextConfigLocation 10 | /WEB-INF/spring/*.xml 11 | 12 | 13 | org.springframework.web.context.ContextLoaderListener 14 | 15 | 16 | 17 | 18 | JpaFilter 19 | org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter 20 | 21 | 22 | JpaFilter 23 | /* 24 | 25 | 26 | AgentWeb 27 | org.springframework.web.servlet.DispatcherServlet 28 | 1 29 | 30 | 31 | 32 | AgentWeb 33 | /mvc/* 34 | 35 | 36 | 37 | 38 | /index.jsp 39 | 40 | 41 | 42 | 43 | 120 44 | 45 | 46 | 47 | 48 | Database connection 49 | jdbc/ToDoDB 50 | javax.sql.DataSource 51 | Container 52 | Shareable 53 | 54 | 55 | persistence/TestPU 56 | TestPU 57 | 58 | 59 | -------------------------------------------------------------------------------- /spring-hibernate/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 |

Simple HotswapAgent test webapp

2 | Use this application as a "real world" test scenario. 3 |
4 | Read README.md for more information how to properly setup this application. 5 |

Test pages:

6 | -------------------------------------------------------------------------------- /spring-hibernate/src/test/java/org/hotswap/agent/example/mvc/IndexControllerIT.java: -------------------------------------------------------------------------------- 1 | package org.hotswap.agent.example.mvc; 2 | 3 | import org.apache.http.HttpResponse; 4 | import org.apache.http.HttpStatus; 5 | import org.apache.http.client.methods.HttpGet; 6 | import org.apache.http.client.methods.HttpUriRequest; 7 | import org.apache.http.impl.client.HttpClientBuilder; 8 | import org.apache.http.util.EntityUtils; 9 | import org.hotswap.agent.example.service.TestRepository; 10 | import org.hotswap.agent.util.test.WaitHelper; 11 | import org.junit.Test; 12 | 13 | import java.io.IOException; 14 | import java.nio.file.Files; 15 | import java.nio.file.Path; 16 | import java.nio.file.Paths; 17 | import java.nio.file.StandardCopyOption; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | public class IndexControllerIT { 22 | String ENDPOINT = "http://localhost:8080/mvc/"; 23 | 24 | @Test 25 | public void testUpAndRunning() throws Exception { 26 | HttpUriRequest request = new HttpGet(ENDPOINT + "hello"); 27 | 28 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 29 | assertEquals(HttpStatus.SC_OK, httpResponse.getStatusLine().getStatusCode()); 30 | 31 | assertEquals("Hello World", EntityUtils.toString(httpResponse.getEntity())); 32 | } 33 | 34 | @Test 35 | public void testHelloWord() throws IOException { 36 | final HttpUriRequest request = new HttpGet(ENDPOINT + "helloRepository"); 37 | 38 | // replace the class file in extraClasspath (classloader looks into this directory) 39 | // autoHotswap should discover this change and reload the class 40 | String helloWorldFile = TestRepository.class.getName().replace(".", "/") + ".class"; 41 | Path source = Paths.get("target/hotswap/" + helloWorldFile); 42 | Path target = Paths.get("target/classes/" + helloWorldFile); 43 | Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); 44 | 45 | // wait for the hotswap 46 | boolean result = WaitHelper.waitForCommand(new WaitHelper.Command() { 47 | @Override 48 | public boolean result() throws Exception { 49 | HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request); 50 | return "Hello World Hotswap".equals(EntityUtils.toString(httpResponse.getEntity())); 51 | } 52 | }); 53 | } 54 | } --------------------------------------------------------------------------------