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