/* * (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 handlerMap; /** * The configured gates */ private final Map> gateConfig; /** * The connected CMTSs and whether or not they are up */ private final Map 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> gateConfig, final Map 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> gateConfig, final Map 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 gateConfigs; @JsonProperty("cmStatuses") private Collection cmStatuses; public Map> getGates() { final Map> 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 getCmStatus() { final Map 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 gateNames; } /** * Class to hold the YAML Cable Modem configuration values */ public static class CmStatusYaml { @JsonProperty("host") private String hostIp; @JsonProperty("status") private boolean status; } }