@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.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); } } } });
@Override public void onEvent(WatchFileEvent event) { if (event.getEventType() != FileEvent.DELETE) reload(configurator, url); } });
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); } }
/** * 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); } }
@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; }
@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(); }
@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 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); } }
/** * 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; }