aboutsummaryrefslogtreecommitdiffstats
path: root/jrt/src/com/yahoo/jrt/Spec.java
blob: 36ee5869d66091bdfde357ad0803cc0852dd722c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jrt;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Objects;


/**
 * A Spec is a network address used for either listening or
 * connecting.
 */
public class Spec implements Comparable<Spec> {

    private final String        host;
    private final int           port;
    private final boolean       malformed;
    private final String asString;

    private static SocketAddress createAddress(String host, int port) {
        return (host == null)
                ? new InetSocketAddress(port)
                : new InetSocketAddress(host, port);
    }

    private static String createString(String host, int port) {
        return (host == null)
                ?  "tcp/" + port
                : "tcp/" + host + ":" + port;
    }
    /**
     * Create a Spec from a string. The form of the input string is
     * 'tcp/host:port' or 'tcp/port' where 'host' is the host name and
     * 'port' is the port number.
     *
     * @param spec input string to be parsed
     * @see #malformed
     */
    public Spec(String spec) {
        if (spec.startsWith("tcp/")) {
            int sep = spec.indexOf(':');
            String portStr;
            String hostStr = null;
            if (sep == -1) {
                portStr = spec.substring(4);
            } else {
                hostStr = spec.substring(4, sep);
                portStr = spec.substring(sep + 1);
            }
            boolean correct = true;
            int portNum = 0;
            try {
                portNum = Integer.parseInt(portStr);
            } catch (NumberFormatException e) {
                correct = false;
            }
            port = portNum;
            malformed = ! correct;
            host = correct ? hostStr : null;
            asString = correct ? createString(host, port) : "MALFORMED";
        } else {
            malformed = true;
            port = 0;
            host = null;
            asString = "MALFORMED";
        }
    }

    /**
     * Create a Spec from a host name and a port number.
     *
     * @param host host name
     * @param port port number
     */
    public Spec(String host, int port) {
        this.host = host;
        this.port = port;
        malformed = false;
        asString = createString(host, port);
    }

    /**
     * Create a Spec with a wildcard address.
     *
     * WARNING: Do not use this constructor to connect to localhost - use e.g. Spec("localhost", port) instead.
     * Why? Because Java may end up picking the wrong localhost hostname to connect to (for reasons
     * detailed in HostName.getLocalhost).
     *
     * @param port port number
     */
    public Spec(int port) {
        this(null, port);
    }

    /**
     * Obtain the host name of this address
     *
     * @return host name
     */
    public String host() {
        return host;
    }

    /**
     * Obtain the port number if this address
     *
     * @return port number
     */
    public int port() {
        return port;
    }

    /**
     * If this Spec was created from a string, this method will tell
     * you whether that string was malformed.
     *
     * @return true if this address is malformed
     */
    public boolean malformed() {
        return malformed;
    }

    /**
     * Resolve the socket address for this Spec. If this Spec is
     * malformed, this method will return null.
     *
     * @return socket address
     */
    SocketAddress resolveAddress() {
        return !malformed ? createAddress(host, port) : null;
    }

    /**
     * Obtain a string representation of this address. The return
     * value from this method may be used to create a new Spec.
     *
     * @return string representation of this address
     */
    public String toString() {
        return asString;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Spec spec = (Spec) o;
        return port == spec.port &&
                malformed == spec.malformed &&
                Objects.equals(host, spec.host);
    }

    @Override
    public int hashCode() {
        return Objects.hash(host, port, malformed);
    }

    @Override
    public int compareTo(Spec o) {
        int cmp = 0;
        if ((host != null) && (o.host != null)) {
            cmp = host.compareTo(o.host);
        } else if (host != null) {
            return -1;
        } else if (o.host != null) {
            return 1;
        }
        return (cmp == 0)
                ? Integer.compare(port, o.port)
                : cmp;

    }
}