1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2000-2016. All Rights Reserved.
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  * %CopyrightEnd%
19  */
20 package com.ericsson.otp.erlang;
21 
22 /**
23  * Provides a Java representation of Erlang PIDs. PIDs represent Erlang
24  * processes and consist of a nodename and a number of integers.
25  */
26 public class OtpErlangPid extends OtpErlangObject implements Comparable<Object> {
27     // don't change this!
28     private static final long serialVersionUID = 1664394142301803659L;
29 
30     private final String node;
31     private final int id;
32     private final int serial;
33     private final int creation;
34 
35     /**
36      * Create a unique Erlang PID belonging to the local node.
37      *
38      * @param self
39      *            the local node.
40      *
41      * @deprecated use OtpLocalNode:createPid() instead
42      */
43     @Deprecated
OtpErlangPid(final OtpLocalNode self)44     public OtpErlangPid(final OtpLocalNode self) {
45         final OtpErlangPid p = self.createPid();
46 
47         id = p.id;
48         serial = p.serial;
49         creation = p.creation;
50         node = p.node;
51     }
52 
53     /**
54      * Create an Erlang PID from a stream containing a PID encoded in Erlang
55      * external format.
56      *
57      * @param buf
58      *            the stream containing the encoded PID.
59      *
60      * @exception OtpErlangDecodeException
61      *                if the buffer does not contain a valid external
62      *                representation of an Erlang PID.
63      */
OtpErlangPid(final OtpInputStream buf)64     public OtpErlangPid(final OtpInputStream buf)
65             throws OtpErlangDecodeException {
66         final OtpErlangPid p = buf.read_pid();
67 
68         node = p.node();
69         id = p.id();
70         serial = p.serial();
71         creation = p.creation();
72     }
73 
74     /**
75      * Create an Erlang pid from its components.
76      *
77      * @param node
78      *            the nodename.
79      *
80      * @param id
81      *            an arbitrary number. Only the low order 15 bits will be used.
82      *
83      * @param serial
84      *            another arbitrary number. Only the low order 13 bits will be
85      *            used.
86      *
87      * @param creation
88      *            yet another arbitrary number. Ony the low order 2 bits will
89      *            be used.
90      */
OtpErlangPid(final String node, final int id, final int serial, final int creation)91     public OtpErlangPid(final String node, final int id, final int serial,
92 			final int creation) {
93 	this(OtpExternal.pidTag, node, id, serial, creation);
94     }
95 
96     /**
97      * Create an Erlang pid from its components.
98      *
99      * @param tag
100      *            the external format to be compliant with
101      *            OtpExternal.pidTag where only a subset of the bits are significant (see other constructor).
102      *            OtpExternal.newPidTag where all 32 bits of id,serial and creation are significant.
103      *            newPidTag can only be decoded by OTP-19 and newer.
104      * @param node
105      *            the nodename.
106      *
107      * @param id
108      *            an arbitrary number.
109      *
110      * @param serial
111      *            another arbitrary number.
112      *
113      * @param creation
114      *            yet another arbitrary number.
115      */
OtpErlangPid(final int tag, final String node, final int id, final int serial, final int creation)116     protected OtpErlangPid(final int tag, final String node, final int id,
117 			   final int serial, final int creation) {
118 	this.node = node;
119 	if (tag == OtpExternal.pidTag) {
120 	    this.id = id & 0x7fff; // 15 bits
121 	    this.serial = serial & 0x1fff; // 13 bits
122 	    this.creation = creation & 0x03; // 2 bits
123 	}
124 	else {  // allow all 32 bits for newPidTag
125 	    this.id = id;
126 	    this.serial = serial;
127 	    this.creation = creation;
128 	}
129     }
130 
tag()131     protected int tag() {
132 	return OtpExternal.newPidTag;
133     }
134 
135     /**
136      * Get the serial number from the PID.
137      *
138      * @return the serial number from the PID.
139      */
serial()140     public int serial() {
141         return serial;
142     }
143 
144     /**
145      * Get the id number from the PID.
146      *
147      * @return the id number from the PID.
148      */
id()149     public int id() {
150         return id;
151     }
152 
153     /**
154      * Get the creation number from the PID.
155      *
156      * @return the creation number from the PID.
157      */
creation()158     public int creation() {
159         return creation;
160     }
161 
162     /**
163      * Get the node name from the PID.
164      *
165      * @return the node name from the PID.
166      */
node()167     public String node() {
168         return node;
169     }
170 
171     /**
172      * Get the string representation of the PID. Erlang PIDs are printed as
173      * #Pid&lt;node.id.serial&gt;
174      *
175      * @return the string representation of the PID.
176      */
177     @Override
toString()178     public String toString() {
179         return "#Pid<" + node.toString() + "." + id + "." + serial + ">";
180     }
181 
182     /**
183      * Convert this PID to the equivalent Erlang external representation.
184      *
185      * @param buf
186      *            an output stream to which the encoded PID should be written.
187      */
188     @Override
encode(final OtpOutputStream buf)189     public void encode(final OtpOutputStream buf) {
190         buf.write_pid(this);
191     }
192 
193     /**
194      * Determine if two PIDs are equal. PIDs are equal if their components are
195      * equal.
196      *
197      * @param o
198      *            the other PID to compare to.
199      *
200      * @return true if the PIDs are equal, false otherwise.
201      */
202     @Override
equals(final Object o)203     public boolean equals(final Object o) {
204         if (!(o instanceof OtpErlangPid)) {
205             return false;
206         }
207 
208         final OtpErlangPid pid = (OtpErlangPid) o;
209 
210         return creation == pid.creation && serial == pid.serial && id == pid.id
211                 && node.compareTo(pid.node) == 0;
212     }
213 
214     @Override
doHashCode()215     protected int doHashCode() {
216         final OtpErlangObject.Hash hash = new OtpErlangObject.Hash(5);
217         hash.combine(creation, serial);
218         hash.combine(id, node.hashCode());
219         return hash.valueOf();
220     }
221 
compareTo(final Object o)222     public int compareTo(final Object o) {
223         if (!(o instanceof OtpErlangPid)) {
224             return -1;
225         }
226 
227         final OtpErlangPid pid = (OtpErlangPid) o;
228         if (creation == pid.creation) {
229             if (serial == pid.serial) {
230                 if (id == pid.id) {
231                     return node.compareTo(pid.node);
232                 }
233                 return id - pid.id;
234             }
235             return serial - pid.serial;
236         }
237         return creation - pid.creation;
238     }
239 }
240