@Override public void onEvent(WatchFileEvent event) { if (event.getEventType() != FileEvent.DELETE && registeredURIs.contains(event.getURI())) { reload(event.getURI()); } } });
@Override public void onEvent(WatchFileEvent event) { if (event.getEventType() != FileEvent.DELETE) reload(configurator, url); } });
public static void close(ClassLoader classLoader) { Map<String, ClassLoader> registerMap = extraRepositories.remove(classLoader); if (registerMap != null) { for (ClassLoader loader : registerMap.values()) { PluginManager.getInstance().getWatcher().closeClassLoader(loader); } } }
/** * Callback method from ch.qos.logback.core.joran.GenericConfigurator. * * @param configurator the configurator object * @param url configuration file url */ public void initLogback(final Object configurator, final URL url) { try { final URI uri = url.toURI(); // skip double registration on reload if (registeredURIs.contains(uri)) return; LOGGER.debug("Watching '{}' URL for Logback configuration changes.", url); registeredURIs.add(uri); watcher.addEventListener(appClassLoader, uri, new WatchEventListener() { @Override public void onEvent(WatchFileEvent event) { if (event.getEventType() != FileEvent.DELETE) reload(configurator, url); } }); } catch (Exception e) { LOGGER.error("Exception initializing logback configurator {} on url {}.", e, configurator, url); } }
@Override public void onEvent(WatchFileEvent event) { if (event.isFile() && event.getURI().toString().endsWith(".class")) { // check that the class is not loaded by the classloader yet (avoid duplicate reload) String className; try { className = IOUtils.urlToClassName(event.getURI()); } catch (IOException e) { LOGGER.trace("Watch event on resource '{}' skipped, probably Ok because of delete/create event sequence (compilation not finished yet).", e, event.getURI()); return; } if (!ClassLoaderHelper.isClassLoaded(appClassLoader, className)) { // refresh spring only for new classes scheduler.scheduleCommand(new ClassPathBeanRefreshCommand(appClassLoader, basePackage, className, event), WAIT_ON_CREATE); } } } });
public BeanClassRefreshCommand(ClassLoader classLoader, String normalizedArchivePath, WatchFileEvent event) { this.classLoader = classLoader; this.archivePath = normalizedArchivePath; this.event = event; // strip from URI prefix up to basePackage and .class suffix. String classFullPath = event.getURI().getPath(); int index = classFullPath.indexOf(normalizedArchivePath); if (index == 0) { // Strip archive path from beginning and .class from the end to get class name from full path to class file String classPath = classFullPath.substring(normalizedArchivePath.length()); classPath = classPath.substring(0, classPath.indexOf(".class")); if (classPath.startsWith("/")) { classPath = classPath.substring(1); } this.className = classPath.replace("/", "."); } else { LOGGER.error("Archive path '{}' doesn't match with classFullPath '{}'", normalizedArchivePath, classFullPath); } }
LOGGER.debug("Watching '{}' URI for Log4j2 configuration changes.", configURI); registeredURIs.add(configURI); watcher.addEventListener(appClassLoader, parentUri, new WatchEventListener() {
@Override public void onEvent(WatchFileEvent event) { if (event.isFile() && event.getURI().toString().endsWith(".class")) { // check that the class is not loaded by the classloader yet (avoid duplicate reload) String className; try { className = IOUtils.urlToClassName(event.getURI()); } catch (IOException e) { LOGGER.trace("Watch event on resource '{}' skipped, probably Ok because of delete/create event sequence (compilation not finished yet).", e, event.getURI()); return; } if (!ClassLoaderHelper.isClassLoaded(appClassLoader, className) || isTestEnvironment) { // refresh weld only for new classes LOGGER.trace("register reload command: {} ", className); scheduler.scheduleCommand(new BeanClassRefreshCommand(appClassLoader, archivePath, beanArchiveUrl, event), WAIT_ON_CREATE); } } } });
/** * Check all merged events with same className for delete and create events. If delete without create is found, than assume * file was deleted. * @param mergedCommands */ private boolean isDeleteEvent(List<Command> mergedCommands) { boolean createFound = false; boolean deleteFound = false; for (Command cmd : mergedCommands) { BeanClassRefreshCommand refreshCommand = (BeanClassRefreshCommand) cmd; if (className.equals(refreshCommand.className)) { if (refreshCommand.event != null) { if (refreshCommand.event.getEventType().equals(FileEvent.DELETE)) deleteFound = true; if (refreshCommand.event.getEventType().equals(FileEvent.CREATE)) createFound = true; } } } LOGGER.trace("isDeleteEvent result {}: createFound={}, deleteFound={}", createFound, deleteFound); return !createFound && deleteFound; }
/** * Instantiates a new bean class refresh command. * * @param appClassLoader the application class loader * @param archivePath the archive path * @param beanArchiveUrl the bean archive url * @param event the class event */ public BeanClassRefreshCommand(ClassLoader appClassLoader, String archivePath, URL beanArchiveUrl, WatchFileEvent event) { this.appClassLoader = appClassLoader; this.event = event; this.beanArchiveUrl = beanArchiveUrl; String classFullPath = event.getURI().getPath(); int index = classFullPath.indexOf(archivePath); if (index == 0) { // Strip archive path from beginning and .class from the end to get class name from full path to class file String classPath = classFullPath.substring(archivePath.length()); classPath = classPath.substring(0, classPath.indexOf(".class")); if (classPath.startsWith("/")) { classPath = classPath.substring(1); } this.className = classPath.replace("/", "."); } else { LOGGER.error("Archive path '{}' doesn't match with classFullPath '{}'", archivePath, classFullPath); } }
watcher.addEventListener(appClassLoader, uri, new WatchEventListener() { @Override public void onEvent(WatchFileEvent event) {
@Override public void onEvent(WatchFileEvent event) { if (event.isFile() && event.getURI().toString().endsWith(".class")) { // check that the class is not loaded by the classloader yet (avoid duplicate reload) String className; try { className = IOUtils.urlToClassName(event.getURI()); } catch (IOException e) { LOGGER.trace("Watch event on resource '{}' skipped, probably Ok because of delete/create event sequence (compilation not finished yet).", e, event.getURI()); return; } if (!ClassLoaderHelper.isClassLoaded(appClassLoader, className) || isTestEnvironment) { // refresh weld only for new classes LOGGER.trace("Register reload command: {} ", className); if (isBdaRegistered(appClassLoader, archivePath)) { // TODO : Create proxy factory scheduler.scheduleCommand(new BeanClassRefreshCommand(appClassLoader, archivePath, event), WAIT_ON_CREATE); } } } } });
/** * Check all merged events with same className for delete and create events. If delete without create is found, than assume * file was deleted. * @param mergedCommands */ private boolean isDeleteEvent(List<Command> mergedCommands) { boolean createFound = false; boolean deleteFound = false; for (Command cmd : mergedCommands) { BeanClassRefreshCommand refreshCommand = (BeanClassRefreshCommand) cmd; if (className.equals(refreshCommand.className)) { if (refreshCommand.event != null) { if (refreshCommand.event.getEventType().equals(FileEvent.DELETE)) deleteFound = true; if (refreshCommand.event.getEventType().equals(FileEvent.CREATE)) createFound = true; } } } LOGGER.trace("isDeleteEvent result {}: createFound={}, deleteFound={}", createFound, deleteFound); return !createFound && deleteFound; }
@Override public void onEvent(WatchFileEvent event) { ClassPool pool = ClassPool.getDefault(); if (!event.getURI().getPath().endsWith(".class")) { return; } URI fileURI = event.getURI(); File classFile = new File(fileURI); CtClass ctClass = null; boolean doHotswap = false; try { ctClass = pool.makeClass(new FileInputStream(classFile)); doHotswap = equinoxPlugin.loadClassToTargetClassLoaders(ctClass, fileURI, true); } catch (Exception e) { LOGGER.warning("MakeClass exception : {}", e.getMessage()); } finally { if (ctClass != null) { ctClass.detach(); } } if (doHotswap) equinoxPlugin.scheduleHotswapCommand(); }
continue; } else { watcher.addEventListener(appClassLoader, basePackageURL, new WatchEventListener() { @Override public void onEvent(WatchFileEvent event) {
/** * Check all merged events with same className for create events. * @param mergedCommands */ private boolean isCreateEvent(List<Command> mergedCommands) { boolean createFound = false; for (Command cmd : mergedCommands) { BeanClassRefreshCommand refreshCommand = (BeanClassRefreshCommand) cmd; if (className.equals(refreshCommand.className)) { if (refreshCommand.event != null) { if (refreshCommand.event.getEventType().equals(FileEvent.CREATE)) createFound = true; } } } LOGGER.trace("isCreateEvent result {}: createFound={}", createFound); return createFound; }
@Override public void executeCommand() { if (isDeleteEvent()) { LOGGER.trace("Skip Spring reload for delete event on class '{}'", className); return; } try { if (classDefinition == null) { try { this.classDefinition = IOUtils.toByteArray(event.getURI()); } catch (IllegalArgumentException e) { LOGGER.debug("File {} not found on filesystem (deleted?). Unable to refresh associated Spring bean.", event.getURI()); return; } } LOGGER.debug("Executing ClassPathBeanDefinitionScannerAgent.refreshClass('{}')", className); Class<?> clazz = Class.forName("org.hotswap.agent.plugin.spring.scanner.ClassPathBeanDefinitionScannerAgent", true, appClassLoader); Method method = clazz.getDeclaredMethod( "refreshClass", new Class[] {String.class, byte[].class}); method.invoke(null, basePackage, classDefinition); } catch (NoSuchMethodException e) { throw new IllegalStateException("Plugin error, method not found", e); } catch (InvocationTargetException e) { LOGGER.error("Error refreshing class {} in classLoader {}", e, className, appClassLoader); } catch (IllegalAccessException e) { throw new IllegalStateException("Plugin error, illegal access", e); } catch (ClassNotFoundException e) { throw new IllegalStateException("Plugin error, Spring class not found in application classloader", e); } }
LOGGER.info("Initialize hotswap on URL {}.", uri); listener = new AutoHotswapPathEventListener(this); watcher.addEventListener(null, uri, listener); } catch (URISyntaxException e) { LOGGER.error("Unable to watch path '{}' for changes.", e, resource);
/** * Check all merged events for delete and create events. If delete without create is found, than assume * file was deleted. */ private boolean isDeleteEvent() { // for all merged commands including this command List<ClassPathBeanRefreshCommand> mergedCommands = new ArrayList<ClassPathBeanRefreshCommand>(); for (Command command : getMergedCommands()) { mergedCommands.add((ClassPathBeanRefreshCommand) command); } mergedCommands.add(this); boolean createFound = false; boolean deleteFound = false; for (ClassPathBeanRefreshCommand command : mergedCommands) { if (command.event != null) { if (command.event.getEventType().equals(FileEvent.DELETE)) deleteFound = true; if (command.event.getEventType().equals(FileEvent.CREATE)) createFound = true; } } LOGGER.trace("isDeleteEvent result {}: createFound={}, deleteFound={}", createFound, deleteFound); return !createFound && deleteFound; }
LOGGER.info("Registering archive path '{}'", archivePath); watcher.addEventListener(appClassLoader, uri, new WatchEventListener() { @Override public void onEvent(WatchFileEvent event) {