/*
|
* %CopyrightBegin%
|
*
|
* Copyright Ericsson AB 2000-2009. All Rights Reserved.
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*
|
* %CopyrightEnd%
|
*/
|
package com.ericsson.otp.erlang;
|
|
/**
|
* Provides a Java representation of Erlang refs. There are two styles of Erlang
|
* refs, old style (one id value) and new style (array of id values). This class
|
* manages both types.
|
*/
|
public class OtpErlangRef extends OtpErlangObject {
|
// don't change this!
|
private static final long serialVersionUID = -7022666480768586521L;
|
private final String node;
|
private final int creation;
|
// old style refs have one 18-bit id
|
// r6 "new" refs have array of ids, first one is only 18 bits however
|
private int ids[];
|
|
/**
|
* Create a unique Erlang ref belonging to the local node.
|
*
|
* @param self the local node.
|
* @deprecated use OtpLocalNode:createRef() instead
|
*/
|
@Deprecated
|
public OtpErlangRef(final OtpLocalNode self) {
|
final OtpErlangRef r = self.createRef();
|
ids = r.ids;
|
creation = r.creation;
|
node = r.node;
|
}
|
|
/**
|
* Create an Erlang ref from a stream containing a ref encoded in Erlang
|
* external format.
|
*
|
* @param buf the stream containing the encoded ref.
|
* @throws OtpErlangDecodeException if the buffer does not contain a valid external
|
* representation of an Erlang ref.
|
*/
|
public OtpErlangRef(final OtpInputStream buf)
|
throws OtpErlangDecodeException {
|
final OtpErlangRef r = buf.read_ref();
|
node = r.node();
|
creation = r.creation();
|
ids = r.ids();
|
}
|
|
/**
|
* Create an old style Erlang ref from its components.
|
*
|
* @param node the nodename.
|
* @param id an arbitrary number. Only the low order 18 bits will be used.
|
* @param creation another arbitrary number. Only the low order 2 bits will be
|
* used.
|
*/
|
public OtpErlangRef(final String node, final int id, final int creation) {
|
this.node = node;
|
ids = new int[1];
|
ids[0] = id & 0x3ffff; // 18 bits
|
this.creation = creation & 0x03; // 2 bits
|
}
|
|
/**
|
* Create a new style Erlang ref from its components.
|
*
|
* @param node the nodename.
|
* @param ids an array of arbitrary numbers. Only the low order 18 bits of
|
* the first number will be used. If the array contains only one
|
* number, an old style ref will be written instead. At most
|
* three numbers will be read from the array.
|
* @param creation another arbitrary number. Only the low order 2 bits will be
|
* used.
|
*/
|
public OtpErlangRef(final String node, final int[] ids, final int creation) {
|
this.node = node;
|
this.creation = creation & 0x03; // 2 bits
|
// use at most 82 bits (18 + 32 + 32)
|
int len = ids.length;
|
this.ids = new int[3];
|
this.ids[0] = 0;
|
this.ids[1] = 0;
|
this.ids[2] = 0;
|
if (len > 3) {
|
len = 3;
|
}
|
System.arraycopy(ids, 0, this.ids, 0, len);
|
this.ids[0] &= 0x3ffff; // only 18 significant bits in first number
|
}
|
|
/**
|
* Get the id number from the ref. Old style refs have only one id number.
|
* If this is a new style ref, the first id number is returned.
|
*
|
* @return the id number from the ref.
|
*/
|
public int id() {
|
return ids[0];
|
}
|
|
/**
|
* Get the array of id numbers from the ref. If this is an old style ref,
|
* the array is of length 1. If this is a new style ref, the array has
|
* length 3.
|
*
|
* @return the array of id numbers from the ref.
|
*/
|
public int[] ids() {
|
return ids;
|
}
|
|
/**
|
* Determine whether this is a new style ref.
|
*
|
* @return true if this ref is a new style ref, false otherwise.
|
*/
|
public boolean isNewRef() {
|
return ids.length > 1;
|
}
|
|
/**
|
* Get the creation number from the ref.
|
*
|
* @return the creation number from the ref.
|
*/
|
public int creation() {
|
return creation;
|
}
|
|
/**
|
* Get the node name from the ref.
|
*
|
* @return the node name from the ref.
|
*/
|
public String node() {
|
return node;
|
}
|
|
/**
|
* Get the string representation of the ref. Erlang refs are printed as
|
* #Ref<node.id>
|
*
|
* @return the string representation of the ref.
|
*/
|
public String toString() {
|
String s = "#Ref<" + node;
|
for (int i = 0; i < ids.length; i++) {
|
s += "." + ids[i];
|
}
|
s += ">";
|
return s;
|
}
|
|
/**
|
* Convert this ref to the equivalent Erlang external representation.
|
*
|
* @param buf an output stream to which the encoded ref should be written.
|
*/
|
public void encode(final OtpOutputStream buf) {
|
buf.write_ref(node, ids, creation);
|
}
|
|
/**
|
* Determine if two refs are equal. Refs are equal if their components are
|
* equal. New refs and old refs are considered equal if the node, creation
|
* and first id numnber are equal.
|
*
|
* @param o the other ref to compare to.
|
* @return true if the refs are equal, false otherwise.
|
*/
|
public boolean equals(final Object o) {
|
if (!(o instanceof OtpErlangRef)) {
|
return false;
|
}
|
final OtpErlangRef ref = (OtpErlangRef) o;
|
if (!(node.equals(ref.node()) && creation == ref.creation())) {
|
return false;
|
}
|
if (isNewRef() && ref.isNewRef()) {
|
return ids[0] == ref.ids[0] && ids[1] == ref.ids[1]
|
&& ids[2] == ref.ids[2];
|
}
|
return ids[0] == ref.ids[0];
|
}
|
|
/**
|
* Compute the hashCode value for a given ref. This function is compatible
|
* with equal.
|
*
|
* @return the hashCode of the node.
|
**/
|
protected int doHashCode() {
|
final OtpErlangObject.Hash hash = new OtpErlangObject.Hash(7);
|
hash.combine(creation, ids[0]);
|
if (isNewRef()) {
|
hash.combine(ids[1], ids[2]);
|
}
|
return hash.valueOf();
|
}
|
|
public Object clone() {
|
final OtpErlangRef newRef = (OtpErlangRef) super.clone();
|
newRef.ids = ids.clone();
|
return newRef;
|
}
|
}
|