Initial source code
[oam/tr069-adapter.git] / netconf-server / src / main / java / org / commscope / tr069adapter / netconf / server / helper / ServerPortAllocationHelper.java
1 /*\r
2  * ============LICENSE_START========================================================================\r
3  * ONAP : tr-069-adapter\r
4  * =================================================================================================\r
5  * Copyright (C) 2020 CommScope Inc Intellectual Property.\r
6  * =================================================================================================\r
7  * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,\r
8  * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You\r
9  * may obtain a copy of the License at\r
10  *\r
11  * http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
14  * either express or implied. See the License for the specific language governing permissions and\r
15  * limitations under the License.\r
16  * ===============LICENSE_END=======================================================================\r
17  */\r
18 \r
19 package org.commscope.tr069adapter.netconf.server.helper;\r
20 \r
21 import java.io.IOException;\r
22 import java.net.Socket;\r
23 import java.util.HashMap;\r
24 import java.util.Map;\r
25 import java.util.PriorityQueue;\r
26 import java.util.concurrent.Semaphore;\r
27 \r
28 import javax.annotation.PostConstruct;\r
29 \r
30 import org.commscope.tr069adapter.netconf.config.NetConfServerProperties;\r
31 import org.commscope.tr069adapter.netconf.error.ServerPortAllocationException;\r
32 import org.slf4j.Logger;\r
33 import org.slf4j.LoggerFactory;\r
34 import org.springframework.beans.factory.annotation.Autowired;\r
35 import org.springframework.stereotype.Component;\r
36 \r
37 @Component\r
38 public class ServerPortAllocationHelper {\r
39 \r
40   private static final Logger LOG = LoggerFactory.getLogger(ServerPortAllocationHelper.class);\r
41 \r
42   private static Map<String, Semaphore> semaphoreMap = new HashMap<>();\r
43 \r
44   private PriorityQueue<String> availablePorts = new PriorityQueue<>();\r
45 \r
46   @Autowired\r
47   NetConfServerProperties config;\r
48 \r
49   @PostConstruct\r
50   public void init() {\r
51     // read the port range and it the available ports.\r
52 \r
53     Integer startPort = config.getDefaultNetconfStartPort();\r
54     Integer maxServers = config.getDefaultMaxServers();\r
55 \r
56     try {\r
57       startPort = Integer.parseInt(config.getNetconfServersStartPort());\r
58     } catch (Exception e) {\r
59       LOG.warn(\r
60           "Failed to initialize the starting port from the environment {}. Hence using the default port range.",\r
61           config.getNetconfServersStartPort());\r
62     }\r
63 \r
64     try {\r
65       maxServers = Integer.parseInt(config.getMaxNumOfNetconfServers());\r
66     } catch (Exception e) {\r
67       LOG.warn(\r
68           "Failed to initialize the max netconf server from the environment {} Hence using the default max servers.",\r
69           config.getMaxNumOfNetconfServers());\r
70     }\r
71 \r
72     for (int i = startPort + maxServers - 1; i >= startPort; i--) {\r
73       semaphoreMap.put(String.valueOf(i), new Semaphore(1));\r
74       availablePorts.add(String.valueOf(i));\r
75     }\r
76     LOG.debug("Successfully populated available ports list.");\r
77   }\r
78 \r
79   public String reserveServerPort() throws ServerPortAllocationException {\r
80 \r
81     if (availablePorts.isEmpty()) {\r
82       LOG.debug(\r
83           "All ports are exhausted. Hence cannot allocate a port to start new netconf server.");\r
84     }\r
85 \r
86     String port = availablePorts.peek();\r
87 \r
88     LOG.debug("Trying to reserve port : {}", port);\r
89     if (isServerPortInUse(port)) {\r
90       LOG.debug("Port {} is already in use.", port);\r
91       return reserveServerPort(); // retry if current port is not available\r
92     }\r
93 \r
94     Semaphore semaphore = semaphoreMap.get(port);\r
95     boolean isAcquired = semaphore.tryAcquire();\r
96     if (isAcquired) {\r
97       LOG.debug("Failed to acquire a lock for port :{}. Hence retrying...", port);\r
98       return reserveServerPort();\r
99     }\r
100 \r
101     availablePorts.poll();\r
102     semaphore.release();\r
103     LOG.debug("Rserved port is {}", port);\r
104     return port;\r
105   }\r
106 \r
107   public boolean checkAndReserveServerPort(String port) {\r
108 \r
109     try {\r
110       Semaphore semaphore = semaphoreMap.get(port);\r
111       semaphore.acquire();\r
112       if (isServerPortInUse(port)) {\r
113         LOG.error("Port {}  already in use.", port);\r
114         semaphore.release();\r
115         return false;\r
116       }\r
117       availablePorts.remove(port);\r
118       semaphore.release();\r
119       LOG.error("Successfully reserved the port {} to start netconf server", port);\r
120     } catch (InterruptedException e) {\r
121       Thread.currentThread().interrupt();\r
122       LOG.error("Failed to lock the port {} : Exception :{}", port, e.toString());\r
123       return checkAndReserveServerPort(port); // retry acquiring the lock.\r
124     }\r
125 \r
126     return true;\r
127   }\r
128 \r
129   public boolean isServerPortInUse(String port) {\r
130     return checkIfPortAvailable(port);\r
131   }\r
132 \r
133   private static boolean checkIfPortAvailable(String portStr) {\r
134     Integer port = Integer.parseInt(portStr);\r
135     try (Socket ignored = new Socket("localhost", port)) {\r
136       return true;\r
137     } catch (IOException e) {\r
138       LOG.error("while checkIfPortAvailable {}", e.toString());\r
139       return false;\r
140     }\r
141   }\r
142 }\r