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