Moving fix by Tony Tkacik in the stable/lithium branch which caused an error with...
[packetcable.git] / packetcable-emulator / src / main / java / org / pcmm / rcd / impl / CMTS.java
1 /*
2  * (c) 2015 Cable Television Laboratories, Inc.  All rights reserved.
3  */
4
5 package org.pcmm.rcd.impl;
6
7 import com.fasterxml.jackson.annotation.JsonProperty;
8 import com.fasterxml.jackson.databind.ObjectMapper;
9 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
10 import org.pcmm.gates.IGateSpec.Direction;
11 import org.pcmm.rcd.ICMTS;
12
13 import java.io.FileInputStream;
14 import java.io.IOException;
15 import java.net.Socket;
16 import java.util.*;
17 import java.util.concurrent.ConcurrentHashMap;
18
19 /**
20  * Mock CMTS that can be used for testing. startServer() is called to start required threads after instantiation.
21  */
22 public class CMTS extends AbstractPCMMServer implements ICMTS {
23
24         /**
25          * Receives messages from the COPS client
26          */
27         private final Map<String, IPCMMClientHandler> handlerMap;
28
29         /**
30          * The configured gates
31          */
32         private final Map<Direction, Set<String>> gateConfig;
33
34         /**
35          * The connected CMTSs and whether or not they are up
36          */
37         private final Map<String, Boolean> cmStatus;
38
39         /**
40          * Constructor for having the server port automatically assigned
41          * Call getPort() after startServer() is called to determine the port number of the server
42          */
43         public CMTS(final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
44                 this(0, gateConfig, cmStatus);
45         }
46
47         /**
48          * Constructor for starting the server to a pre-defined port number
49          * @param port - the port number on which to start the server.
50          */
51         public CMTS(final int port, final Map<Direction, Set<String>> gateConfig, final Map<String, Boolean> cmStatus) {
52                 super(port);
53                 if (gateConfig == null || cmStatus == null) throw new IllegalArgumentException("Config must not be null");
54                 this.gateConfig = Collections.unmodifiableMap(gateConfig);
55                 this.cmStatus = Collections.unmodifiableMap(cmStatus);
56                 handlerMap = new ConcurrentHashMap<>();
57         }
58
59         @Override
60         public void stopServer() {
61                 for (final IPCMMClientHandler handler : handlerMap.values()) {
62                         handler.stop();
63                 }
64                 super.stopServer();
65         }
66
67         @Override
68         protected IPCMMClientHandler getPCMMClientHandler(final Socket socket) throws IOException {
69                 final String key = socket.getLocalAddress().getHostName() + ':' + socket.getPort();
70                 if (handlerMap.get(key) == null) {
71                         final IPCMMClientHandler handler = new CmtsPcmmClientHandler(socket, gateConfig, cmStatus);
72                         handler.connect();
73                         handlerMap.put(key, handler);
74                         return handler;
75                 } else return handlerMap.get(key);
76         }
77
78         /**
79          * To start a CMTS
80          * @param args - the arguments which will contain configuration information
81          * @throws IOException - should the server fail to start for reasons such as port contention.
82          */
83         public static void main(final String[] args) throws IOException {
84                 final CmtsYaml config = getConfig(args[0]);
85                 final CMTS cmts = new CMTS(config.port, config.getGates(), config.getCmStatus());
86                 cmts.startServer();
87         }
88
89         /**
90          * Returns the object that represents the YAML file
91          * @param uri - the location of the YAML file
92          * @return - the config object
93          * @throws IOException - when the URI does not contain the proper YAML file
94          */
95         private static CmtsYaml getConfig(final String uri) throws IOException {
96                 final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
97                 return mapper.readValue(new FileInputStream(uri), CmtsYaml.class);
98         }
99
100         /**
101          * Class to hold configuration settings in a YAML file
102          */
103         public static class CmtsYaml {
104                 @JsonProperty("port")
105                 private int port;
106
107                 @JsonProperty("gates")
108                 private Collection<GateConfigYaml> gateConfigs;
109
110                 @JsonProperty("cmStatuses")
111                 private Collection<CmStatusYaml> cmStatuses;
112
113                 public Map<Direction, Set<String>> getGates() {
114                         final Map<Direction, Set<String>> out = new HashMap<>();
115
116                         for (final GateConfigYaml gateConfig : gateConfigs) {
117                                 final Direction direction;
118                                 if (gateConfig.gateType.equalsIgnoreCase("UPSTREAM")) {
119                                         direction = Direction.UPSTREAM;
120                                 } else if (gateConfig.gateType.equalsIgnoreCase("DOWNSTREAM")) {
121                                         direction = Direction.DOWNSTREAM;
122                                 } else direction = null;
123
124                                 if (direction != null) {
125                                         out.put(direction, gateConfig.gateNames);
126                                 }
127                         }
128                         return out;
129                 }
130
131                 public Map<String, Boolean> getCmStatus() {
132                         final Map<String, Boolean> out = new HashMap<>();
133
134                         for (final CmStatusYaml cmStatus : cmStatuses) {
135                                 out.put(cmStatus.hostIp, cmStatus.status);
136                         }
137                         return out;
138                 }
139         }
140
141         /**
142          * Class to hold the YAML gate configuration values
143          */
144         public static class GateConfigYaml {
145                 @JsonProperty("type")
146                 private String gateType;
147
148                 @JsonProperty("names")
149                 private Set<String> gateNames;
150         }
151
152         /**
153          * Class to hold the YAML Cable Modem configuration values
154          */
155         public static class CmStatusYaml {
156                 @JsonProperty("host")
157                 private String hostIp;
158
159                 @JsonProperty("status")
160                 private boolean status;
161         }
162
163 }