Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
Simple layer on top of ByteBuffer for BINARY format. (#276)
Browse files Browse the repository at this point in the history
* Implement a simple layer on top of ByteBuffer for BINARY format.
  • Loading branch information
carlosalberto authored Oct 19, 2018
1 parent ac3c666 commit 9202384
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2016-2018 The OpenTracing Authors
*
* 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.
*/
package io.opentracing.propagation;

import java.nio.ByteBuffer;

/**
* Binary is an interface defining the required operations for a binary carrier for
* Tracer.inject() and Tracer.extract(). Binary can be defined either as inbound (extraction)
* or outbound (injection).
*
* When Binary is defined as inbound, extractionBuffer() will be called to retrieve the ByteBuffer
* containing the data used for SpanContext extraction.
*
* When Binary is defined as outbound, setInjectBufferLength() will be called in order to hint
* the required buffer length to inject the SpanContext, and injectionBuffer() will be called
* afterwards to retrieve the actual ByteBuffer used for the SpanContext injection.
*
* @see Format.Builtin#BINARY
* @see io.opentracing.Tracer#inject(SpanContext, Format, Object)
* @see io.opentracing.Tracer#extract(Format, Object)
*/
public interface Binary {
/**
* Gets the buffer used to store data as part of {@link SpanContext} injection.
*
* The lenght parameter hints the buffer length required for
* {@link SpanContext} injection. The user may use this to allocate a new
* ByteBuffer or resize an existing one.
*
* It is an error to call this method when Binary is used
* for {@link SpanContext} extraction.
*
* @param length The buffer length required for {@link SpanContext} injection.
* It needs to be larger than zero.
*
* @return The buffer used for {@link SpanContext} injection.
*/
ByteBuffer injectionBuffer(int lenght);

/**
* Gets the buffer containing the data used for {@link SpanContext} extraction.
*
* It is an error to call this method when Binary is used
* for {@link SpanContext} injection.
*
* @return The buffer used for {@link SpanContext} extraction.
*/
ByteBuffer extractionBuffer();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2016-2018 The OpenTracing Authors
*
* 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.
*/
package io.opentracing.propagation;

import java.nio.ByteBuffer;

public final class BinaryAdapters {

private BinaryAdapters() {}

/**
* Creates an inbound Binary instance used for extraction with the
* specified ByteBuffer as input.
*
* @param buffer The ByteBuffer used as input.
*
* @return The new {@link Binary} carrier used for extraction.
*/
public static Binary extractionCarrier(ByteBuffer buffer) {
if (buffer == null) {
throw new NullPointerException();
}

return new BinaryExtractAdapter(buffer);
}

/**
* Creates an outbound {@link Binary} instance used for injection with the
* specified ByteBuffer as output. ByteBuffer.limit() will be set to the value
* of the requested length at {@link Binary#injectionBuffer()} time, and
* AssertionError will be thrown if the requested length is larger than
* the remaining length of ByteBuffer.
*
* @param buffer The ByteBuffer used as input.
*
* @return The new Binary carrier used for injection.
*/
public static Binary injectionCarrier(ByteBuffer buffer) {
return new BinaryInjectAdapter(buffer);
}

static class BinaryExtractAdapter implements Binary {
ByteBuffer buffer;

public BinaryExtractAdapter(ByteBuffer buffer) {
this.buffer = buffer;
}

@Override
public ByteBuffer injectionBuffer(int length) {
throw new UnsupportedOperationException();
}

@Override
public ByteBuffer extractionBuffer() {
return buffer;
}
}

static class BinaryInjectAdapter implements Binary {
ByteBuffer buffer;

public BinaryInjectAdapter(ByteBuffer buffer) {
this.buffer = buffer;
}

@Override
public ByteBuffer injectionBuffer(int length) {
if (length < 1) {
throw new IllegalArgumentException("length needs to be larger than 0");
}
if (length > buffer.remaining()) {
throw new AssertionError("length is larger than the backing ByteBuffer remaining length");
}

buffer.limit(buffer.position() + length);
return buffer;
}

@Override
public ByteBuffer extractionBuffer() {
throw new UnsupportedOperationException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
import io.opentracing.SpanContext;
import io.opentracing.Tracer;

import java.nio.ByteBuffer;

/**
* Format instances control the behavior of Tracer.inject and Tracer.extract (and also constrain the type of the
* carrier parameter to same).
Expand Down Expand Up @@ -76,7 +74,7 @@ private Builtin(String name) {
* @see io.opentracing.Tracer#extract(Format, Object)
* @see Format
*/
public final static Format<ByteBuffer> BINARY = new Builtin<ByteBuffer>("BINARY");
public final static Format<Binary> BINARY = new Builtin<Binary>("BINARY");

/**
* @return Short name for built-in formats as they tend to show up in exception messages.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2016-2018 The OpenTracing Authors
*
* 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.
*/
package io.opentracing.propagation;

import java.nio.ByteBuffer;
import org.junit.Test;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class BinaryAdaptersTest {

@Test
public void testExtractBinary() {
ByteBuffer buff = ByteBuffer.wrap(new byte[0]);
Binary binary = BinaryAdapters.extractionCarrier(buff);
assertEquals(buff, binary.extractionBuffer());
}

@Test(expected = NullPointerException.class)
public void testExtractBinaryNull() {
BinaryAdapters.extractionCarrier(null);
}

@Test(expected = UnsupportedOperationException.class)
public void testExtractBinaryInjectBuffer() {
Binary binary = BinaryAdapters.extractionCarrier(ByteBuffer.allocate(1));
binary.injectionBuffer(1);
}

@Test
public void testInjectBinary() {
ByteBuffer buffer = ByteBuffer.allocate(1);
Binary binary = BinaryAdapters.injectionCarrier(buffer);
assertEquals(buffer, binary.injectionBuffer(1));
assertEquals(0, buffer.position());
}

@Test(expected = IllegalArgumentException.class)
public void testInjectBinaryInvalidLength() {
Binary binary = BinaryAdapters.injectionCarrier(ByteBuffer.allocate(1));
binary.injectionBuffer(0);
}

@Test(expected = AssertionError.class)
public void testInjectBinaryLargerLength() {
Binary binary = BinaryAdapters.injectionCarrier(ByteBuffer.allocate(1));
binary.injectionBuffer(2);
}

@Test(expected = UnsupportedOperationException.class)
public void testInjectBinaryExtractBuffer() {
Binary binary = BinaryAdapters.injectionCarrier(ByteBuffer.allocate(1));
binary.extractionBuffer();
}
}
83 changes: 83 additions & 0 deletions opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
*/
package io.opentracing.mock;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -25,6 +31,7 @@
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import io.opentracing.noop.NoopScopeManager;
import io.opentracing.propagation.Binary;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
import io.opentracing.util.ThreadLocalScopeManager;
Expand Down Expand Up @@ -112,6 +119,82 @@ public <C> MockSpan.MockContext extract(Format<C> format, C carrier) {
}
};

Propagator BINARY = new Propagator() {
static final int BUFFER_SIZE = 128;

@Override
public <C> void inject(MockSpan.MockContext ctx, Format<C> format, C carrier) {
if (!(carrier instanceof Binary)) {
throw new IllegalArgumentException("Expected Binary, received " + carrier.getClass());
}

Binary binary = (Binary) carrier;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream objStream = null;
try {
objStream = new ObjectOutputStream(stream);
objStream.writeLong(ctx.spanId());
objStream.writeLong(ctx.traceId());

for (Map.Entry<String, String> entry : ctx.baggageItems()) {
objStream.writeUTF(entry.getKey());
objStream.writeUTF(entry.getValue());
}
objStream.flush(); // *need* to flush ObjectOutputStream.

byte[] buff = stream.toByteArray();
binary.injectionBuffer(buff.length).put(buff);

} catch (IOException e) {
throw new RuntimeException("Corrupted state", e);
} finally {
if (objStream != null) {
try { objStream.close(); } catch (Exception e2) {}
}
}
}

@Override
public <C> MockSpan.MockContext extract(Format<C> format, C carrier) {
if (!(carrier instanceof Binary)) {
throw new IllegalArgumentException("Expected Binary, received " + carrier.getClass());
}

Long traceId = null;
Long spanId = null;
Map<String, String> baggage = new HashMap<>();

Binary binary = (Binary) carrier;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectInputStream objStream = null;
try {
ByteBuffer extractBuff = binary.extractionBuffer();
byte[] buff = new byte[extractBuff.remaining()];
extractBuff.get(buff);

objStream = new ObjectInputStream(new ByteArrayInputStream(buff));
spanId = objStream.readLong();
traceId = objStream.readLong();

while (objStream.available() > 0) {
baggage.put(objStream.readUTF(), objStream.readUTF());
}
} catch (IOException e) {
throw new RuntimeException("Corrupted state", e);
} finally {
if (objStream != null) {
try { objStream.close(); } catch (Exception e2) {}
}
}

if (traceId != null && spanId != null) {
return new MockSpan.MockContext(traceId, spanId, baggage);
}

return null;
}
};

Propagator TEXT_MAP = new Propagator() {
public static final String SPAN_ID_KEY = "spanid";
public static final String TRACE_ID_KEY = "traceid";
Expand Down
Loading

0 comments on commit 9202384

Please sign in to comment.