Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

redeployer

  • Loading branch information...
commit 2899b5347dc8dd5a60fada1e908d7d4a52ffc945 2 parents d7598b9 + 353668f
@purplefox purplefox authored
Showing with 878 additions and 163 deletions.
  1. +7 −0 vertx-examples/src/main/javascript/redeploy/mods/test-mod1/app.js
  2. +4 −0 vertx-examples/src/main/javascript/redeploy/mods/test-mod1/mod.json
  3. +7 −0 vertx-examples/src/main/modtest/mods/barmod/app.js
  4. +3 −0  vertx-examples/src/main/modtest/mods/barmod/mod.json
  5. +11 −0 vertx-examples/src/main/modtest/mods/foomod/app.js
  6. +3 −0  vertx-examples/src/main/modtest/mods/foomod/mod.json
  7. +3 −0  vertx-examples/src/main/modtest/mods/foomod/mod.json~
  8. +0 −1  vertx-examples/src/main/python/webapp/static_data.py
  9. +2 −8 vertx-lang/vertx-lang-groovy/src/main/groovy/org/vertx/groovy/deploy/impl/groovy/GroovyVerticleFactory.groovy
  10. +3 −0  vertx-lang/vertx-lang-java/src/main/java/org/vertx/java/deploy/impl/java/JavaVerticleFactory.java
  11. +2 −4 vertx-lang/vertx-lang-jython/src/main/java/org/vertx/java/deploy/impl/jython/JythonVerticle.java
  12. +0 −4 vertx-lang/vertx-lang-jython/src/main/java/org/vertx/java/deploy/impl/jython/JythonVerticleFactory.java
  13. +0 −1  vertx-lang/vertx-lang-jython/src/main/python_scripts/core/handlers.py
  14. +0 −2  vertx-lang/vertx-lang-jython/src/main/python_scripts/core/javautils.py
  15. +0 −1  vertx-lang/vertx-lang-jython/src/main/python_scripts/core/net.py
  16. +2 −2 vertx-platform/src/main/java/org/vertx/java/deploy/Container.java
  17. +2 −2 vertx-platform/src/main/java/org/vertx/java/deploy/VerticleFactory.java
  18. +60 −0 vertx-platform/src/main/java/org/vertx/java/deploy/impl/CountingCompletionHandler.java
  19. +56 −0 vertx-platform/src/main/java/org/vertx/java/deploy/impl/Deployment.java
  20. +10 −0 vertx-platform/src/main/java/org/vertx/java/deploy/impl/ModuleReloader.java
  21. +283 −0 vertx-platform/src/main/java/org/vertx/java/deploy/impl/Redeployer.java
  22. +51 −0 vertx-platform/src/main/java/org/vertx/java/deploy/impl/VerticleHolder.java
  23. +116 −125 vertx-platform/src/main/java/org/vertx/java/deploy/impl/VerticleManager.java
  24. +2 −2 vertx-platform/src/main/java/org/vertx/java/deploy/impl/cli/Starter.java
  25. +4 −5 vertx-testframework/src/main/java/org/vertx/java/framework/TestBase.java
  26. +247 −0 vertx-testsuite/src/test/java/org/vertx/java/tests/core/redeploy/RedeployerTest.java
  27. +0 −1  vertx-testsuite/src/test/python_scripts/core/buffer/test_client.py
  28. +0 −1  vertx-testsuite/src/test/python_scripts/core/filesystem/test_client.py
  29. +0 −1  vertx-testsuite/src/test/python_scripts/core/isolation/test_client.py
  30. +0 −1  vertx-testsuite/src/test/python_scripts/core/parsetools/test_client.py
  31. +0 −1  vertx-testsuite/src/test/python_scripts/core/scriptloading/test_client.py
  32. +0 −1  vertx-testsuite/src/test/python_scripts/core/shareddata/test_client.py
View
7 vertx-examples/src/main/javascript/redeploy/mods/test-mod1/app.js
@@ -0,0 +1,7 @@
+load("vertx.js")
+
+console.log("in test-mod1");
+
+vertx.createHttpServer().requestHandler(function(req) {
+ req.response.end("<html><body><h1>Hello from vert.x!</h1></body></html>");
+}).listen(8080, 'localhost');
View
4 vertx-examples/src/main/javascript/redeploy/mods/test-mod1/mod.json
@@ -0,0 +1,4 @@
+{
+ "main": "app.js",
+ "auto-redeploy": true
+}
View
7 vertx-examples/src/main/modtest/mods/barmod/app.js
@@ -0,0 +1,7 @@
+load('vertx.js')
+
+console.log("barmod loaded");
+
+function vertxStop() {
+ console.log("barmod unloaded");
+}
View
3  vertx-examples/src/main/modtest/mods/barmod/mod.json
@@ -0,0 +1,3 @@
+{
+"main":"app.js"
+}
View
11 vertx-examples/src/main/modtest/mods/foomod/app.js
@@ -0,0 +1,11 @@
+load('vertx.js')
+
+console.log("in foomod");
+
+vertx.deployModule('barmod', null, 1, function(depID) {
+ vertx.setTimer(1000, function() {
+ vertx.undeployModule(depID);
+ })
+});
+
+
View
3  vertx-examples/src/main/modtest/mods/foomod/mod.json
@@ -0,0 +1,3 @@
+{
+"main":"app.js"
+}
View
3  vertx-examples/src/main/modtest/mods/foomod/mod.json~
@@ -0,0 +1,3 @@
+{
+main:"app.js"
+}
View
1  vertx-examples/src/main/python/webapp/static_data.py
@@ -1,4 +1,3 @@
-import vertx
from core.event_bus import EventBus
eb = EventBus
View
10 ...g-groovy/src/main/groovy/org/vertx/groovy/deploy/impl/groovy/GroovyVerticleFactory.groovy
@@ -16,20 +16,14 @@
package org.vertx.groovy.deploy.impl.groovy
-import groovy.lang.Binding
-import groovy.lang.GroovyClassLoader
-import groovy.lang.GroovyCodeSource
-import groovy.lang.Script
+import java.lang.reflect.Method
import org.vertx.groovy.core.Vertx
import org.vertx.groovy.deploy.Container
import org.vertx.java.core.impl.VertxInternal
import org.vertx.java.deploy.Verticle
import org.vertx.java.deploy.VerticleFactory
-import org.vertx.java.deploy.impl.VertxLocator
import org.vertx.java.deploy.impl.VerticleManager
-
-import java.lang.reflect.Method
-import java.net.URL
+import org.vertx.java.deploy.impl.VertxLocator
/**
* @author <a href="http://tfox.org">Tim Fox</a>
View
3  ...ng/vertx-lang-java/src/main/java/org/vertx/java/deploy/impl/java/JavaVerticleFactory.java
@@ -60,6 +60,9 @@ private boolean isJavaSource(String main) {
}
public Verticle createVerticle(String main, ClassLoader loader) throws Exception {
+
+ System.out.println("creating verticle " + main);
+
ClassLoader cl = loader;
String className = main;
if (isJavaSource(main)) {
View
6 ...ang/vertx-lang-jython/src/main/java/org/vertx/java/deploy/impl/jython/JythonVerticle.java
@@ -16,11 +16,9 @@
package org.vertx.java.deploy.impl.jython;
-import org.python.util.PythonInterpreter;
-import org.python.core.PyException;
-import org.python.core.PySystemState;
import org.python.core.Options;
-
+import org.python.core.PySystemState;
+import org.python.util.PythonInterpreter;
import org.vertx.java.core.logging.Logger;
import org.vertx.java.core.logging.impl.LoggerFactory;
import org.vertx.java.deploy.Verticle;
View
4 ...tx-lang-jython/src/main/java/org/vertx/java/deploy/impl/jython/JythonVerticleFactory.java
@@ -16,14 +16,10 @@
package org.vertx.java.deploy.impl.jython;
-import org.vertx.java.core.logging.Logger;
import org.vertx.java.deploy.Verticle;
import org.vertx.java.deploy.VerticleFactory;
import org.vertx.java.deploy.impl.VerticleManager;
-
-import java.util.List;
-
/**
* @author <a href="https://github.com/sjhorn">Scott Horn</a>
*/
View
1  vertx-lang/vertx-lang-jython/src/main/python_scripts/core/handlers.py
@@ -15,7 +15,6 @@
import org.vertx.java.core.Handler
from core.buffer import Buffer
-from core.javautils import map_from_java, map_to_java
__author__ = "Scott Horn"
__email__ = "scott@hornmicro.com"
View
2  vertx-lang/vertx-lang-jython/src/main/python_scripts/core/javautils.py
@@ -21,9 +21,7 @@
import sys
from types import *
-from java import lang
from java import util
-from java import io
__author__ = "Scott Horn"
__email__ = "scott@hornmicro.com"
View
1  vertx-lang/vertx-lang-jython/src/main/python_scripts/core/net.py
@@ -23,7 +23,6 @@
import core.buffer
import core.streams
-from core.javautils import map_from_java, map_to_java
from core.handlers import CloseHandler, DoneHandler, ClosedHandler
from core.event_bus import EventBus
View
4 vertx-platform/src/main/java/org/vertx/java/deploy/Container.java
@@ -89,7 +89,7 @@ public void deployWorkerVerticle(String main, JsonObject config, int instances)
public void deployWorkerVerticle(String main, JsonObject config, int instances, Handler<String> doneHandler) {
URL[] currURLs = mgr.getDeploymentURLs();
File modDir = mgr.getDeploymentModDir();
- mgr.deploy(true, main, config, currURLs, instances, modDir, doneHandler);
+ mgr.deployVerticle(true, main, config, currURLs, instances, modDir, doneHandler);
}
/**
@@ -186,7 +186,7 @@ public void deployVerticle(String main, JsonObject config, int instances) {
public void deployVerticle(String main, JsonObject config, int instances, Handler<String> doneHandler) {
URL[] currURLs = mgr.getDeploymentURLs();
File modDir = mgr.getDeploymentModDir();
- mgr.deploy(false, main, config, currURLs, instances, modDir, doneHandler);
+ mgr.deployVerticle(false, main, config, currURLs, instances, modDir, doneHandler);
}
/**
View
4 vertx-platform/src/main/java/org/vertx/java/deploy/VerticleFactory.java
@@ -17,10 +17,10 @@
package org.vertx.java.deploy;
-import java.util.ServiceLoader;
-
import org.vertx.java.deploy.impl.VerticleManager;
+import java.util.ServiceLoader;
+
/**
* @author <a href="http://tfox.org">Tim Fox</a>
*/
View
60 vertx-platform/src/main/java/org/vertx/java/deploy/impl/CountingCompletionHandler.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.vertx.java.deploy.impl;
+
+import org.vertx.java.core.Handler;
+import org.vertx.java.core.impl.Context;
+
+/**
+ * @author <a href="http://tfox.org">Tim Fox</a>
+ */
+public class CountingCompletionHandler {
+
+ private final Context context;
+
+ CountingCompletionHandler(Context context) {
+ this.context = context;
+ }
+
+ int count;
+ int required;
+ Handler<Void> doneHandler;
+
+ synchronized void complete() {
+ count++;
+ checkDone();
+ }
+
+ synchronized void incRequired() {
+ required++;
+ }
+
+ synchronized void setHandler(Handler<Void> doneHandler) {
+ this.doneHandler = doneHandler;
+ checkDone();
+ }
+
+ void checkDone() {
+ if (doneHandler != null && count == required) {
+ context.execute(new Runnable() {
+ public void run() {
+ doneHandler.handle(null);
+ }
+ });
+ }
+ }
+}
View
56 vertx-platform/src/main/java/org/vertx/java/deploy/impl/Deployment.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2011-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.vertx.java.deploy.impl;
+
+import org.vertx.java.core.json.JsonObject;
+import org.vertx.java.deploy.VerticleFactory;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="http://tfox.org">Tim Fox</a>
+ */
+public class Deployment {
+ public final String name;
+ public final String modName;
+ public final int instances;
+ public final VerticleFactory factory;
+ public final JsonObject config;
+ public final URL[] urls;
+ public final File modDir;
+ public final List<VerticleHolder> verticles = new ArrayList<>();
+ public final List<String> childDeployments = new ArrayList<>();
+ public final String parentDeploymentName;
+ public final boolean autoRedeploy;
+
+ public Deployment(String name, String modName, int instances, VerticleFactory factory, JsonObject config,
+ URL[] urls, File modDir, String parentDeploymentName,
+ boolean autoRedeploy) {
+ this.name = name;
+ this.modName = modName;
+ this.instances = instances;
+ this.factory = factory;
+ this.config = config;
+ this.urls = urls;
+ this.modDir = modDir;
+ this.parentDeploymentName = parentDeploymentName;
+ this.autoRedeploy = autoRedeploy;
+ }
+}
View
10 vertx-platform/src/main/java/org/vertx/java/deploy/impl/ModuleReloader.java
@@ -0,0 +1,10 @@
+package org.vertx.java.deploy.impl;
+
+import java.util.Set;
+
+/**
+ * @author <a href="http://tfox.org">Tim Fox</a>
+ */
+public interface ModuleReloader {
+ void reloadModules(Set<Deployment> parents);
+}
View
283 vertx-platform/src/main/java/org/vertx/java/deploy/impl/Redeployer.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2011-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.vertx.java.deploy.impl;
+
+import org.vertx.java.core.Handler;
+import org.vertx.java.core.SimpleHandler;
+import org.vertx.java.core.Vertx;
+import org.vertx.java.core.impl.Context;
+import org.vertx.java.core.logging.Logger;
+import org.vertx.java.core.logging.impl.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * @author <a href="http://tfox.org">Tim Fox</a>
+ *
+ */
+public class Redeployer {
+
+ private static final Logger log = LoggerFactory.getLogger(Redeployer.class);
+
+ private static final long GRACE_PERIOD = 600;
+ private static final long CHECK_PERIOD = 200;
+
+ private final File modRoot;
+ private final ModuleReloader reloader;
+ private final Map<Path, Set<Deployment>> watchedDeployments = new HashMap<>();
+ private final Map<WatchKey, Path> watchKeys = new HashMap<>();
+ private final Map<Path, Path> moduleDirs = new HashMap<>();
+ private final WatchService watchService;
+ private final Vertx vertx;
+ private final Map<Path, Long> changing = new HashMap<>();
+ private final long timerID;
+ private final Queue<Deployment> toDeploy = new ConcurrentLinkedQueue<>();
+ private final Queue<Deployment> toUndeploy = new ConcurrentLinkedQueue<>();
+ private Context ctx;
+
+ public Redeployer(Vertx vertx, File modRoot, ModuleReloader reloader) {
+ this.modRoot = modRoot;
+ this.reloader = reloader;
+ try {
+ watchService = FileSystems.getDefault().newWatchService();
+ } catch (IOException e) {
+ log.error("Failed to create redeployer", e);
+ throw new IllegalArgumentException(e.getMessage());
+ }
+
+ this.vertx = vertx;
+ timerID = vertx.setPeriodic(CHECK_PERIOD, new Handler<Long>() {
+ public void handle(Long id) {
+ if (ctx == null) {
+ ctx = Context.getContext();
+ } else {
+ checkContext();
+ }
+ try {
+ checkEvents();
+ } catch (Exception e) {
+ log.error("Failed to check events", e);
+ }
+ }
+ });
+ }
+
+ public void close() {
+ vertx.cancelTimer(timerID);
+ }
+
+ public void moduleDeployed(Deployment deployment) {
+ toDeploy.add(deployment);
+ }
+
+ public void moduleUndeployed(Deployment deployment) {
+ toUndeploy.add(deployment);
+ }
+
+ // We process all the deployments and undeployments on the same context as the
+ // rest of the stuff
+ // this means we don't have to synchronize between the deployment and
+ // any stuff done on the timer
+ private void processDeployments() {
+ Deployment dep;
+ while ((dep = toDeploy.poll()) != null) {
+ File fmodDir = new File(modRoot, dep.modName);
+ Path modDir = fmodDir.toPath();
+ Set<Deployment> deps = watchedDeployments.get(modDir);
+ if (deps == null) {
+ deps = new HashSet<>();
+ watchedDeployments.put(modDir, deps);
+ try {
+ registerAll(modDir, modDir);
+ } catch (IOException e) {
+ log.error("Failed to register", e);
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+ deps.add(dep);
+ }
+ }
+
+ // This can be optimised
+ private void processUndeployments() {
+ Deployment dep;
+ while ((dep = toUndeploy.poll()) != null) {
+ File modDir = new File(modRoot, dep.modName);
+ Path pModDir = modDir.toPath();
+ Set<Deployment> deps = watchedDeployments.get(pModDir);
+ deps.remove(dep);
+ if (deps.isEmpty()) {
+ watchedDeployments.remove(pModDir);
+ Set<Path> modPaths = new HashSet<>();
+ for (Map.Entry<Path, Path> entry: moduleDirs.entrySet()) {
+ if (entry.getValue().equals(pModDir)) {
+ modPaths.add(entry.getKey());
+ }
+ }
+ for (Path p: modPaths) {
+ moduleDirs.remove(p);
+ changing.remove(p);
+ }
+ Set<WatchKey> keys = new HashSet<>();
+ for (Map.Entry<WatchKey, Path> entry: watchKeys.entrySet()) {
+ if (modPaths.contains(entry.getValue())) {
+ keys.add(entry.getKey());
+ }
+ }
+ for (WatchKey key: keys) {
+ key.cancel();
+ watchKeys.remove(key);
+ }
+ }
+ }
+ }
+
+ void checkEvents() {
+ processUndeployments();
+ processDeployments();
+ Set<Path> changed = new HashSet<>();
+ while (true) {
+ WatchKey key = watchService.poll();
+ if (key == null) {
+ break;
+ }
+ handleEvent(key, changed);
+ }
+ long now = System.currentTimeMillis();
+ for (Path modulePath: changed) {
+ changing.put(modulePath, now);
+ }
+ Set<Path> toRedeploy = new HashSet<>();
+ for (Map.Entry<Path, Long> entry: changing.entrySet()) {
+ if (now - entry.getValue() > GRACE_PERIOD) {
+ // Module has changed but no changes for GRACE_PERIOD ms
+ // we can assume the redeploy has finished
+ toRedeploy.add(entry.getKey());
+ }
+ }
+ if (!toRedeploy.isEmpty()) {
+ Set<Deployment> deployments = new HashSet<>();
+ for (Path moduleDir: toRedeploy) {
+ log.info("moduleDir is " + moduleDir);
+ log.info("Module has changed - redeploying module from directory " + moduleDir.toString());
+ changing.remove(moduleDir);
+ deployments.addAll(watchedDeployments.get(moduleDir));
+ }
+ reloader.reloadModules(deployments);
+ }
+ }
+
+
+ private void handleEvent(WatchKey key, Set<Path> changed) {
+ Path dir = watchKeys.get(key);
+ if (dir == null) {
+ throw new IllegalStateException("Unrecognised watch key " + dir);
+ }
+
+ for (WatchEvent<?> event : key.pollEvents()) {
+ WatchEvent.Kind<?> kind = event.kind();
+
+ if (kind == StandardWatchEventKinds.OVERFLOW) {
+ log.warn("Overflow event on watched directory");
+ continue;
+ }
+
+ Path moduleDir = moduleDirs.get(dir);
+ if (moduleDir != null) {
+
+ @SuppressWarnings("unchecked")
+ WatchEvent<Path> ev = (WatchEvent<Path>) event;
+ Path name = ev.context();
+
+ Path child = dir.resolve(name);
+
+ if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
+ if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) {
+ try {
+ registerAll(moduleDir, child);
+ } catch (IOException e) {
+ log.error("Failed to register child", e);
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+ } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
+ moduleDirs.remove(child);
+ }
+ changed.add(moduleDir);
+ }
+ }
+
+ boolean valid = key.reset();
+ if (!valid) {
+ watchKeys.remove(key);
+ }
+ }
+
+ private void register(Path modDir, Path dir) throws IOException {
+ WatchKey key = dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
+ StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
+ watchKeys.put(key, dir);
+ moduleDirs.put(dir, modDir);
+ }
+
+ private void registerAll(final Path modDir, final Path dir) throws IOException {
+ Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ register(modDir, dir);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+// private void dumpSizes() {
+// log.info("watchkeys: " + watchKeys.size());
+// log.info("moduleDirs: " + moduleDirs.size());
+// log.info("changing: " + changing.size());
+// int size = 0;
+// for (Set<Deployment> s: this.watchedDeployments.values()) {
+// size += s.size();
+// }
+// log.info("watcheddeployments:" + size);
+// }
+
+ private void checkContext() {
+ //Sanity check
+ if (Context.getContext() != ctx) {
+ throw new IllegalStateException("Got context: " + Context.getContext() + " expected " + ctx);
+ }
+ }
+
+}
View
51 vertx-platform/src/main/java/org/vertx/java/deploy/impl/VerticleHolder.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.vertx.java.deploy.impl;
+
+import org.vertx.java.core.impl.Context;
+import org.vertx.java.core.impl.DeploymentHandle;
+import org.vertx.java.core.json.JsonObject;
+import org.vertx.java.core.logging.Logger;
+import org.vertx.java.deploy.Verticle;
+
+/**
+ * @author <a href="http://tfox.org">Tim Fox</a>
+ */
+class VerticleHolder implements DeploymentHandle {
+ final Deployment deployment;
+ final Context context;
+ final Verticle verticle;
+ final String loggerName;
+ final Logger logger;
+ //We put the config here too so it's still accessible to the verticle after it has been deployed
+ //(deploy is async)
+ final JsonObject config;
+
+ VerticleHolder(Deployment deployment, Context context, Verticle verticle, String loggerName,
+ Logger logger, JsonObject config) {
+ this.deployment = deployment;
+ this.context = context;
+ this.verticle = verticle;
+ this.loggerName = loggerName;
+ this.logger = logger;
+ this.config = config;
+ }
+
+ public void reportException(Throwable t) {
+ deployment.factory.reportException(t);
+ }
+}
View
241 vertx-platform/src/main/java/org/vertx/java/deploy/impl/VerticleManager.java
@@ -26,7 +26,6 @@
import org.vertx.java.core.http.HttpClientResponse;
import org.vertx.java.core.impl.BlockingAction;
import org.vertx.java.core.impl.Context;
-import org.vertx.java.core.impl.DeploymentHandle;
import org.vertx.java.core.impl.VertxInternal;
import org.vertx.java.core.json.DecodeException;
import org.vertx.java.core.json.JsonObject;
@@ -35,7 +34,6 @@
import org.vertx.java.deploy.Container;
import org.vertx.java.deploy.Verticle;
import org.vertx.java.deploy.VerticleFactory;
-import org.vertx.java.deploy.impl.VerticleManager;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -55,6 +53,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Set;
import java.util.UUID;
@@ -68,7 +67,7 @@
/**
* @author <a href="http://tfox.org">Tim Fox</a>
*/
-public class VerticleManager {
+public class VerticleManager implements ModuleReloader {
private static final Logger log = LoggerFactory.getLogger(VerticleManager.class);
private static final String REPO_URI_ROOT = "/vertx-mods/mods/";
@@ -83,6 +82,7 @@
private final CountDownLatch stopLatch = new CountDownLatch(1);
private Map<String, VerticleFactory> factories;
private final String defaultRepo;
+ private final Redeployer redeployer;
public VerticleManager(VertxInternal vertx) {
this(vertx, null);
@@ -102,10 +102,11 @@ public VerticleManager(VertxInternal vertx, String defaultRepo) {
modRoot = new File(modDir);
} else {
// Default to local module directory called 'mods'
- modRoot = new File("./mods");
+ modRoot = new File("mods");
}
this.factories = new HashMap<>();
+ this.redeployer = new Redeployer(vertx, modRoot, this);
// Find and load VerticleFactories
Iterable<VerticleFactory> services = VerticleFactory.factories;
@@ -154,16 +155,16 @@ public Logger getLogger() {
return holder == null ? null : holder.logger;
}
- public void deploy(boolean worker, final String main,
- final JsonObject config, final URL[] urls,
- int instances, File currentModDir,
- final Handler<String> doneHandler) {
+ public void deployVerticle(boolean worker, final String main,
+ final JsonObject config, final URL[] urls,
+ int instances, File currentModDir,
+ final Handler<String> doneHandler) {
Context ctx = vertx.getOrAssignContext();
- doDeploy(worker, main, config, urls, instances, currentModDir, ctx, doneHandler);
+ doDeploy(null, false, worker, main, null, config, urls, instances, currentModDir, ctx, doneHandler);
}
public synchronized void undeployAll(final Handler<Void> doneHandler) {
- final UndeployCount count = new UndeployCount();
+ final CountingCompletionHandler count = new CountingCompletionHandler(vertx.getOrAssignContext());
if (!deployments.isEmpty()) {
// We do it this way since undeploy is itself recursive - we don't want
// to attempt to undeploy the same verticle twice if it's a child of
@@ -173,7 +174,7 @@ public synchronized void undeployAll(final Handler<Void> doneHandler) {
count.incRequired();
undeploy(name, new SimpleHandler() {
public void handle() {
- count.undeployed();
+ count.complete();
}
});
}
@@ -181,13 +182,6 @@ public void handle() {
count.setHandler(doneHandler);
}
- public synchronized void undeploy(String name, final Handler<Void> doneHandler) {
- if (deployments.get(name) == null) {
- throw new IllegalArgumentException("There is no deployment with name " + name);
- }
- doUndeploy(name, doneHandler);
- }
-
public synchronized Map<String, Integer> listInstances() {
Map<String, Integer> map = new HashMap<>();
for (Map.Entry<String, Deployment> entry: deployments.entrySet()) {
@@ -198,6 +192,11 @@ public synchronized void undeploy(String name, final Handler<Void> doneHandler)
public void deployMod(final String modName, final JsonObject config,
final int instances, final File currentModDir, final Handler<String> doneHandler) {
+ doDeployMod(false, null, modName, config, instances, currentModDir, doneHandler);
+ }
+
+ private void doDeployMod(final boolean redeploy, final String depName, final String modName, final JsonObject config,
+ final int instances, final File currentModDir, final Handler<String> doneHandler) {
final Context ctx = vertx.getOrAssignContext();
AsyncResultHandler<Boolean> handler = new AsyncResultHandler<Boolean>() {
@@ -209,11 +208,9 @@ public void handle(AsyncResult<Boolean> res) {
public void handle(Boolean res) {
if (res) {
// Now deploy it
- deployMod(modName, config, instances, currentModDir, doneHandler);
+ doDeployMod(redeploy, depName, modName, config, instances, currentModDir, doneHandler);
} else {
- if (doneHandler != null) {
- doneHandler.handle(null);
- }
+ executeHandlerOnContext(ctx, doneHandler, null);
}
}
});
@@ -229,7 +226,6 @@ public void handle(Boolean res) {
@Override
public Boolean action() throws Exception {
- log.debug("Attempting to deploy module " + modName);
File modDir = new File(modRoot, modName);
JsonObject conf = loadModuleConfig(modName, modDir);
if (conf != null) {
@@ -249,13 +245,25 @@ public Boolean action() throws Exception {
// If preserveCwd then use the current module directory instead, or the cwd if not in a module
File modDirToUse = preserveCwd ? currentModDir : modDir;
- List<URL> urls = processIncludes(modName, new ArrayList<URL>(), modName, modDir, conf,
+ List<URL> urls = processIncludes(modName, new ArrayList<URL>(), modName, modDirToUse, conf,
new HashMap<String, String>(), new HashSet<String>());
if (urls == null) {
return false;
}
- doDeploy(worker, main, config,
- urls.toArray(new URL[urls.size()]), instances, modDirToUse, ctx, doneHandler);
+
+ Boolean ar = conf.getBoolean("auto-redeploy");
+ final boolean autoRedeploy = ar == null ? false : ar;
+
+ Handler<String> handler = new Handler<String>() {
+ public void handle(String res) {
+ if (res != null && !redeploy && autoRedeploy) {
+ redeployer.moduleDeployed(deployments.get(res));
+ }
+ executeHandlerOnContext(context, doneHandler, res);
+ }
+ };
+ doDeploy(depName, autoRedeploy, worker, main, modName, config,
+ urls.toArray(new URL[urls.size()]), instances, modDir, ctx, handler);
return true;
} else {
return false;
@@ -273,6 +281,8 @@ private JsonObject loadModuleConfig(String modName, File modDir) {
conf = new Scanner(new File(modDir, "mod.json")).useDelimiter("\\A").next();
} catch (FileNotFoundException e) {
throw new IllegalStateException("Module " + modName + " does not contain a mod.json file");
+ } catch (NoSuchElementException e) {
+ throw new IllegalStateException("Module " + modName + " contains an empty mod.json file");
}
JsonObject json;
try {
@@ -380,10 +390,11 @@ public void handle(Boolean b) {
return urls;
}
+
/* (non-Javadoc)
- * @see org.vertx.java.deploy.impl.VTest#installMod(java.lang.String, org.vertx.java.core.Handler)
- */
-public void installMod(final String moduleName, final Handler<Boolean> doneHandler) {
+ * @see org.vertx.java.deploy.impl.VTest#installMod(java.lang.String, org.vertx.java.core.Handler)
+ */
+ public void installMod(final String moduleName, final Handler<Boolean> doneHandler) {
HttpClient client = vertx.createHttpClient();
client.setHost(defaultRepo);
client.exceptionHandler(new Handler<Exception>() {
@@ -418,9 +429,9 @@ public void handle(Buffer buffer) {
}
/* (non-Javadoc)
- * @see org.vertx.java.deploy.impl.VTest#uninstallMod(java.lang.String)
- */
-public void uninstallMod(String moduleName) {
+ * @see org.vertx.java.deploy.impl.VTest#uninstallMod(java.lang.String)
+ */
+ public void uninstallMod(String moduleName) {
log.info("Removing module " + moduleName + " from directory " + modRoot);
File modDir = new File(modRoot, moduleName);
if (!modDir.exists()) {
@@ -526,13 +537,15 @@ private void setPathAdjustment(File modDir) {
Context.getContext().setPathAdjustment(relative);
}
- private synchronized void doDeploy(boolean worker, final String main,
+ private synchronized void doDeploy(String depName,
+ boolean autoRedeploy,
+ boolean worker, final String main,
+ final String modName,
final JsonObject config, final URL[] urls,
int instances,
final File modDir,
final Context context,
final Handler<String> doneHandler) {
-
// Infer the main type
String language = "java";
for (VerticleFactory vf : factories.values()) {
@@ -542,7 +555,8 @@ private synchronized void doDeploy(boolean worker, final String main,
}
}
- final String deploymentName = "deployment-" + UUID.randomUUID().toString();
+ final String deploymentName =
+ depName != null ? depName : "deployment-" + UUID.randomUUID().toString();
log.debug("Deploying name : " + deploymentName + " main: " + main +
" instances: " + instances);
@@ -558,16 +572,14 @@ private synchronized void doDeploy(boolean worker, final String main,
class AggHandler {
AtomicInteger count = new AtomicInteger(0);
+ boolean failed;
- void started() {
+ void done(boolean res) {
+ if (!res) {
+ failed = true;
+ }
if (count.incrementAndGet() == instCount) {
- if (doneHandler != null) {
- context.execute(new Runnable() {
- public void run() {
- doneHandler.handle(deploymentName);
- }
- });
- }
+ executeHandlerOnContext(context, doneHandler, failed ? null : deploymentName);
}
}
}
@@ -575,9 +587,10 @@ public void run() {
final AggHandler aggHandler = new AggHandler();
String parentDeploymentName = getDeploymentName();
- final Deployment deployment = new Deployment(deploymentName, verticleFactory,
- config == null ? new JsonObject() : config.copy(), urls, modDir, parentDeploymentName);
- deployments.put(deploymentName, deployment);
+ final Deployment deployment = new Deployment(deploymentName, modName, instances, verticleFactory,
+ config == null ? new JsonObject() : config.copy(), urls, modDir, parentDeploymentName,
+ autoRedeploy);
+ addDeployment(deploymentName, deployment);
if (parentDeploymentName != null) {
Deployment parent = deployments.get(parentDeploymentName);
parent.childDeployments.add(deploymentName);
@@ -611,9 +624,7 @@ public void run() {
if (error) {
doUndeploy(deploymentName, new SimpleHandler() {
public void handle() {
- if (doneHandler != null) {
- doneHandler.handle(null);
- }
+ aggHandler.done(false);
}
});
return;
@@ -629,15 +640,16 @@ public void handle() {
setPathAdjustment(modDir);
}
verticle.start();
+ aggHandler.done(true);
} catch (Throwable t) {
vertx.reportException(t);
doUndeploy(deploymentName, new SimpleHandler() {
public void handle() {
- doneHandler.handle(null);
+ aggHandler.done(false);
}
});
}
- aggHandler.started();
+
}
};
@@ -671,14 +683,14 @@ private VerticleHolder getVerticleHolder() {
}
private void doUndeploy(String name, final Handler<Void> doneHandler) {
- UndeployCount count = new UndeployCount();
- doUndeploy(name, count);
- if (doneHandler != null) {
- count.setHandler(doneHandler);
- }
+ CountingCompletionHandler count = new CountingCompletionHandler(vertx.getOrAssignContext());
+ doUndeploy(name, count);
+ if (doneHandler != null) {
+ count.setHandler(doneHandler);
+ }
}
- private void doUndeploy(String name, final UndeployCount count) {
+ private void doUndeploy(String name, final CountingCompletionHandler count) {
final Deployment deployment = deployments.remove(name);
@@ -688,7 +700,6 @@ private void doUndeploy(String name, final UndeployCount count) {
}
if (!deployment.verticles.isEmpty()) {
-
for (final VerticleHolder holder: deployment.verticles) {
count.incRequired();
holder.context.execute(new Runnable() {
@@ -698,7 +709,7 @@ public void run() {
} catch (Throwable t) {
vertx.reportException(t);
}
- count.undeployed();
+ count.complete();
LoggerFactory.removeLogger(holder.loggerName);
holder.context.runCloseHooks();
}
@@ -714,80 +725,60 @@ public void run() {
}
}
- private static class VerticleHolder implements DeploymentHandle {
- final Deployment deployment;
- final Context context;
- final Verticle verticle;
- final String loggerName;
- final Logger logger;
- //We put the config here too so it's still accessible to the verticle after it has been deployed
- //(deploy is async)
- final JsonObject config;
-
- private VerticleHolder(Deployment deployment, Context context, Verticle verticle, String loggerName,
- Logger logger, JsonObject config) {
- this.deployment = deployment;
- this.context = context;
- this.verticle = verticle;
- this.loggerName = loggerName;
- this.logger = logger;
- this.config = config;
- }
-
- public void reportException(Throwable t) {
- deployment.factory.reportException(t);
+ public void reloadModules(final Set<Deployment> deps) {
+ for (final Deployment deployment: deps) {
+ if (deployments.containsKey(deployment.name)) {
+ doUndeploy(deployment.name, new SimpleHandler() {
+ public void handle() {
+ redeploy(deployment, deps);
+ }
+ });
+ } else {
+ // This will be the case if the previous deployment failed, e.g.
+ // a code error in a user verticle
+ redeploy(deployment, deps);
+ }
}
}
- private static class Deployment {
- final String name;
- final VerticleFactory factory;
- final JsonObject config;
- final URL[] urls;
- final File modDir;
- final List<VerticleHolder> verticles = new ArrayList<>();
- final List<String> childDeployments = new ArrayList<>();
- final String parentDeploymentName;
-
- private Deployment(String name, VerticleFactory factory, JsonObject config,
- URL[] urls, File modDir, String parentDeploymentName) {
- this.name = name;
- this.factory = factory;
- this.config = config;
- this.urls = urls;
- this.modDir = modDir;
- this.parentDeploymentName = parentDeploymentName;
+ public synchronized void undeploy(String name, final Handler<Void> doneHandler) {
+ final Deployment dep = deployments.get(name);
+ if (dep == null) {
+ throw new IllegalArgumentException("There is no deployment with name " + name);
}
+ Handler<Void> wrappedHandler = new SimpleHandler() {
+ public void handle() {
+ if (dep.modName != null && dep.autoRedeploy) {
+ redeployer.moduleUndeployed(dep);
+ }
+ if (doneHandler != null) {
+ doneHandler.handle(null);
+ }
+ }
+ };
+ doUndeploy(name, wrappedHandler);
}
- private class UndeployCount {
- int count;
- int required;
- Handler<Void> doneHandler;
- Context context = vertx.getOrAssignContext();
-
- synchronized void undeployed() {
- count++;
- checkDone();
- }
-
- synchronized void incRequired() {
- required++;
- }
+ private void redeploy(final Deployment deployment, final Set<Deployment> deployments) {
+ doDeployMod(true, deployment.name, deployment.modName, deployment.config, deployment.instances,
+ null, null);
+ }
- synchronized void setHandler(Handler<Void> doneHandler) {
- this.doneHandler = doneHandler;
- checkDone();
+ private void executeHandlerOnContext(final Context context,
+ final Handler<String> doneHandler,
+ final String res)
+ {
+ if (doneHandler != null) {
+ context.execute(new Runnable() {
+ public void run() {
+ doneHandler.handle(res);
+ }
+ });
}
+ }
- void checkDone() {
- if (doneHandler != null && count == required) {
- context.execute(new Runnable() {
- public void run() {
- doneHandler.handle(null);
- }
- });
- }
- }
+ private void addDeployment(String deploymentName, Deployment deployment) {
+ deployments.put(deploymentName, deployment);
}
+
}
View
4 vertx-platform/src/main/java/org/vertx/java/deploy/impl/cli/Starter.java
@@ -59,7 +59,7 @@ public static void main(String[] args) {
private VerticleManager mgr;
private Starter(String[] sargs) {
- String vertxVersion = String.format("vert.x %s", System.getProperty("vertx.version", "0.0.0-UNKNOWN!"));
+ String vertxVersion = String.format("vert.x %s", System.getProperty("vertx.version", "0.0.0-UNKNOWN!"));
if (sargs.length < 1) {
displaySyntax();
} else {
@@ -217,7 +217,7 @@ public void handle(String id) {
if (module) {
mgr.deployMod(main, conf, instances, null, doneHandler);
} else {
- mgr.deploy(worker, main, conf, urls, instances, null, doneHandler);
+ mgr.deployVerticle(worker, main, conf, urls, instances, null, doneHandler);
}
addShutdownHook();
View
9 vertx-testframework/src/main/java/org/vertx/java/framework/TestBase.java
@@ -28,7 +28,6 @@
import org.vertx.java.core.logging.impl.LoggerFactory;
import org.vertx.java.deploy.impl.VerticleManager;
-import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
@@ -176,9 +175,9 @@ protected String startApp(boolean worker, String main, int instances) throws Exc
}
protected String startApp(boolean worker, String main, JsonObject config, int instances, boolean await) throws Exception {
- if(Runtime.getRuntime().availableProcessors() < 2) {
- log.error("*** The test framework requires at least 2 processors ***");
- fail("The test framework requires at least 2 processors");
+ if (Runtime.getRuntime().availableProcessors() < 2) {
+ log.error("*** The test framework requires at least 2 processors ***");
+ fail("The test framework requires at least 2 processors");
}
URL url;
if (main.endsWith(".js") || main.endsWith(".rb") || main.endsWith(".groovy") || main.endsWith(".py")) {
@@ -206,7 +205,7 @@ public void handle(String deploymentName) {
}
};
- verticleManager.deploy(worker, main, config, new URL[] {url}, instances, null, doneHandler);
+ verticleManager.deployVerticle(worker, main, config, new URL[]{url}, instances, null, doneHandler);
if (!doneLatch.await(30, TimeUnit.SECONDS)) {
throw new IllegalStateException("Timedout waiting for apps to start");
View
247 vertx-testsuite/src/test/java/org/vertx/java/tests/core/redeploy/RedeployerTest.java
@@ -0,0 +1,247 @@
+package org.vertx.java.tests.core.redeploy;
+
+import junit.framework.TestCase;
+import org.junit.Test;
+import org.vertx.java.core.Vertx;
+import org.vertx.java.core.buffer.Buffer;
+import org.vertx.java.core.file.AsyncFile;
+import org.vertx.java.core.impl.ConcurrentHashSet;
+import org.vertx.java.core.logging.Logger;
+import org.vertx.java.core.logging.impl.LoggerFactory;
+import org.vertx.java.deploy.impl.Deployment;
+import org.vertx.java.deploy.impl.ModuleReloader;
+import org.vertx.java.deploy.impl.Redeployer;
+import org.vertx.java.framework.TestUtils;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.RandomAccessFile;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author <a href="http://tfox.org">Tim Fox</a>
+ */
+public class RedeployerTest extends TestCase {
+
+ private static final Logger log = LoggerFactory.getLogger(RedeployerTest.class);
+
+ Vertx vertx;
+ TestReloader reloader;
+ File modRoot;
+ Redeployer red;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ vertx = Vertx.newVertx();
+ reloader = new TestReloader();
+ modRoot = new File("reloader-test-mods");
+ modRoot.mkdir();
+ red = new Redeployer(vertx, modRoot, reloader);
+ }
+
+ protected void tearDown() throws Exception {
+ red.close();
+ vertx.fileSystem().deleteSync(modRoot.getAbsolutePath(), true);
+ super.tearDown();
+ }
+
+ @Test
+ public void tesCreateFile() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ createFile(modDir, "blah.txt", TestUtils.randomAlphaString(1000));
+ waitReload(dep);
+ }
+
+ @Test
+ public void testModifyFile() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ modifyFile(modDir, "blah.txt");
+ waitReload(dep);
+ }
+
+ @Test
+ public void testDeleteFile() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ createFile(modDir, "blah.txt", TestUtils.randomAlphaString(1000));
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ deleteFile(modDir, "blah.txt");
+ waitReload(dep);
+ }
+
+ @Test
+ public void testCreateDirectory() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ createDirectory(modDir, "some-dir");
+ waitReload(dep);
+ }
+
+ @Test
+ public void testCreateFileInSubDirectory() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ createDirectory(modDir, "some-dir");
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ File subDir = new File(modDir, "some-dir");
+ createFile(subDir, "bar.txt", TestUtils.randomAlphaString(1000));
+ waitReload(dep);
+ }
+
+ @Test
+ public void testDeleteFileInSubDirectory() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ createDirectory(modDir, "some-dir");
+ File subDir = new File(modDir, "some-dir");
+ createFile(subDir, "bar.txt", TestUtils.randomAlphaString(1000));
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ deleteFile(subDir, "bar.txt");
+ waitReload(dep);
+ }
+
+ @Test
+ public void testModifyFileInSubDirectory() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ createDirectory(modDir, "some-dir");
+ File subDir = new File(modDir, "some-dir");
+ createFile(subDir, "bar.txt", TestUtils.randomAlphaString(1000));
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ modifyFile(subDir, "bar.txt");
+ waitReload(dep);
+ }
+
+ @Test
+ public void testDeleteSubDir() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ createDirectory(modDir, "some-dir");
+ File subDir = new File(modDir, "some-dir");
+ createFile(subDir, "bar.txt", TestUtils.randomAlphaString(1000));
+ Deployment dep = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep);
+ Thread.sleep(500);
+ vertx.fileSystem().deleteSync(subDir.getAbsolutePath(), true);
+ waitReload(dep);
+ }
+
+ @Test
+ public void testReloadMultipleDeps() throws Exception {
+ String modName = "my-mod";
+ File modDir = createModDir(modName);
+ createModDir("other-mod");
+ createFile(modDir, "foo.js", TestUtils.randomAlphaString(1000));
+ Deployment dep1 = createDeployment("dep1", "my-mod", null);
+ red.moduleDeployed(dep1);
+ Deployment dep2 = createDeployment("dep2", "my-mod", null);
+ red.moduleDeployed(dep2);
+ Deployment dep3 = createDeployment("dep3", "other-mod", null);
+ red.moduleDeployed(dep3);
+ Thread.sleep(500);
+ createFile(modDir, "blah.txt", TestUtils.randomAlphaString(1000));
+ waitReload(dep1, dep2);
+ }
+
+ private File createModDir(String modName) {
+ File modDir = new File(modRoot, modName);
+ modDir.mkdir();
+ return modDir;
+ }
+
+ private void createFile(File dir, String fileName, String content) throws Exception {
+ File f = new File(dir, fileName);
+ vertx.fileSystem().writeFileSync(f.getAbsolutePath(), new Buffer(content));
+ }
+
+ private void modifyFile(File dir, String fileName) throws Exception {
+ File f = new File(dir, fileName);
+ FileWriter fw = new FileWriter(f, true);
+ fw.write(TestUtils.randomAlphaString(500));
+ fw.close();
+ }
+
+ private void deleteFile(File dir, String fileName) throws Exception {
+ File f = new File(dir, fileName);
+ f.delete();
+ }
+
+ private void createDirectory(File dir, String dirName) throws Exception {
+ File f = new File(dir, dirName);
+ vertx.fileSystem().mkdirSync(f.getAbsolutePath());
+ }
+
+ private void waitReload(Deployment... deps) throws Exception {
+ Set<Deployment> set = new HashSet<>();
+ for (Deployment dep: deps) {
+ set.add(dep);
+ }
+ reloader.waitReload(set);
+ }
+
+ class TestReloader implements ModuleReloader {
+
+ Set<Deployment> reloaded = new ConcurrentHashSet<>();
+ CountDownLatch latch = new CountDownLatch(1);
+
+ @Override
+ public void reloadModules(Set<Deployment> deps) {
+ reloaded.addAll(deps);
+ latch.countDown();
+ }
+
+ void waitReload(Set<Deployment> deps) throws Exception {
+ if (!reloaded.isEmpty()) {
+ checkDeps(deps);
+ } else {
+ if (!latch.await(5, TimeUnit.SECONDS)) {
+ throw new IllegalStateException("Time out");
+ }
+ checkDeps(deps);
+ }
+ }
+
+ private void checkDeps(Set<Deployment> deps) {
+ assertEquals(deps.size(), reloaded.size());
+ for (Deployment dep: deps) {
+ assertTrue(reloaded.contains(dep));
+ }
+ }
+ }
+
+ private Deployment createDeployment(String name, String modName, String parentName) {
+ return new Deployment(name, modName, 1, null, null, null, null, parentName, true);
+ }
+
+
+}
View
1  vertx-testsuite/src/test/python_scripts/core/buffer/test_client.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import vertx
from test_utils import TestUtils
from core.buffer import Buffer
View
1  vertx-testsuite/src/test/python_scripts/core/filesystem/test_client.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import vertx
from test_utils import TestUtils
from core.buffer import Buffer
from core.file_system import FileSystem
View
1  vertx-testsuite/src/test/python_scripts/core/isolation/test_client.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import vertx
from test_utils import TestUtils
tu = TestUtils()
View
1  vertx-testsuite/src/test/python_scripts/core/parsetools/test_client.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import vertx
from test_utils import TestUtils
from core.parsetools import RecordParser
from core.buffer import Buffer
View
1  vertx-testsuite/src/test/python_scripts/core/scriptloading/test_client.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import vertx
from test_utils import TestUtils
tu = TestUtils()
View
1  vertx-testsuite/src/test/python_scripts/core/shareddata/test_client.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import vertx
from test_utils import TestUtils
from core.shared_data import SharedData
from core.buffer import Buffer
Please sign in to comment.
Something went wrong with that request. Please try again.