Fix removal of chains.
[rhynodge.git] / src / main / java / net / pterodactylus / reactor / loader / ChainWatcher.java
index aa8b7b4..3d30f26 100644 (file)
@@ -19,9 +19,12 @@ package net.pterodactylus.reactor.loader;
 
 import java.io.File;
 import java.io.FilenameFilter;
+import java.io.IOException;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import net.pterodactylus.reactor.Reaction;
@@ -30,16 +33,17 @@ import net.pterodactylus.reactor.loader.Chain.Parameter;
 import net.pterodactylus.reactor.loader.Chain.Part;
 
 import org.apache.log4j.Logger;
-import org.simpleframework.xml.Serializer;
-import org.simpleframework.xml.core.Persister;
 
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Maps;
 import com.google.common.util.concurrent.AbstractExecutionThreadService;
 import com.google.common.util.concurrent.Uninterruptibles;
 
 /**
- * Watches a directory for chain XML files and loads and unloads
+ * Watches a directory for chain configuration files and loads and unloads
  * {@link Reaction}s from the {@link Engine}.
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
@@ -49,13 +53,16 @@ public class ChainWatcher extends AbstractExecutionThreadService {
        /** The logger. */
        private static final Logger logger = Logger.getLogger(ChainWatcher.class);
 
+       /** The JSON object mapper. */
+       private static final ObjectMapper objectMapper = new ObjectMapper();
+
        /** The reaction loader. */
        private final ReactionLoader reactionLoader = new ReactionLoader();
 
        /** The engine to load reactions with. */
        private final Engine engine;
 
-       /** The directory to watch for chain XML files. */
+       /** The directory to watch for chain configuration files. */
        private final String directory;
 
        /**
@@ -93,47 +100,51 @@ public class ChainWatcher extends AbstractExecutionThreadService {
                                continue;
                        }
 
-                       /* list all files, scan for XMLs. */
+                       /* list all files, scan for configuration files. */
                        logger.debug(String.format("Scanning %s...", directory));
-                       File[] xmlFiles = directoryFile.listFiles(new FilenameFilter() {
+                       File[] configurationFiles = directoryFile.listFiles(new FilenameFilter() {
 
                                @Override
                                public boolean accept(File dir, String name) {
-                                       return name.endsWith(".xml");
+                                       return name.endsWith(".json");
                                }
                        });
-                       logger.debug(String.format("Found %d XML file(s), parsing...", xmlFiles.length));
+                       logger.debug(String.format("Found %d configuration file(s), parsing...", configurationFiles.length));
 
                        /* now parse all XML files. */
                        Map<String, Chain> chains = new HashMap<String, Chain>();
-                       for (File xmlFile : xmlFiles) {
-                               Serializer serializer = new Persister();
-                               logger.debug(String.format("Reading %s...", xmlFile.getPath()));
-                               Chain chain = serializer.read(Chain.class, xmlFile);
+                       for (File configurationFile : configurationFiles) {
+
+                               /* parse XML file. */
+                               Chain chain = parseConfigurationFile(configurationFile);
+                               if (chain == null) {
+                                       logger.warn(String.format("Could not parse %s.", configurationFile));
+                                       continue;
+                               }
 
                                /* dump chain */
                                logger.debug(String.format(" Enabled: %s", chain.enabled()));
 
-                               System.out.println(String.format(" Query: %s", chain.query().name()));
+                               logger.debug(String.format(" Query: %s", chain.query().name()));
                                for (Parameter parameter : chain.query().parameters()) {
-                                       System.out.println(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
+                                       logger.debug(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
                                }
                                for (Part filter : chain.filters()) {
-                                       System.out.println(String.format(" Filter: %s", filter.name()));
+                                       logger.debug(String.format(" Filter: %s", filter.name()));
                                        for (Parameter parameter : filter.parameters()) {
-                                               System.out.println(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
+                                               logger.debug(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
                                        }
                                }
-                               System.out.println(String.format(" Trigger: %s", chain.trigger().name()));
+                               logger.debug(String.format(" Trigger: %s", chain.trigger().name()));
                                for (Parameter parameter : chain.trigger().parameters()) {
-                                       System.out.println(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
+                                       logger.debug(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
                                }
-                               System.out.println(String.format(" Action: %s", chain.action().name()));
+                               logger.debug(String.format(" Action: %s", chain.action().name()));
                                for (Parameter parameter : chain.action().parameters()) {
-                                       System.out.println(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
+                                       logger.debug(String.format("  Parameter: %s=%s", parameter.name(), parameter.value()));
                                }
 
-                               chains.put(xmlFile.getName(), chain);
+                               chains.put(getReactionName(configurationFile.getName()), chain);
                        }
 
                        /* filter enabled chains. */
@@ -147,6 +158,7 @@ public class ChainWatcher extends AbstractExecutionThreadService {
                        logger.debug(String.format("Found %d enabled Chain(s).", enabledChains.size()));
 
                        /* check for removed chains. */
+                       Set<String> chainsToRemove = new HashSet<String>();
                        for (Entry<String, Chain> loadedChain : loadedChains.entrySet()) {
 
                                /* skip chains that still exist. */
@@ -156,7 +168,12 @@ public class ChainWatcher extends AbstractExecutionThreadService {
 
                                logger.info(String.format("Removing Chain: %s", loadedChain.getKey()));
                                engine.removeReaction(loadedChain.getKey());
-                               loadedChains.remove(loadedChain.getKey());
+                               chainsToRemove.add(loadedChain.getKey());
+                       }
+
+                       /* remove removed chains from loaded chains. */
+                       for (String reactionName : chainsToRemove) {
+                               loadedChains.remove(reactionName);
                        }
 
                        /* check for new chains. */
@@ -179,4 +196,39 @@ public class ChainWatcher extends AbstractExecutionThreadService {
                }
        }
 
+       //
+       // STATIC METHODS
+       //
+
+       /**
+        * Parses the given configuration file into a {@link Chain}.
+        *
+        * @param configurationFile
+        *            The configuration file to parse
+        * @return The parsed chain
+        */
+       private static Chain parseConfigurationFile(File configurationFile) {
+               try {
+                       return objectMapper.readValue(configurationFile, Chain.class);
+               } catch (JsonParseException jpe1) {
+                       logger.warn(String.format("Could not parse %s.", configurationFile), jpe1);
+               } catch (JsonMappingException jme1) {
+                       logger.warn(String.format("Could not parse %s.", configurationFile), jme1);
+               } catch (IOException ioe1) {
+                       logger.info(String.format("Could not read %s.", configurationFile));
+               }
+               return null;
+       }
+
+       /**
+        * Extracts the name of the reaction from the given filename.
+        *
+        * @param filename
+        *            The filename to extract the reaction name from
+        * @return The name of the reaction
+        */
+       private static String getReactionName(String filename) {
+               return (filename.lastIndexOf(".") > -1) ? filename.substring(0, filename.lastIndexOf(".")) : filename;
+       }
+
 }