/* * %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[] = null; /** * 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. * * @exception 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. */ @Override 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. */ @Override 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. */ @Override 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. **/ @Override 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(); } @Override public Object clone() { final OtpErlangRef newRef = (OtpErlangRef) super.clone(); newRef.ids = ids.clone(); return newRef; } }