aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java
diff options
context:
space:
mode:
authorGravatar Michajlo Matijkiw <michajlo@google.com>2016-07-14 22:31:34 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2016-07-15 13:31:20 +0000
commit937cb800767178b245587276d81d17b94384e44b (patch)
treeb649d5082a07d34863c5d096c175eb501f62ec07 /src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java
parent3b25028750dd7a6df6777f6c70c1feae9063a630 (diff)
Remove not-quite necessary serialization bits
What we really are doing here is formatting. -- MOS_MIGRATED_REVID=127481183
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java568
1 files changed, 568 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java b/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java
new file mode 100644
index 0000000000..54a223fbe8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/packages/AttributeFormatter.java
@@ -0,0 +1,568 @@
+// Copyright 2014 The Bazel Authors. 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.
+package com.google.devtools.build.lib.packages;
+
+import static com.google.devtools.build.lib.packages.BuildType.DISTRIBUTIONS;
+import static com.google.devtools.build.lib.packages.BuildType.FILESET_ENTRY_LIST;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_DICT_UNARY;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.BuildType.LICENSE;
+import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL;
+import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL_LIST;
+import static com.google.devtools.build.lib.packages.BuildType.OUTPUT;
+import static com.google.devtools.build.lib.packages.BuildType.OUTPUT_LIST;
+import static com.google.devtools.build.lib.packages.BuildType.TRISTATE;
+import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
+import static com.google.devtools.build.lib.syntax.Type.INTEGER;
+import static com.google.devtools.build.lib.syntax.Type.INTEGER_LIST;
+import static com.google.devtools.build.lib.syntax.Type.STRING;
+import static com.google.devtools.build.lib.syntax.Type.STRING_DICT;
+import static com.google.devtools.build.lib.syntax.Type.STRING_DICT_UNARY;
+import static com.google.devtools.build.lib.syntax.Type.STRING_LIST;
+import static com.google.devtools.build.lib.syntax.Type.STRING_LIST_DICT;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.packages.BuildType.Selector;
+import com.google.devtools.build.lib.packages.BuildType.SelectorList;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute.Discriminator;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute.SelectorEntry;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute.SelectorEntry.Builder;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute.Tristate;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.LabelDictUnaryEntry;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.LabelListDictEntry;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.StringDictEntry;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.StringDictUnaryEntry;
+import com.google.devtools.build.lib.query2.proto.proto2api.Build.StringListDictEntry;
+import com.google.devtools.build.lib.syntax.GlobCriteria;
+import com.google.devtools.build.lib.syntax.GlobList;
+import com.google.devtools.build.lib.syntax.Type;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nullable;
+
+/** Common utilities for serializing {@link Attribute}s as protocol buffers. */
+public class AttributeFormatter {
+
+ private static final ImmutableSet<Type<?>> depTypes =
+ ImmutableSet.<Type<?>>of(
+ STRING, LABEL, OUTPUT, STRING_LIST, LABEL_LIST, OUTPUT_LIST, DISTRIBUTIONS);
+
+ private static final ImmutableSet<Type<?>> noDepTypes =
+ ImmutableSet.<Type<?>>of(NODEP_LABEL_LIST, NODEP_LABEL);
+
+ private AttributeFormatter() {}
+
+ /**
+ * Convert attribute value to proto representation.
+ *
+ * <p>If {@param value} is null, only the {@code name}, {@code explicitlySpecified}, {@code
+ * nodep} (if applicable), and {@code type} fields will be included in the proto message.
+ *
+ * <p>If {@param includeGlobs} is true then {@link GlobCriteria} will be included in the proto
+ * message if present.
+ *
+ * <p>If {@param encodeBooleanAndTriStateAsIntegerAndString} is true then boolean and tristate
+ * values are also encoded as integers and strings.
+ */
+ public static Build.Attribute getAttributeProto(
+ Attribute attr,
+ @Nullable Object value,
+ boolean explicitlySpecified,
+ boolean includeGlobs,
+ boolean encodeBooleanAndTriStateAsIntegerAndString) {
+ return getAttributeProto(
+ attr.getName(),
+ attr.getType(),
+ value,
+ explicitlySpecified,
+ includeGlobs,
+ encodeBooleanAndTriStateAsIntegerAndString);
+ }
+
+ @VisibleForTesting
+ static Build.Attribute getAttributeProto(
+ String name,
+ Type<?> type,
+ @Nullable Object value,
+ boolean explicitlySpecified,
+ boolean includeGlobs,
+ boolean encodeBooleanAndTriStateAsIntegerAndString) {
+ Build.Attribute.Builder attrPb = Build.Attribute.newBuilder();
+ attrPb.setName(name);
+ attrPb.setExplicitlySpecified(explicitlySpecified);
+ maybeSetNoDep(type, attrPb);
+
+ if (value instanceof SelectorList<?>) {
+ attrPb.setType(Discriminator.SELECTOR_LIST);
+ writeSelectorListToBuilder(attrPb, type, (SelectorList<?>) value, includeGlobs);
+ } else {
+ attrPb.setType(ProtoUtils.getDiscriminatorFromType(type));
+ if (value != null) {
+ AttributeBuilderAdapter adapter =
+ new AttributeBuilderAdapter(attrPb, encodeBooleanAndTriStateAsIntegerAndString);
+ writeAttributeValueToBuilder(adapter, type, value, includeGlobs);
+ }
+ }
+
+ return attrPb.build();
+ }
+
+ private static void maybeSetNoDep(Type<?> type, Build.Attribute.Builder attrPb) {
+ if (depTypes.contains(type)) {
+ attrPb.setNodep(false);
+ } else if (noDepTypes.contains(type)) {
+ attrPb.setNodep(true);
+ }
+ }
+
+ private static void writeSelectorListToBuilder(
+ Build.Attribute.Builder attrPb,
+ Type<?> type,
+ SelectorList<?> selectorList,
+ boolean includeGlobs) {
+ Build.Attribute.SelectorList.Builder selectorListBuilder =
+ Build.Attribute.SelectorList.newBuilder();
+ selectorListBuilder.setType(ProtoUtils.getDiscriminatorFromType(type));
+ for (Selector<?> selector : selectorList.getSelectors()) {
+ Build.Attribute.Selector.Builder selectorBuilder = Build.Attribute.Selector.newBuilder()
+ .setNoMatchError(selector.getNoMatchError())
+ .setHasDefaultValue(selector.hasDefault());
+
+ // Note that the order of entries returned by selector.getEntries is stable. The map's
+ // entries' order is preserved from the sorting performed by the SelectorValue constructor.
+ for (Entry<Label, ?> entry : selector.getEntries().entrySet()) {
+ Label condition = entry.getKey();
+ Builder selectorEntryBuilder = SelectorEntry.newBuilder()
+ .setLabel(condition.toString())
+ .setIsDefaultValue(!selector.isValueSet(condition));
+
+ Object conditionValue = entry.getValue();
+ if (conditionValue != null) {
+ writeAttributeValueToBuilder(
+ new SelectorEntryBuilderAdapter(selectorEntryBuilder),
+ type,
+ conditionValue,
+ includeGlobs);
+ }
+ selectorBuilder.addEntries(selectorEntryBuilder);
+ }
+ selectorListBuilder.addElements(selectorBuilder);
+ }
+ attrPb.setSelectorList(selectorListBuilder);
+ }
+
+ /**
+ * Set the appropriate type and value. Since string and string list store values for multiple
+ * types, use the toString() method on the objects instead of casting them.
+ */
+ @SuppressWarnings("unchecked")
+ private static void writeAttributeValueToBuilder(
+ AttributeValueBuilderAdapter builder, Type<?> type, Object value, boolean includeGlobs) {
+ if (type == INTEGER) {
+ builder.setIntValue((Integer) value);
+ } else if (type == STRING || type == LABEL || type == NODEP_LABEL || type == OUTPUT) {
+ builder.setStringValue(value.toString());
+ } else if (type == STRING_LIST || type == LABEL_LIST || type == NODEP_LABEL_LIST
+ || type == OUTPUT_LIST || type == DISTRIBUTIONS) {
+ for (Object entry : (Collection<?>) value) {
+ builder.addStringListValue(entry.toString());
+ }
+ } else if (type == INTEGER_LIST) {
+ for (Integer entry : (Collection<Integer>) value) {
+ builder.addIntListValue(entry);
+ }
+ } else if (type == BOOLEAN) {
+ builder.setBooleanValue((Boolean) value);
+ } else if (type == TRISTATE) {
+ builder.setTristateValue(triStateToProto((TriState) value));
+ } else if (type == LICENSE) {
+ License license = (License) value;
+ Build.License.Builder licensePb = Build.License.newBuilder();
+ for (License.LicenseType licenseType : license.getLicenseTypes()) {
+ licensePb.addLicenseType(licenseType.toString());
+ }
+ for (Label exception : license.getExceptions()) {
+ licensePb.addException(exception.toString());
+ }
+ builder.setLicense(licensePb);
+ } else if (type == STRING_DICT) {
+ Map<String, String> dict = (Map<String, String>) value;
+ for (Map.Entry<String, String> keyValueList : dict.entrySet()) {
+ StringDictEntry.Builder entry =
+ StringDictEntry.newBuilder()
+ .setKey(keyValueList.getKey())
+ .setValue(keyValueList.getValue());
+ builder.addStringDictValue(entry);
+ }
+ } else if (type == STRING_DICT_UNARY) {
+ Map<String, String> dict = (Map<String, String>) value;
+ for (Map.Entry<String, String> dictEntry : dict.entrySet()) {
+ StringDictUnaryEntry.Builder entry =
+ StringDictUnaryEntry.newBuilder()
+ .setKey(dictEntry.getKey())
+ .setValue(dictEntry.getValue());
+ builder.addStringDictUnaryValue(entry);
+ }
+ } else if (type == STRING_LIST_DICT) {
+ Map<String, List<String>> dict = (Map<String, List<String>>) value;
+ for (Map.Entry<String, List<String>> dictEntry : dict.entrySet()) {
+ StringListDictEntry.Builder entry =
+ StringListDictEntry.newBuilder().setKey(dictEntry.getKey());
+ for (Object dictEntryValue : dictEntry.getValue()) {
+ entry.addValue(dictEntryValue.toString());
+ }
+ builder.addStringListDictValue(entry);
+ }
+ } else if (type == LABEL_DICT_UNARY) {
+ Map<String, Label> dict = (Map<String, Label>) value;
+ for (Map.Entry<String, Label> dictEntry : dict.entrySet()) {
+ LabelDictUnaryEntry.Builder entry =
+ LabelDictUnaryEntry.newBuilder()
+ .setKey(dictEntry.getKey())
+ .setValue(dictEntry.getValue().toString());
+ builder.addLabelDictUnaryValue(entry);
+ }
+ } else if (type == FILESET_ENTRY_LIST) {
+ List<FilesetEntry> filesetEntries = (List<FilesetEntry>) value;
+ for (FilesetEntry filesetEntry : filesetEntries) {
+ Build.FilesetEntry.Builder filesetEntryPb =
+ Build.FilesetEntry.newBuilder()
+ .setSource(filesetEntry.getSrcLabel().toString())
+ .setDestinationDirectory(filesetEntry.getDestDir().getPathString())
+ .setSymlinkBehavior(symlinkBehaviorToPb(filesetEntry.getSymlinkBehavior()))
+ .setStripPrefix(filesetEntry.getStripPrefix())
+ .setFilesPresent(filesetEntry.getFiles() != null);
+
+ if (filesetEntry.getFiles() != null) {
+ for (Label file : filesetEntry.getFiles()) {
+ filesetEntryPb.addFile(file.toString());
+ }
+ }
+
+ if (filesetEntry.getExcludes() != null) {
+ for (String exclude : filesetEntry.getExcludes()) {
+ filesetEntryPb.addExclude(exclude);
+ }
+ }
+
+ builder.addFilesetListValue(filesetEntryPb);
+ }
+ } else {
+ throw new AssertionError("Unknown type: " + type);
+ }
+
+ if (includeGlobs && value instanceof GlobList<?>) {
+ GlobList<?> globList = (GlobList<?>) value;
+
+ for (GlobCriteria criteria : globList.getCriteria()) {
+ Build.GlobCriteria.Builder criteriaPb =
+ Build.GlobCriteria.newBuilder().setGlob(criteria.isGlob());
+ for (String include : criteria.getIncludePatterns()) {
+ criteriaPb.addInclude(include);
+ }
+ for (String exclude : criteria.getExcludePatterns()) {
+ criteriaPb.addExclude(exclude);
+ }
+
+ builder.addGlobCriteria(criteriaPb);
+ }
+ }
+ }
+
+ private static Tristate triStateToProto(TriState value) {
+ switch (value) {
+ case AUTO:
+ return Tristate.AUTO;
+ case NO:
+ return Tristate.NO;
+ case YES:
+ return Tristate.YES;
+ default:
+ throw new AssertionError("Expected AUTO/NO/YES to cover all possible cases");
+ }
+ }
+
+ // This is needed because I do not want to use the SymlinkBehavior from the
+ // protocol buffer all over the place, so there are two classes that do
+ // essentially the same thing.
+ private static Build.FilesetEntry.SymlinkBehavior symlinkBehaviorToPb(
+ FilesetEntry.SymlinkBehavior symlinkBehavior) {
+ switch (symlinkBehavior) {
+ case COPY:
+ return Build.FilesetEntry.SymlinkBehavior.COPY;
+ case DEREFERENCE:
+ return Build.FilesetEntry.SymlinkBehavior.DEREFERENCE;
+ default:
+ throw new AssertionError("Unhandled FilesetEntry.SymlinkBehavior");
+ }
+ }
+
+ /**
+ * An adapter used by {@link #writeAttributeValueToBuilder} in order to reuse the same code for
+ * writing to both {@link Build.Attribute.Builder} and {@link SelectorEntry.Builder} objects.
+ */
+ private interface AttributeValueBuilderAdapter {
+
+ void addStringListValue(String s);
+
+ void addFilesetListValue(Build.FilesetEntry.Builder builder);
+
+ void addGlobCriteria(Build.GlobCriteria.Builder builder);
+
+ void addLabelDictUnaryValue(LabelDictUnaryEntry.Builder builder);
+
+ void addLabelListDictValue(LabelListDictEntry.Builder builder);
+
+ void addIntListValue(int i);
+
+ void addStringDictUnaryValue(StringDictUnaryEntry.Builder builder);
+
+ void addStringDictValue(StringDictEntry.Builder builder);
+
+ void addStringListDictValue(StringListDictEntry.Builder builder);
+
+ void setBooleanValue(boolean b);
+
+ void setIntValue(int i);
+
+ void setLicense(Build.License.Builder builder);
+
+ void setStringValue(String s);
+
+ void setTristateValue(Tristate tristate);
+ }
+
+ /**
+ * An {@link AttributeValueBuilderAdapter} which writes to a {@link Build.Attribute.Builder}.
+ *
+ * <p>If {@param encodeBooleanAndTriStateAsIntegerAndString} is {@code true}, then {@link
+ * Boolean} and {@link TriState} attribute values also write to the integer and string fields.
+ * This offers backwards compatibility to clients that expect attribute values of those types.
+ */
+ private static class AttributeBuilderAdapter implements AttributeValueBuilderAdapter {
+ private final boolean encodeBooleanAndTriStateAsIntegerAndString;
+ private final Build.Attribute.Builder attributeBuilder;
+
+ private AttributeBuilderAdapter(
+ Build.Attribute.Builder attributeBuilder,
+ boolean encodeBooleanAndTriStateAsIntegerAndString) {
+ this.attributeBuilder = Preconditions.checkNotNull(attributeBuilder);
+ this.encodeBooleanAndTriStateAsIntegerAndString = encodeBooleanAndTriStateAsIntegerAndString;
+ }
+
+ public void addStringListValue(String s) {
+ attributeBuilder.addStringListValue(s);
+ }
+
+ @Override
+ public void addFilesetListValue(Build.FilesetEntry.Builder builder) {
+ attributeBuilder.addFilesetListValue(builder);
+ }
+
+ @Override
+ public void addGlobCriteria(Build.GlobCriteria.Builder builder) {
+ attributeBuilder.addGlobCriteria(builder);
+ }
+
+ @Override
+ public void addLabelDictUnaryValue(LabelDictUnaryEntry.Builder builder) {
+ attributeBuilder.addLabelDictUnaryValue(builder);
+ }
+
+ @Override
+ public void addLabelListDictValue(LabelListDictEntry.Builder builder) {
+ attributeBuilder.addLabelListDictValue(builder);
+ }
+
+ @Override
+ public void addIntListValue(int i) {
+ attributeBuilder.addIntListValue(i);
+ }
+
+ @Override
+ public void addStringDictUnaryValue(StringDictUnaryEntry.Builder builder) {
+ attributeBuilder.addStringDictUnaryValue(builder);
+ }
+
+ @Override
+ public void addStringDictValue(StringDictEntry.Builder builder) {
+ attributeBuilder.addStringDictValue(builder);
+ }
+
+ @Override
+ public void addStringListDictValue(StringListDictEntry.Builder builder) {
+ attributeBuilder.addStringListDictValue(builder);
+ }
+
+ @Override
+ public void setBooleanValue(boolean b) {
+ if (b) {
+ attributeBuilder.setBooleanValue(true);
+ if (encodeBooleanAndTriStateAsIntegerAndString) {
+ attributeBuilder.setStringValue("true");
+ attributeBuilder.setIntValue(1);
+ }
+ } else {
+ attributeBuilder.setBooleanValue(false);
+ if (encodeBooleanAndTriStateAsIntegerAndString) {
+ attributeBuilder.setStringValue("false");
+ attributeBuilder.setIntValue(0);
+ }
+ }
+ }
+
+ @Override
+ public void setIntValue(int i) {
+ attributeBuilder.setIntValue(i);
+ }
+
+ @Override
+ public void setLicense(Build.License.Builder builder) {
+ attributeBuilder.setLicense(builder);
+ }
+
+ @Override
+ public void setStringValue(String s) {
+ attributeBuilder.setStringValue(s);
+ }
+
+ @Override
+ public void setTristateValue(Tristate tristate) {
+ switch (tristate) {
+ case AUTO:
+ attributeBuilder.setTristateValue(Tristate.AUTO);
+ if (encodeBooleanAndTriStateAsIntegerAndString) {
+ attributeBuilder.setIntValue(-1);
+ attributeBuilder.setStringValue("auto");
+ }
+ break;
+ case NO:
+ attributeBuilder.setTristateValue(Tristate.NO);
+ if (encodeBooleanAndTriStateAsIntegerAndString) {
+ attributeBuilder.setIntValue(0);
+ attributeBuilder.setStringValue("no");
+ }
+ break;
+ case YES:
+ attributeBuilder.setTristateValue(Tristate.YES);
+ if (encodeBooleanAndTriStateAsIntegerAndString) {
+ attributeBuilder.setIntValue(1);
+ attributeBuilder.setStringValue("yes");
+ }
+ break;
+ default:
+ throw new AssertionError("Expected AUTO/NO/YES to cover all possible cases");
+ }
+ }
+ }
+
+ /**
+ * An {@link AttributeValueBuilderAdapter} which writes to a {@link SelectorEntry.Builder}.
+ *
+ * <p>Note that there is no {@code encodeBooleanAndTriStateAsIntegerAndString} parameter needed
+ * here. This is because the clients that expect those alternate encodings of boolean and
+ * tristate attribute values do not support {@link SelectorList} values. When providing output to
+ * those clients, we compute the set of possible attribute values (expanding {@link SelectorList}
+ * values, evaluating computed defaults, and flattening collections of collections; see {@link
+ * com.google.devtools.build.lib.packages.AggregatingAttributeMapper#getPossibleAttributeValues}
+ * and {@link
+ * com.google.devtools.build.lib.packages.AggregatingAttributeMapper#flattenAttributeValues}).
+ */
+ private static class SelectorEntryBuilderAdapter implements AttributeValueBuilderAdapter {
+ private final SelectorEntry.Builder selectorEntryBuilder;
+
+ private SelectorEntryBuilderAdapter(Builder selectorEntryBuilder) {
+ this.selectorEntryBuilder = Preconditions.checkNotNull(selectorEntryBuilder);
+ }
+
+ public void addStringListValue(String s) {
+ selectorEntryBuilder.addStringListValue(s);
+ }
+
+ @Override
+ public void addFilesetListValue(Build.FilesetEntry.Builder builder) {
+ selectorEntryBuilder.addFilesetListValue(builder);
+ }
+
+ @Override
+ public void addGlobCriteria(Build.GlobCriteria.Builder builder) {
+ selectorEntryBuilder.addGlobCriteria(builder);
+ }
+
+ @Override
+ public void addLabelDictUnaryValue(LabelDictUnaryEntry.Builder builder) {
+ selectorEntryBuilder.addLabelDictUnaryValue(builder);
+ }
+
+ @Override
+ public void addLabelListDictValue(LabelListDictEntry.Builder builder) {
+ selectorEntryBuilder.addLabelListDictValue(builder);
+ }
+
+ @Override
+ public void addIntListValue(int i) {
+ selectorEntryBuilder.addIntListValue(i);
+ }
+
+ @Override
+ public void addStringDictUnaryValue(StringDictUnaryEntry.Builder builder) {
+ selectorEntryBuilder.addStringDictUnaryValue(builder);
+ }
+
+ @Override
+ public void addStringDictValue(StringDictEntry.Builder builder) {
+ selectorEntryBuilder.addStringDictValue(builder);
+ }
+
+ @Override
+ public void addStringListDictValue(StringListDictEntry.Builder builder) {
+ selectorEntryBuilder.addStringListDictValue(builder);
+ }
+
+ @Override
+ public void setBooleanValue(boolean b) {
+ selectorEntryBuilder.setBooleanValue(b);
+ }
+
+ @Override
+ public void setIntValue(int i) {
+ selectorEntryBuilder.setIntValue(i);
+ }
+
+ @Override
+ public void setLicense(Build.License.Builder builder) {
+ selectorEntryBuilder.setLicense(builder);
+ }
+
+ @Override
+ public void setStringValue(String s) {
+ selectorEntryBuilder.setStringValue(s);
+ }
+
+ @Override
+ public void setTristateValue(Tristate tristate) {
+ selectorEntryBuilder.setTristateValue(tristate);
+ }
+ }
+}
+