aboutsummaryrefslogtreecommitdiff
path: root/impl_core/src/main/java/io/opencensus/implcore/tags
diff options
context:
space:
mode:
authorYang Song <songy23@users.noreply.github.com>2017-11-09 13:59:08 -0800
committerGitHub <noreply@github.com>2017-11-09 13:59:08 -0800
commit5923bdbee2ea12ad9c4fa962b5adf526d9fe839d (patch)
tree5eac15ce4178a53c1deb212b050c59034a9a6cfc /impl_core/src/main/java/io/opencensus/implcore/tags
parent32cc8dd045a2502dffa792fd87ff9e994d8e7496 (diff)
downloadopencensus-java-5923bdbee2ea12ad9c4fa962b5adf526d9fe839d.tar.gz
Move implementation directories (#786)
* Move directories: core_impl to impl_core, core_impl_java to impl, core_impl_android to impl_lite.
Diffstat (limited to 'impl_core/src/main/java/io/opencensus/implcore/tags')
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java73
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java41
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java51
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java64
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java84
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java33
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java114
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java56
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java171
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java48
-rw-r--r--impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java34
11 files changed, 769 insertions, 0 deletions
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java
new file mode 100644
index 00000000..1a4ef81b
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import io.grpc.Context;
+import io.opencensus.common.Scope;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.unsafe.ContextUtils;
+import javax.annotation.Nullable;
+
+/**
+ * Utility methods for accessing the {@link TagContext} contained in the {@link io.grpc.Context}.
+ */
+final class CurrentTagContextUtils {
+
+ private CurrentTagContextUtils() {}
+
+ /**
+ * Returns the {@link TagContext} from the current context.
+ *
+ * @return the {@code TagContext} from the current context.
+ */
+ @Nullable
+ static TagContext getCurrentTagContext() {
+ return ContextUtils.TAG_CONTEXT_KEY.get();
+ }
+
+ /**
+ * Enters the scope of code where the given {@link TagContext} is in the current context and
+ * returns an object that represents that scope. The scope is exited when the returned object is
+ * closed.
+ *
+ * @param tags the {@code TagContext} to be set to the current context.
+ * @return an object that defines a scope where the given {@code TagContext} is set to the current
+ * context.
+ */
+ static Scope withTagContext(TagContext tags) {
+ return new WithTagContext(tags);
+ }
+
+ private static final class WithTagContext implements Scope {
+
+ private final Context orig;
+
+ /**
+ * Constructs a new {@link WithTagContext}.
+ *
+ * @param tags the {@code TagContext} to be added to the current {@code Context}.
+ */
+ private WithTagContext(TagContext tags) {
+ orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tags).attach();
+ }
+
+ @Override
+ public void close() {
+ Context.current().detach(orig);
+ }
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java
new file mode 100644
index 00000000..ab60ffa1
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.opencensus.tags.TaggingState;
+import io.opencensus.tags.TagsComponent;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * The current {@link TaggingState} for a {@link TagsComponent}.
+ *
+ * <p>This class allows different tagging classes to share the state in a thread-safe way.
+ */
+@ThreadSafe
+public final class CurrentTaggingState {
+ private volatile TaggingState currentState = TaggingState.ENABLED;
+
+ public TaggingState get() {
+ return currentState;
+ }
+
+ void set(TaggingState state) {
+ currentState = checkNotNull(state, "state");
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java b/impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java
new file mode 100644
index 00000000..eae54c5d
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import io.opencensus.common.Scope;
+import io.opencensus.implcore.internal.NoopScope;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagContextBuilder;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+
+/** {@link TagContextBuilder} that is used when tagging is disabled. */
+final class NoopTagContextBuilder extends TagContextBuilder {
+ static final NoopTagContextBuilder INSTANCE = new NoopTagContextBuilder();
+
+ private NoopTagContextBuilder() {}
+
+ @Override
+ public TagContextBuilder put(TagKey key, TagValue value) {
+ return this;
+ }
+
+ @Override
+ public TagContextBuilder remove(TagKey key) {
+ return this;
+ }
+
+ @Override
+ public TagContext build() {
+ return TagContextImpl.EMPTY;
+ }
+
+ @Override
+ public Scope buildScoped() {
+ return NoopScope.getInstance();
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java
new file mode 100644
index 00000000..1f473454
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.opencensus.common.Scope;
+import io.opencensus.tags.TagContextBuilder;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import java.util.HashMap;
+import java.util.Map;
+
+final class TagContextBuilderImpl extends TagContextBuilder {
+ private final Map<TagKey, TagValue> tags;
+
+ TagContextBuilderImpl(Map<TagKey, TagValue> tags) {
+ this.tags = new HashMap<TagKey, TagValue>(tags);
+ }
+
+ TagContextBuilderImpl() {
+ this.tags = new HashMap<TagKey, TagValue>();
+ }
+
+ @Override
+ public TagContextBuilderImpl put(TagKey key, TagValue value) {
+ return setInternal(key, checkNotNull(value, "value"));
+ }
+
+ private TagContextBuilderImpl setInternal(TagKey key, TagValue value) {
+ tags.put(checkNotNull(key), value);
+ return this;
+ }
+
+ @Override
+ public TagContextBuilderImpl remove(TagKey key) {
+ tags.remove(key);
+ return this;
+ }
+
+ @Override
+ public TagContextImpl build() {
+ return new TagContextImpl(tags);
+ }
+
+ @Override
+ public Scope buildScoped() {
+ return CurrentTagContextUtils.withTagContext(build());
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java
new file mode 100644
index 00000000..177ce639
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+public final class TagContextImpl extends TagContext {
+
+ public static final TagContextImpl EMPTY =
+ new TagContextImpl(Collections.<TagKey, TagValue>emptyMap());
+
+ // The types of the TagKey and value must match for each entry.
+ private final Map<TagKey, TagValue> tags;
+
+ public TagContextImpl(Map<? extends TagKey, ? extends TagValue> tags) {
+ this.tags = Collections.unmodifiableMap(new HashMap<TagKey, TagValue>(tags));
+ }
+
+ public Map<TagKey, TagValue> getTags() {
+ return tags;
+ }
+
+ @Override
+ protected Iterator<Tag> getIterator() {
+ return new TagIterator(tags);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // Directly compare the tags when both objects are TagContextImpls, for efficiency.
+ if (other instanceof TagContextImpl) {
+ return getTags().equals(((TagContextImpl) other).getTags());
+ }
+ return super.equals(other);
+ }
+
+ private static final class TagIterator implements Iterator<Tag> {
+ Iterator<Map.Entry<TagKey, TagValue>> iterator;
+
+ TagIterator(Map<TagKey, TagValue> tags) {
+ iterator = tags.entrySet().iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public Tag next() {
+ final Entry<TagKey, TagValue> next = iterator.next();
+ return Tag.create(next.getKey(), next.getValue());
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("TagIterator.remove()");
+ }
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java
new file mode 100644
index 00000000..5fbc5050
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import io.opencensus.tags.Tag;
+
+final class TagContextUtils {
+ private TagContextUtils() {}
+
+ /**
+ * Add a {@code Tag} of any type to a builder.
+ *
+ * @param tag tag containing the key and value to set.
+ * @param builder the builder to update.
+ */
+ static void addTagToBuilder(Tag tag, TagContextBuilderImpl builder) {
+ builder.put(tag.getKey(), tag.getValue());
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java
new file mode 100644
index 00000000..82c1d8cf
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import io.opencensus.common.Scope;
+import io.opencensus.implcore.internal.NoopScope;
+import io.opencensus.tags.InternalUtils;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagContextBuilder;
+import io.opencensus.tags.Tagger;
+import io.opencensus.tags.TaggingState;
+import java.util.Iterator;
+
+public final class TaggerImpl extends Tagger {
+ // All methods in this class use TagContextImpl and TagContextBuilderImpl. For example,
+ // withTagContext(...) always puts a TagContextImpl into scope, even if the argument is another
+ // TagContext subclass.
+
+ private final CurrentTaggingState state;
+
+ TaggerImpl(CurrentTaggingState state) {
+ this.state = state;
+ }
+
+ @Override
+ public TagContextImpl empty() {
+ return TagContextImpl.EMPTY;
+ }
+
+ @Override
+ public TagContextImpl getCurrentTagContext() {
+ return state.get() == TaggingState.DISABLED
+ ? TagContextImpl.EMPTY
+ : toTagContextImpl(CurrentTagContextUtils.getCurrentTagContext());
+ }
+
+ @Override
+ public TagContextBuilder emptyBuilder() {
+ return state.get() == TaggingState.DISABLED
+ ? NoopTagContextBuilder.INSTANCE
+ : new TagContextBuilderImpl();
+ }
+
+ @Override
+ public TagContextBuilder currentBuilder() {
+ return state.get() == TaggingState.DISABLED
+ ? NoopTagContextBuilder.INSTANCE
+ : toBuilder(CurrentTagContextUtils.getCurrentTagContext());
+ }
+
+ @Override
+ public TagContextBuilder toBuilder(TagContext tags) {
+ return state.get() == TaggingState.DISABLED
+ ? NoopTagContextBuilder.INSTANCE
+ : toTagContextBuilderImpl(tags);
+ }
+
+ @Override
+ public Scope withTagContext(TagContext tags) {
+ return state.get() == TaggingState.DISABLED
+ ? NoopScope.getInstance()
+ : CurrentTagContextUtils.withTagContext(toTagContextImpl(tags));
+ }
+
+ private static TagContextImpl toTagContextImpl(TagContext tags) {
+ if (tags instanceof TagContextImpl) {
+ return (TagContextImpl) tags;
+ } else {
+ Iterator<Tag> i = InternalUtils.getTags(tags);
+ if (!i.hasNext()) {
+ return TagContextImpl.EMPTY;
+ }
+ TagContextBuilderImpl builder = new TagContextBuilderImpl();
+ while (i.hasNext()) {
+ Tag tag = i.next();
+ if (tag != null) {
+ TagContextUtils.addTagToBuilder(tag, builder);
+ }
+ }
+ return builder.build();
+ }
+ }
+
+ private static TagContextBuilderImpl toTagContextBuilderImpl(TagContext tags) {
+ // Copy the tags more efficiently in the expected case, when the TagContext is a TagContextImpl.
+ if (tags instanceof TagContextImpl) {
+ return new TagContextBuilderImpl(((TagContextImpl) tags).getTags());
+ } else {
+ TagContextBuilderImpl builder = new TagContextBuilderImpl();
+ for (Iterator<Tag> i = InternalUtils.getTags(tags); i.hasNext(); ) {
+ Tag tag = i.next();
+ if (tag != null) {
+ TagContextUtils.addTagToBuilder(tag, builder);
+ }
+ }
+ return builder;
+ }
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java
new file mode 100644
index 00000000..216afdc9
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.opencensus.implcore.tags.propagation.TagPropagationComponentImpl;
+import io.opencensus.tags.Tagger;
+import io.opencensus.tags.TaggingState;
+import io.opencensus.tags.TagsComponent;
+import io.opencensus.tags.propagation.TagPropagationComponent;
+
+/** Base implementation of {@link TagsComponent}. */
+public class TagsComponentImplBase extends TagsComponent {
+
+ // The TaggingState shared between the TagsComponent, Tagger, and TagPropagationComponent
+ private final CurrentTaggingState state = new CurrentTaggingState();
+
+ private final Tagger tagger = new TaggerImpl(state);
+ private final TagPropagationComponent tagPropagationComponent =
+ new TagPropagationComponentImpl(state);
+
+ @Override
+ public Tagger getTagger() {
+ return tagger;
+ }
+
+ @Override
+ public TagPropagationComponent getTagPropagationComponent() {
+ return tagPropagationComponent;
+ }
+
+ @Override
+ public TaggingState getState() {
+ return state.get();
+ }
+
+ @Override
+ public void setState(TaggingState newState) {
+ state.set(checkNotNull(newState, "newState"));
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java
new file mode 100644
index 00000000..d889a4b8
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2016-17, OpenCensus 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.opencensus.implcore.tags.propagation;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+import com.google.common.io.ByteArrayDataOutput;
+import com.google.common.io.ByteStreams;
+import io.opencensus.implcore.internal.VarInt;
+import io.opencensus.implcore.tags.TagContextImpl;
+import io.opencensus.tags.InternalUtils;
+import io.opencensus.tags.Tag;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TagKey;
+import io.opencensus.tags.TagValue;
+import io.opencensus.tags.propagation.TagContextDeserializationException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Methods for serializing and deserializing {@link TagContext}s.
+ *
+ * <p>The format defined in this class is shared across all implementations of OpenCensus. It allows
+ * tags to propagate across requests.
+ *
+ * <p>OpenCensus tag context encoding:
+ *
+ * <ul>
+ * <li>Tags are encoded in single byte sequence. The version 0 format is:
+ * <li>{@code <version_id><encoded_tags>}
+ * <li>{@code <version_id> == a single byte, value 0}
+ * <li>{@code <encoded_tags> == (<tag_field_id><tag_encoding>)*}
+ * <ul>
+ * <li>{@code <tag_field_id>} == a single byte, value 0
+ * <li>{@code <tag_encoding>}:
+ * <ul>
+ * <li>{@code <tag_key_len><tag_key><tag_val_len><tag_val>}
+ * <ul>
+ * <li>{@code <tag_key_len>} == varint encoded integer
+ * <li>{@code <tag_key>} == tag_key_len bytes comprising tag key name
+ * <li>{@code <tag_val_len>} == varint encoded integer
+ * <li>{@code <tag_val>} == tag_val_len bytes comprising UTF-8 string
+ * </ul>
+ * </ul>
+ * </ul>
+ * </ul>
+ */
+final class SerializationUtils {
+ private SerializationUtils() {}
+
+ @VisibleForTesting static final int VERSION_ID = 0;
+ @VisibleForTesting static final int TAG_FIELD_ID = 0;
+
+ // Serializes a TagContext to the on-the-wire format.
+ // Encoded tags are of the form: <version_id><encoded_tags>
+ static byte[] serializeBinary(TagContext tags) {
+ // Use a ByteArrayDataOutput to avoid needing to handle IOExceptions.
+ final ByteArrayDataOutput byteArrayDataOutput = ByteStreams.newDataOutput();
+ byteArrayDataOutput.write(VERSION_ID);
+ for (Iterator<Tag> i = InternalUtils.getTags(tags); i.hasNext(); ) {
+ Tag tag = i.next();
+ encodeTag(tag, byteArrayDataOutput);
+ }
+ return byteArrayDataOutput.toByteArray();
+ }
+
+ // Deserializes input to TagContext based on the binary format standard.
+ // The encoded tags are of the form: <version_id><encoded_tags>
+ static TagContextImpl deserializeBinary(byte[] bytes) throws TagContextDeserializationException {
+ try {
+ if (bytes.length == 0) {
+ // Does not allow empty byte array.
+ throw new TagContextDeserializationException("Input byte[] can not be empty.");
+ }
+
+ ByteBuffer buffer = ByteBuffer.wrap(bytes).asReadOnlyBuffer();
+ int versionId = buffer.get();
+ if (versionId != VERSION_ID) {
+ throw new TagContextDeserializationException(
+ "Wrong Version ID: " + versionId + ". Currently supported version is: " + VERSION_ID);
+ }
+ return new TagContextImpl(parseTags(buffer));
+ } catch (BufferUnderflowException exn) {
+ throw new TagContextDeserializationException(exn.toString()); // byte array format error.
+ }
+ }
+
+ private static Map<TagKey, TagValue> parseTags(ByteBuffer buffer)
+ throws TagContextDeserializationException {
+ Map<TagKey, TagValue> tags = new HashMap<TagKey, TagValue>();
+ int limit = buffer.limit();
+ while (buffer.position() < limit) {
+ int type = buffer.get();
+ if (type == TAG_FIELD_ID) {
+ TagKey key = createTagKey(decodeString(buffer));
+ TagValue val = createTagValue(key, decodeString(buffer));
+ tags.put(key, val);
+ } else {
+ // Stop parsing at the first unknown field ID, since there is no way to know its length.
+ // TODO(sebright): Consider storing the rest of the byte array in the TagContext.
+ return tags;
+ }
+ }
+ return tags;
+ }
+
+ // TODO(sebright): Consider exposing a TagKey name validation method to avoid needing to catch an
+ // IllegalArgumentException here.
+ private static final TagKey createTagKey(String name) throws TagContextDeserializationException {
+ try {
+ return TagKey.create(name);
+ } catch (IllegalArgumentException e) {
+ throw new TagContextDeserializationException("Invalid tag key: " + name, e);
+ }
+ }
+
+ // TODO(sebright): Consider exposing a TagValue validation method to avoid needing to catch
+ // an IllegalArgumentException here.
+ private static final TagValue createTagValue(TagKey key, String value)
+ throws TagContextDeserializationException {
+ try {
+ return TagValue.create(value);
+ } catch (IllegalArgumentException e) {
+ throw new TagContextDeserializationException(
+ "Invalid tag value for key " + key + ": " + value, e);
+ }
+ }
+
+ private static final void encodeTag(Tag tag, ByteArrayDataOutput byteArrayDataOutput) {
+ byteArrayDataOutput.write(TAG_FIELD_ID);
+ encodeString(tag.getKey().getName(), byteArrayDataOutput);
+ encodeString(tag.getValue().asString(), byteArrayDataOutput);
+ }
+
+ private static final void encodeString(String input, ByteArrayDataOutput byteArrayDataOutput) {
+ putVarInt(input.length(), byteArrayDataOutput);
+ byteArrayDataOutput.write(input.getBytes(Charsets.UTF_8));
+ }
+
+ private static final void putVarInt(int input, ByteArrayDataOutput byteArrayDataOutput) {
+ byte[] output = new byte[VarInt.varIntSize(input)];
+ VarInt.putVarInt(input, output, 0);
+ byteArrayDataOutput.write(output);
+ }
+
+ private static final String decodeString(ByteBuffer buffer) {
+ int length = VarInt.getVarInt(buffer);
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < length; i++) {
+ builder.append((char) buffer.get());
+ }
+ return builder.toString();
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java
new file mode 100644
index 00000000..eea24a33
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags.propagation;
+
+import io.opencensus.implcore.tags.CurrentTaggingState;
+import io.opencensus.implcore.tags.TagContextImpl;
+import io.opencensus.tags.TagContext;
+import io.opencensus.tags.TaggingState;
+import io.opencensus.tags.propagation.TagContextBinarySerializer;
+import io.opencensus.tags.propagation.TagContextDeserializationException;
+
+final class TagContextBinarySerializerImpl extends TagContextBinarySerializer {
+ private static final byte[] EMPTY_BYTE_ARRAY = {};
+
+ private final CurrentTaggingState state;
+
+ TagContextBinarySerializerImpl(CurrentTaggingState state) {
+ this.state = state;
+ }
+
+ @Override
+ public byte[] toByteArray(TagContext tags) {
+ return state.get() == TaggingState.DISABLED
+ ? EMPTY_BYTE_ARRAY
+ : SerializationUtils.serializeBinary(tags);
+ }
+
+ @Override
+ public TagContext fromByteArray(byte[] bytes) throws TagContextDeserializationException {
+ return state.get() == TaggingState.DISABLED
+ ? TagContextImpl.EMPTY
+ : SerializationUtils.deserializeBinary(bytes);
+ }
+}
diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java
new file mode 100644
index 00000000..5def0758
--- /dev/null
+++ b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017, OpenCensus 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.opencensus.implcore.tags.propagation;
+
+import io.opencensus.implcore.tags.CurrentTaggingState;
+import io.opencensus.tags.propagation.TagContextBinarySerializer;
+import io.opencensus.tags.propagation.TagPropagationComponent;
+
+public final class TagPropagationComponentImpl extends TagPropagationComponent {
+ private final TagContextBinarySerializer tagContextBinarySerializer;
+
+ public TagPropagationComponentImpl(CurrentTaggingState state) {
+ tagContextBinarySerializer = new TagContextBinarySerializerImpl(state);
+ }
+
+ @Override
+ public TagContextBinarySerializer getBinarySerializer() {
+ return tagContextBinarySerializer;
+ }
+}