• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.trace;
18 
19 import io.opencensus.internal.Utils;
20 import java.util.Arrays;
21 import java.util.Random;
22 import javax.annotation.Nullable;
23 import javax.annotation.concurrent.Immutable;
24 
25 /**
26  * A class that represents a span identifier. A valid span identifier is an 8-byte array with at
27  * least one non-zero byte.
28  *
29  * @since 0.5
30  */
31 @Immutable
32 public final class SpanId implements Comparable<SpanId> {
33   /**
34    * The size in bytes of the {@code SpanId}.
35    *
36    * @since 0.5
37    */
38   public static final int SIZE = 8;
39 
40   private static final int HEX_SIZE = 2 * SIZE;
41 
42   /**
43    * The invalid {@code SpanId}. All bytes are 0.
44    *
45    * @since 0.5
46    */
47   public static final SpanId INVALID = new SpanId(new byte[SIZE]);
48 
49   // The internal representation of the SpanId.
50   private final byte[] bytes;
51 
SpanId(byte[] bytes)52   private SpanId(byte[] bytes) {
53     this.bytes = bytes;
54   }
55 
56   /**
57    * Returns a {@code SpanId} built from a byte representation.
58    *
59    * <p>Equivalent with:
60    *
61    * <pre>{@code
62    * SpanId.fromBytes(buffer, 0);
63    * }</pre>
64    *
65    * @param buffer the representation of the {@code SpanId}.
66    * @return a {@code SpanId} whose representation is given by the {@code buffer} parameter.
67    * @throws NullPointerException if {@code buffer} is null.
68    * @throws IllegalArgumentException if {@code buffer.length} is not {@link SpanId#SIZE}.
69    * @since 0.5
70    */
fromBytes(byte[] buffer)71   public static SpanId fromBytes(byte[] buffer) {
72     Utils.checkNotNull(buffer, "buffer");
73     Utils.checkArgument(
74         buffer.length == SIZE, "Invalid size: expected %s, got %s", SIZE, buffer.length);
75     byte[] bytesCopied = Arrays.copyOf(buffer, SIZE);
76     return new SpanId(bytesCopied);
77   }
78 
79   /**
80    * Returns a {@code SpanId} whose representation is copied from the {@code src} beginning at the
81    * {@code srcOffset} offset.
82    *
83    * @param src the buffer where the representation of the {@code SpanId} is copied.
84    * @param srcOffset the offset in the buffer where the representation of the {@code SpanId}
85    *     begins.
86    * @return a {@code SpanId} whose representation is copied from the buffer.
87    * @throws NullPointerException if {@code src} is null.
88    * @throws IndexOutOfBoundsException if {@code srcOffset+SpanId.SIZE} is greater than {@code
89    *     src.length}.
90    * @since 0.5
91    */
fromBytes(byte[] src, int srcOffset)92   public static SpanId fromBytes(byte[] src, int srcOffset) {
93     byte[] bytes = new byte[SIZE];
94     System.arraycopy(src, srcOffset, bytes, 0, SIZE);
95     return new SpanId(bytes);
96   }
97 
98   /**
99    * Returns a {@code SpanId} built from a lowercase base16 representation.
100    *
101    * @param src the lowercase base16 representation.
102    * @return a {@code SpanId} built from a lowercase base16 representation.
103    * @throws NullPointerException if {@code src} is null.
104    * @throws IllegalArgumentException if {@code src.length} is not {@code 2 * SpanId.SIZE} OR if the
105    *     {@code str} has invalid characters.
106    * @since 0.11
107    */
fromLowerBase16(CharSequence src)108   public static SpanId fromLowerBase16(CharSequence src) {
109     Utils.checkArgument(
110         src.length() == HEX_SIZE, "Invalid size: expected %s, got %s", HEX_SIZE, src.length());
111     return new SpanId(LowerCaseBase16Encoding.decodeToBytes(src));
112   }
113 
114   /**
115    * Generates a new random {@code SpanId}.
116    *
117    * @param random The random number generator.
118    * @return a valid new {@code SpanId}.
119    * @since 0.5
120    */
generateRandomId(Random random)121   public static SpanId generateRandomId(Random random) {
122     byte[] bytes = new byte[SIZE];
123     do {
124       random.nextBytes(bytes);
125     } while (Arrays.equals(bytes, INVALID.bytes));
126     return new SpanId(bytes);
127   }
128 
129   /**
130    * Returns the byte representation of the {@code SpanId}.
131    *
132    * @return the byte representation of the {@code SpanId}.
133    * @since 0.5
134    */
getBytes()135   public byte[] getBytes() {
136     return Arrays.copyOf(bytes, SIZE);
137   }
138 
139   /**
140    * Copies the byte array representations of the {@code SpanId} into the {@code dest} beginning at
141    * the {@code destOffset} offset.
142    *
143    * <p>Equivalent with (but faster because it avoids any new allocations):
144    *
145    * <pre>{@code
146    * System.arraycopy(getBytes(), 0, dest, destOffset, SpanId.SIZE);
147    * }</pre>
148    *
149    * @param dest the destination buffer.
150    * @param destOffset the starting offset in the destination buffer.
151    * @throws NullPointerException if {@code dest} is null.
152    * @throws IndexOutOfBoundsException if {@code destOffset+SpanId.SIZE} is greater than {@code
153    *     dest.length}.
154    * @since 0.5
155    */
copyBytesTo(byte[] dest, int destOffset)156   public void copyBytesTo(byte[] dest, int destOffset) {
157     System.arraycopy(bytes, 0, dest, destOffset, SIZE);
158   }
159 
160   /**
161    * Returns whether the span identifier is valid. A valid span identifier is an 8-byte array with
162    * at least one non-zero byte.
163    *
164    * @return {@code true} if the span identifier is valid.
165    * @since 0.5
166    */
isValid()167   public boolean isValid() {
168     return !Arrays.equals(bytes, INVALID.bytes);
169   }
170 
171   /**
172    * Returns the lowercase base16 encoding of this {@code SpanId}.
173    *
174    * @return the lowercase base16 encoding of this {@code SpanId}.
175    * @since 0.11
176    */
toLowerBase16()177   public String toLowerBase16() {
178     return LowerCaseBase16Encoding.encodeToString(bytes);
179   }
180 
181   @Override
equals(@ullable Object obj)182   public boolean equals(@Nullable Object obj) {
183     if (obj == this) {
184       return true;
185     }
186 
187     if (!(obj instanceof SpanId)) {
188       return false;
189     }
190 
191     SpanId that = (SpanId) obj;
192     return Arrays.equals(bytes, that.bytes);
193   }
194 
195   @Override
hashCode()196   public int hashCode() {
197     return Arrays.hashCode(bytes);
198   }
199 
200   @Override
toString()201   public String toString() {
202     return "SpanId{spanId=" + toLowerBase16() + "}";
203   }
204 
205   @Override
compareTo(SpanId that)206   public int compareTo(SpanId that) {
207     for (int i = 0; i < SIZE; i++) {
208       if (bytes[i] != that.bytes[i]) {
209         return bytes[i] < that.bytes[i] ? -1 : 1;
210       }
211     }
212     return 0;
213   }
214 }
215