1c5f2a3a6551faa756814a0249e523ac27b6e121
[policy/apex-pdp.git] / core / core-infrastructure / src / main / java / org / onap / policy / apex / core / infrastructure / messaging / util / MessagingUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019 Nordix Foundation.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.core.infrastructure.messaging.util;
23
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.io.ObjectOutputStream;
27 import java.net.InetAddress;
28 import java.net.NetworkInterface;
29 import java.net.Socket;
30 import java.net.UnknownHostException;
31 import java.util.Enumeration;
32
33 import org.slf4j.ext.XLogger;
34 import org.slf4j.ext.XLoggerFactory;
35
36 /**
37  * The Class MessagingUtils is a class with static methods used in IPC messaging for finding free ports, translating
38  * host names to addresses, serializing objects and flushing object streams.
39  *
40  * @author Sajeevan Achuthan (sajeevan.achuthan@ericsson.com)
41  */
42 public final class MessagingUtils {
43     // The port number of the lowest user port, ports 0-1023 are system ports
44     private static final int LOWEST_USER_PORT = 1024;
45
46     /**
47      * Port number is an unsigned 16-bit integer, so maximum port is 65535.
48      */
49     private static final int MAX_PORT_RANGE = 65535;
50
51     // Logger for this class
52     private static final XLogger LOGGER = XLoggerFactory.getXLogger(MessagingUtils.class);
53
54     /**
55      * Private constructor used to prevent sub class instantiation.
56      */
57     private MessagingUtils() {
58         // Private constructor to block subclassing
59     }
60
61     /**
62      * This method searches the availability of the port, if the requested port not available, this method will throw an
63      * exception.
64      *
65      * @param port the port to check
66      * @return the port verified as being free
67      * @throws RuntimeException on port allocation errors
68      */
69     public static int checkPort(final int port) {
70         LOGGER.entry("Checking availability of  port {}", port);
71
72         if (isPortAvailable(port)) {
73             LOGGER.debug("Port {} is available ", port);
74             return port;
75         }
76         LOGGER.debug("Port {} is not available", port);
77         throw new IllegalArgumentException("could not allocate requested port: " + port);
78     }
79
80     /**
81      * This method searches the availability of the port, if the requested port not available,this method will increment
82      * the port number and check the availability of that port, this process will continue until it reaches max port
83      * range which is MAX_PORT_RANGE.
84      *
85      * @param port the first port to check
86      * @return the port that was found
87      * @throws RuntimeException on port allocation errors
88      */
89     public static int findPort(final int port) {
90         LOGGER.entry("Checking availability of  port {}", port);
91
92         int availablePort = port;
93
94         while (availablePort <= MAX_PORT_RANGE) {
95             if (isPortAvailable(availablePort)) {
96                 LOGGER.debug("Port {} is available ", availablePort);
97                 return availablePort;
98             }
99             LOGGER.debug("Port {} is not available", availablePort);
100             availablePort++;
101         }
102         throw new IllegalArgumentException("could not find free available");
103     }
104
105     /**
106      * Check if port is available or not.
107      *
108      * @param port the port to test
109      * @return true if port is available
110      */
111     public static boolean isPortAvailable(final int port) {
112         try (final Socket socket = new Socket("localhost", port)) {
113             return false;
114         } catch (final IOException ignoredException) {
115             LOGGER.trace("Port {} is available", port, ignoredException);
116             return true;
117         }
118     }
119
120     /**
121      * Returns the local host address.
122      *
123      * @return the local host address
124      * @throws IllegalStateException if the local host's address cannot be found
125      */
126     public static InetAddress getHost() {
127         try {
128             return InetAddress.getLocalHost();
129         } catch (final UnknownHostException e) {
130             throw new IllegalStateException(e.getMessage(), e);
131         }
132     }
133
134     /**
135      * This method searches the availability of the port, if the requested port not available,this method will increment
136      * the port number and check the availability, this process will continue until it find port available.
137      *
138      * @param port the first port to check
139      * @return the port that was found
140      * @throws RuntimeException on port allocation errors
141      */
142     public static int allocateAddress(final int port) {
143         if (port < LOWEST_USER_PORT) {
144             throw new IllegalArgumentException("The port " + port + "  is already in use");
145         }
146         return MessagingUtils.findPort(port);
147     }
148
149     /**
150      * Get an Internet Address for the local host.
151      *
152      * @return an Internet address
153      * @throws UnknownHostException if the address of the local host cannot be found
154      */
155     public static InetAddress getLocalHostLanAddress() throws UnknownHostException {
156         try {
157             InetAddress candidateAddress = null;
158             // Iterate all NICs (network interface cards)...
159             for (final Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces
160                     .hasMoreElements();) {
161                 final NetworkInterface iface = ifaces.nextElement();
162                 // Iterate all IP addresses assigned to each card...
163                 for (final Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs
164                         .hasMoreElements();) {
165                     final InetAddress inetAddr = inetAddrs.nextElement();
166                     if (!inetAddr.isLoopbackAddress()) {
167
168                         if (inetAddr.isSiteLocalAddress()) {
169                             // Found non-loopback site-local address. Return it
170                             // immediately...
171                             return inetAddr;
172                         } else if (candidateAddress == null) {
173                             // Found non-loopback address, but not
174                             // necessarily site-local.
175                             // Store it as a candidate to be returned if
176                             // site-local address is not subsequently
177                             // found...
178                             candidateAddress = inetAddr;
179                             // Note that we don't repeatedly assign
180                             // non-loopback non-site-local addresses as
181                             // candidates,
182                             // only the first. For subsequent iterations,
183                             // candidate will be non-null.
184                         }
185                     }
186                 }
187             }
188             if (candidateAddress != null) {
189                 // We did not find a site-local address, but we found some other
190                 // non-loopback address.
191                 // Server might have a non-site-local address assigned to its
192                 // NIC (or it might be running
193                 // IPv6 which deprecates the "site-local" concept).
194                 // Return this non-loopback candidate address...
195                 return candidateAddress;
196             }
197             // At this point, we did not find a non-loopback address.
198             // Fall back to returning whatever InetAddress.getLocalHost()
199             // returns...
200             final InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
201             if (jdkSuppliedAddress == null) {
202                 throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
203             }
204             return jdkSuppliedAddress;
205         } catch (final Exception e) {
206             final UnknownHostException unknownHostException =
207                     new UnknownHostException("Failed to determine LAN address: " + e);
208             unknownHostException.initCause(e);
209             throw unknownHostException;
210         }
211     }
212
213     /**
214      * This method serializes the message holder objects.
215      *
216      * @param object the object
217      * @return byte[]
218      */
219     public static byte[] serializeObject(final Object object) {
220         LOGGER.entry(object.getClass().getName());
221         final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
222         ObjectOutputStream oos = null;
223         try {
224             oos = new ObjectOutputStream(bytesOut);
225             oos.writeObject(object);
226         } catch (final IOException e) {
227             LOGGER.warn("error on object serialization", e);
228         } finally {
229             flushAndClose(oos, bytesOut);
230         }
231         return bytesOut.toByteArray();
232     }
233
234     /**
235      * Flush and close an object stream and a byte array output stream.
236      *
237      * @param oos the object output stream
238      * @param bytesOut the byte array output stream
239      */
240     private static void flushAndClose(final ObjectOutputStream oos, final ByteArrayOutputStream bytesOut) {
241         try {
242             if (oos != null) {
243                 oos.flush();
244                 oos.close();
245             }
246             if (bytesOut != null) {
247                 bytesOut.close();
248             }
249
250         } catch (final IOException e) {
251             LOGGER.error("Failed to close the Srialization operation");
252             LOGGER.catching(e);
253         }
254     }
255 }