Moved CMTS emulator to its own module so it can either be run standalone or be used...
[packetcable.git] / packetcable-emulator / src / main / java / org / pcmm / rcd / impl / CMTS.java
diff --git a/packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CMTS.java b/packetcable-emulator/src/main/java/org/pcmm/rcd/impl/CMTS.java
new file mode 100644 (file)
index 0000000..e53439e
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * (c) 2015 Cable Television Laboratories, Inc.  All rights reserved.
+ */
+
+package org.pcmm.rcd.impl;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import org.pcmm.gates.IGateSpec.Direction;
+import org.pcmm.rcd.ICMTS;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Mock CMTS that can be used for testing. startServer() is called to start required threads after instantiation.
+ */
+public class CMTS extends AbstractPCMMServer implements ICMTS {
+
+       /**
+        * Receives messages from the COPS client
+        */
+       private final Map<String, IPCMMClientHandler> handlerMap;
+
+       /**
+        * The configured gates
+        */
+       private final Map<Direction, Set<String>> gateConfig;
+
+       /**
+        * The connected CMTSs and whether or not they are up
+        */
+       private final Map<String, Boolean> cmStatus;
+
+       /**
+        * Constructor for having the server port automatically assigned
+        * Call getPort() after startServer() is called to determine the port number of the server
+        */
+       public CMTS(final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
+               this(0, gateConfig, cmStatus);
+       }
+
+       /**
+        * Constructor for starting the server to a pre-defined port number
+        * @param port - the port number on which to start the server.
+        */
+       public CMTS(final int port, final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
+               super(port);
+               if (gateConfig == null || cmStatus == null) throw new IllegalArgumentException("Config must not be null");
+               this.gateConfig = Collections.unmodifiableMap(gateConfig);
+               this.cmStatus = Collections.unmodifiableMap(cmStatus);
+               handlerMap = new ConcurrentHashMap<>();
+       }
+
+       @Override
+       public void stopServer() {
+               for (final IPCMMClientHandler handler : handlerMap.values()) {
+                       handler.stop();
+               }
+               super.stopServer();
+       }
+
+       @Override
+       protected IPCMMClientHandler getPCMMClientHandler(final Socket socket) throws IOException {
+               final String key = socket.getLocalAddress().getHostName() + ':' + socket.getPort();
+               if (handlerMap.get(key) == null) {
+                       final IPCMMClientHandler handler = new CmtsPcmmClientHandler(socket, gateConfig, cmStatus);
+                       handler.connect();
+                       handlerMap.put(key, handler);
+                       return handler;
+               } else return handlerMap.get(key);
+       }
+
+       /**
+        * To start a CMTS
+        * @param args - the arguments which will contain configuration information
+        * @throws IOException - should the server fail to start for reasons such as port contention.
+        */
+       public static void main(final String[] args) throws IOException {
+               final CmtsYaml config = getConfig(args[0]);
+               final CMTS cmts = new CMTS(config.port, config.getGates(), config.getCmStatus());
+               cmts.startServer();
+       }
+
+       /**
+        * Returns the object that represents the YAML file
+        * @param uri - the location of the YAML file
+        * @return - the config object
+        * @throws IOException - when the URI does not contain the proper YAML file
+        */
+       private static CmtsYaml getConfig(final String uri) throws IOException {
+               final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+               return mapper.readValue(new FileInputStream(uri), CmtsYaml.class);
+       }
+
+       /**
+        * Class to hold configuration settings in a YAML file
+        */
+       public static class CmtsYaml {
+               @JsonProperty("port")
+               private int port;
+
+               @JsonProperty("gates")
+               private Collection<GateConfigYaml> gateConfigs;
+
+               @JsonProperty("cmStatuses")
+               private Collection<CmStatusYaml> cmStatuses;
+
+               public Map<Direction, Set<String>> getGates() {
+                       final Map<Direction, Set<String>> out = new HashMap<>();
+
+                       for (final GateConfigYaml gateConfig : gateConfigs) {
+                               final Direction direction;
+                               if (gateConfig.gateType.equalsIgnoreCase("UPSTREAM")) {
+                                       direction = Direction.UPSTREAM;
+                               } else if (gateConfig.gateType.equalsIgnoreCase("DOWNSTREAM")) {
+                                       direction = Direction.DOWNSTREAM;
+                               } else direction = null;
+
+                               if (direction != null) {
+                                       out.put(direction, gateConfig.gateNames);
+                               }
+                       }
+                       return out;
+               }
+
+               public Map<String, Boolean> getCmStatus() {
+                       final Map<String, Boolean> out = new HashMap<>();
+
+                       for (final CmStatusYaml cmStatus : cmStatuses) {
+                               out.put(cmStatus.hostIp, cmStatus.status);
+                       }
+                       return out;
+               }
+       }
+
+       /**
+        * Class to hold the YAML gate configuration values
+        */
+       public static class GateConfigYaml {
+               @JsonProperty("type")
+               private String gateType;
+
+               @JsonProperty("names")
+               private Set<String> gateNames;
+       }
+
+       /**
+        * Class to hold the YAML Cable Modem configuration values
+        */
+       public static class CmStatusYaml {
+               @JsonProperty("host")
+               private String hostIp;
+
+               @JsonProperty("status")
+               private boolean status;
+       }
+
+}