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