blob: 4f32e182c37d560c6355691ad909fe3847f1fee5 [file] [log] [blame]
lryane4bd1c72014-09-08 14:03:35 -07001package com.google.net.stubby;
2
ejona8c76c8a2014-10-09 09:53:41 -07003import static com.google.common.base.Charsets.US_ASCII;
lryane4bd1c72014-09-08 14:03:35 -07004
lryane4bd1c72014-09-08 14:03:35 -07005import com.google.common.base.Function;
6import com.google.common.base.Preconditions;
7import com.google.common.collect.Iterables;
lryane4bd1c72014-09-08 14:03:35 -07008import com.google.common.collect.LinkedListMultimap;
9import com.google.common.collect.ListMultimap;
10import com.google.common.collect.Lists;
11
lryane4bd1c72014-09-08 14:03:35 -070012import java.util.Iterator;
13import java.util.List;
14import java.util.Map;
15import java.util.Set;
16
17import javax.annotation.concurrent.NotThreadSafe;
18
19/**
20 * Provides access to read and write metadata values to be exchanged during a call.
21 * <p>
22 * This class is not thread safe, implementations should ensure that header reads and writes
23 * do not occur in multiple threads concurrently.
24 * </p>
25 */
26@NotThreadSafe
lryan1369ea12014-09-23 10:36:55 -070027public abstract class Metadata {
lryane4bd1c72014-09-08 14:03:35 -070028
29 /**
zhangkun2b116ef2014-12-03 20:28:00 -080030 * All binary headers should have this suffix in their names. Vice versa.
31 */
32 public static final String BINARY_HEADER_SUFFIX = "-bin";
33
34 /**
lryane4bd1c72014-09-08 14:03:35 -070035 * Interleave keys and values into a single iterator.
36 */
37 private static Iterator<String> fromMapEntries(Iterable<Map.Entry<String, String>> entries) {
38 final Iterator<Map.Entry<String, String>> iterator = entries.iterator();
39 return new Iterator<String>() {
40 Map.Entry<String, String> last;
41 @Override
42 public boolean hasNext() {
43 return last != null || iterator.hasNext();
44 }
45
46 @Override
47 public String next() {
48 if (last == null) {
49 last = iterator.next();
50 return last.getKey();
51 } else {
52 String val = last.getValue();
53 last = null;
54 return val;
55 }
56 }
57
58 @Override
59 public void remove() {
60 throw new UnsupportedOperationException();
61 }
62 };
63 }
64
65 /**
zhangkun2b116ef2014-12-03 20:28:00 -080066 * Simple metadata marshaller that encodes strings as is.
67 *
68 * <p>This should be used with ASCII strings that only contain printable characters and space.
69 * Otherwise the output may be considered invalid and discarded by the transport.
lryane4bd1c72014-09-08 14:03:35 -070070 */
zhangkun2b116ef2014-12-03 20:28:00 -080071 public static final AsciiMarshaller<String> ASCII_STRING_MARSHALLER =
72 new AsciiMarshaller<String>() {
lryane4bd1c72014-09-08 14:03:35 -070073
74 @Override
zhangkun2b116ef2014-12-03 20:28:00 -080075 public String toAsciiString(String value) {
lryane4bd1c72014-09-08 14:03:35 -070076 return value;
77 }
78
79 @Override
zhangkun2b116ef2014-12-03 20:28:00 -080080 public String parseAsciiString(String serialized) {
81 return serialized;
lryane4bd1c72014-09-08 14:03:35 -070082 }
83 };
84
ejona9d502992014-09-22 12:23:19 -070085 /**
zhangkun2b116ef2014-12-03 20:28:00 -080086 * Simple metadata marshaller that encodes an integer as a signed decimal string.
ejona9d502992014-09-22 12:23:19 -070087 */
zhangkun2b116ef2014-12-03 20:28:00 -080088 public static final AsciiMarshaller<Integer> INTEGER_MARSHALLER = new AsciiMarshaller<Integer>() {
ejona9d502992014-09-22 12:23:19 -070089
90 @Override
zhangkun2b116ef2014-12-03 20:28:00 -080091 public String toAsciiString(Integer value) {
ejona9d502992014-09-22 12:23:19 -070092 return value.toString();
93 }
94
95 @Override
zhangkun2b116ef2014-12-03 20:28:00 -080096 public Integer parseAsciiString(String serialized) {
97 return Integer.parseInt(serialized);
ejona9d502992014-09-22 12:23:19 -070098 }
99 };
100
lryane4bd1c72014-09-08 14:03:35 -0700101 private final ListMultimap<String, MetadataEntry> store;
102 private final boolean serializable;
103
104 /**
105 * Constructor called by the transport layer when it receives binary metadata.
106 */
107 // TODO(user): Convert to use ByteString so we can cache transformations
108 private Metadata(byte[]... binaryValues) {
109 store = LinkedListMultimap.create();
110 for (int i = 0; i < binaryValues.length; i++) {
ejona8c76c8a2014-10-09 09:53:41 -0700111 String name = new String(binaryValues[i], US_ASCII);
lryane4bd1c72014-09-08 14:03:35 -0700112 store.put(name, new MetadataEntry(binaryValues[++i]));
113 }
114 this.serializable = false;
115 }
116
117 /**
lryane4bd1c72014-09-08 14:03:35 -0700118 * Constructor called by the application layer when it wants to send metadata.
119 */
120 private Metadata() {
121 store = LinkedListMultimap.create();
122 this.serializable = true;
123 }
124
125 /**
126 * Returns true if a value is defined for the given key.
127 */
nathanmittler0304b3d2014-10-24 13:39:13 -0700128 public boolean containsKey(Key<?> key) {
lryane4bd1c72014-09-08 14:03:35 -0700129 return store.containsKey(key.name);
130 }
131
132 /**
133 * Returns the last metadata entry added with the name 'name' parsed as T.
lryan1369ea12014-09-23 10:36:55 -0700134 * @return the parsed metadata entry or null if there are none.
lryane4bd1c72014-09-08 14:03:35 -0700135 */
136 public <T> T get(Key<T> key) {
lryan1369ea12014-09-23 10:36:55 -0700137 if (containsKey(key)) {
138 MetadataEntry metadataEntry = Iterables.getLast(store.get(key.name()));
139 return metadataEntry.getParsed(key);
140 }
141 return null;
lryane4bd1c72014-09-08 14:03:35 -0700142 }
143
144 /**
145 * Returns all the metadata entries named 'name', in the order they were received,
lryan1369ea12014-09-23 10:36:55 -0700146 * parsed as T or null if there are none.
lryane4bd1c72014-09-08 14:03:35 -0700147 */
148 public <T> Iterable<T> getAll(final Key<T> key) {
lryan1369ea12014-09-23 10:36:55 -0700149 if (containsKey(key)) {
150 return Iterables.transform(
151 store.get(key.name()),
152 new Function<MetadataEntry, T>() {
153 @Override
154 public T apply(MetadataEntry entry) {
155 return entry.getParsed(key);
156 }
157 });
158 }
159 return null;
lryane4bd1c72014-09-08 14:03:35 -0700160 }
161
162 public <T> void put(Key<T> key, T value) {
163 store.put(key.name(), new MetadataEntry(key, value));
164 }
165
166 /**
167 * Remove a specific value.
168 */
169 public <T> boolean remove(Key<T> key, T value) {
170 return store.remove(key.name(), value);
171 }
172
173 /**
174 * Remove all values for the given key.
175 */
176 public <T> List<T> removeAll(final Key<T> key) {
177 return Lists.transform(store.removeAll(key.name()), new Function<MetadataEntry, T>() {
178 @Override
179 public T apply(MetadataEntry metadataEntry) {
180 return metadataEntry.getParsed(key);
181 }
182 });
183 }
184
185 /**
186 * Can this metadata be serialized. Metadata constructed from raw binary or ascii values
187 * cannot be serialized without merging it into a serializable instance using
188 * {@link #merge(Metadata, java.util.Set)}
189 */
190 public boolean isSerializable() {
191 return serializable;
192 }
193
194 /**
zhangkun2b116ef2014-12-03 20:28:00 -0800195 * Serialize all the metadata entries.
196 *
197 * <p>It produces serialized names and values interleaved. result[i*2] are names, while
198 * result[i*2+1] are values.
199 *
200 * <p>Names are ASCII string bytes. If the name ends with "-bin", the value can be raw binary.
201 * Otherwise, the value must be printable ASCII characters or space.
lryane4bd1c72014-09-08 14:03:35 -0700202 */
203 public byte[][] serialize() {
204 Preconditions.checkState(serializable, "Can't serialize raw metadata");
205 byte[][] serialized = new byte[store.size() * 2][];
206 int i = 0;
207 for (Map.Entry<String, MetadataEntry> entry : store.entries()) {
208 serialized[i++] = entry.getValue().key.asciiName();
209 serialized[i++] = entry.getValue().getSerialized();
210 }
211 return serialized;
212 }
213
214 /**
lryane4bd1c72014-09-08 14:03:35 -0700215 * Perform a simple merge of two sets of metadata.
216 * <p>
217 * Note that we can't merge non-serializable metadata into serializable.
218 * </p>
219 */
220 public void merge(Metadata other) {
221 Preconditions.checkNotNull(other);
222 if (this.serializable) {
223 if (!other.serializable) {
224 throw new IllegalArgumentException(
225 "Cannot merge non-serializable metadata into serializable metadata without keys");
226 }
227 }
228 store.putAll(other.store);
229 }
230
231 /**
232 * Merge values for the given set of keys into this set of metadata.
233 */
nathanmittler0304b3d2014-10-24 13:39:13 -0700234 @SuppressWarnings({"rawtypes", "unchecked"})
235 public void merge(Metadata other, Set<Key<?>> keys) {
lryane4bd1c72014-09-08 14:03:35 -0700236 Preconditions.checkNotNull(other);
nathanmittler0304b3d2014-10-24 13:39:13 -0700237 for (Key<?> key : keys) {
lryane4bd1c72014-09-08 14:03:35 -0700238 if (other.containsKey(key)) {
nathanmittler0304b3d2014-10-24 13:39:13 -0700239 Iterable<?> values = other.getAll(key);
lryane4bd1c72014-09-08 14:03:35 -0700240 for (Object value : values) {
nathanmittler0304b3d2014-10-24 13:39:13 -0700241 put((Key) key, value);
lryane4bd1c72014-09-08 14:03:35 -0700242 }
243 }
244 }
245 }
246
247 /**
248 * Concrete instance for metadata attached to the start of a call.
249 */
lryan1369ea12014-09-23 10:36:55 -0700250 public static class Headers extends Metadata {
lryane4bd1c72014-09-08 14:03:35 -0700251 private String path;
252 private String authority;
253
254 /**
255 * Called by the transport layer to create headers from their binary serialized values.
256 */
257 public Headers(byte[]... headers) {
258 super(headers);
259 }
260
261 /**
lryane4bd1c72014-09-08 14:03:35 -0700262 * Called by the application layer to construct headers prior to passing them to the
263 * transport for serialization.
264 */
265 public Headers() {
266 }
267
268 /**
269 * The path for the operation.
270 */
271 public String getPath() {
272 return path;
273 }
274
275 public void setPath(String path) {
276 this.path = path;
277 }
278
279 /**
280 * The serving authority for the operation.
281 */
282 public String getAuthority() {
283 return authority;
284 }
285
286 public void setAuthority(String authority) {
287 this.authority = authority;
288 }
nathanmittler23fbc7c2014-09-11 12:50:16 -0700289
290 @Override
291 public void merge(Metadata other) {
292 super.merge(other);
293 mergePathAndAuthority(other);
294 }
295
296 @Override
nathanmittler0304b3d2014-10-24 13:39:13 -0700297 public void merge(Metadata other, Set<Key<?>> keys) {
nathanmittler23fbc7c2014-09-11 12:50:16 -0700298 super.merge(other, keys);
299 mergePathAndAuthority(other);
300 }
301
302 private void mergePathAndAuthority(Metadata other) {
303 if (other instanceof Headers) {
304 Headers otherHeaders = (Headers) other;
305 path = otherHeaders.path != null ? otherHeaders.path : path;
306 authority = otherHeaders.authority != null ? otherHeaders.authority : authority;
307 }
308 }
lryane4bd1c72014-09-08 14:03:35 -0700309 }
310
311 /**
312 * Concrete instance for metadata attached to the end of the call. Only provided by
313 * servers.
314 */
lryan1369ea12014-09-23 10:36:55 -0700315 public static class Trailers extends Metadata {
lryane4bd1c72014-09-08 14:03:35 -0700316 /**
317 * Called by the transport layer to create trailers from their binary serialized values.
318 */
319 public Trailers(byte[]... headers) {
320 super(headers);
321 }
322
323 /**
lryane4bd1c72014-09-08 14:03:35 -0700324 * Called by the application layer to construct trailers prior to passing them to the
325 * transport for serialization.
326 */
327 public Trailers() {
328 }
329 }
330
331
332 /**
zhangkun2b116ef2014-12-03 20:28:00 -0800333 * Marshaller for metadata values that are serialized into raw binary.
lryane4bd1c72014-09-08 14:03:35 -0700334 */
zhangkun2b116ef2014-12-03 20:28:00 -0800335 public static interface BinaryMarshaller<T> {
lryane4bd1c72014-09-08 14:03:35 -0700336 /**
337 * Serialize a metadata value to bytes.
338 * @param value to serialize
zhangkun2b116ef2014-12-03 20:28:00 -0800339 * @return serialized version of value
lryane4bd1c72014-09-08 14:03:35 -0700340 */
341 public byte[] toBytes(T value);
342
343 /**
lryane4bd1c72014-09-08 14:03:35 -0700344 * Parse a serialized metadata value from bytes.
345 * @param serialized value of metadata to parse
346 * @return a parsed instance of type T
347 */
348 public T parseBytes(byte[] serialized);
zhangkun2b116ef2014-12-03 20:28:00 -0800349 }
350
351 /**
352 * Marshaller for metadata values that are serialized into ASCII strings that contain only
353 * printable characters and space.
354 */
355 public static interface AsciiMarshaller<T> {
356 /**
357 * Serialize a metadata value to a ASCII string that contains only printable characters and
358 * space.
359 *
360 * @param value to serialize
361 * @return serialized version of value, or null if value cannot be transmitted.
362 */
363 public String toAsciiString(T value);
lryane4bd1c72014-09-08 14:03:35 -0700364
365 /**
zhangkun2b116ef2014-12-03 20:28:00 -0800366 * Parse a serialized metadata value from an ASCII string.
367 * @param serialized value of metadata to parse
lryane4bd1c72014-09-08 14:03:35 -0700368 * @return a parsed instance of type T
369 */
zhangkun2b116ef2014-12-03 20:28:00 -0800370 public T parseAsciiString(String serialized);
lryane4bd1c72014-09-08 14:03:35 -0700371 }
372
373 /**
374 * Key for metadata entries. Allows for parsing and serialization of metadata.
375 */
zhangkun2b116ef2014-12-03 20:28:00 -0800376 public abstract static class Key<T> {
377
378 /**
379 * Creates a key for a binary header.
380 *
381 * @param name must end with {@link BINARY_HEADER_SUFFIX}
382 */
383 public static <T> Key<T> of(String name, BinaryMarshaller<T> marshaller) {
384 return new BinaryKey<T>(name, marshaller);
385 }
386
387 /**
388 * Creates a key for a ASCII header.
389 *
390 * @param name must not end with {@link BINARY_HEADER_SUFFIX}
391 */
392 public static <T> Key<T> of(String name, AsciiMarshaller<T> marshaller) {
393 return new AsciiKey<T>(name, marshaller);
ejona9d502992014-09-22 12:23:19 -0700394 }
lryane4bd1c72014-09-08 14:03:35 -0700395
396 private final String name;
397 private final byte[] asciiName;
lryane4bd1c72014-09-08 14:03:35 -0700398
zhangkun2b116ef2014-12-03 20:28:00 -0800399 private Key(String name) {
lryan1369ea12014-09-23 10:36:55 -0700400 this.name = Preconditions.checkNotNull(name, "name").toLowerCase().intern();
lryan28497e32014-10-17 16:14:38 -0700401 this.asciiName = this.name.getBytes(US_ASCII);
lryane4bd1c72014-09-08 14:03:35 -0700402 }
403
404 public String name() {
405 return name;
406 }
407
lryan1369ea12014-09-23 10:36:55 -0700408 // TODO (lryan): Migrate to ByteString
409 public byte[] asciiName() {
lryane4bd1c72014-09-08 14:03:35 -0700410 return asciiName;
411 }
412
lryan1369ea12014-09-23 10:36:55 -0700413 @Override
414 public boolean equals(Object o) {
415 if (this == o) return true;
416 if (o == null || getClass() != o.getClass()) return false;
nathanmittler0304b3d2014-10-24 13:39:13 -0700417 Key<?> key = (Key<?>) o;
lryan1369ea12014-09-23 10:36:55 -0700418 return !(name != null ? !name.equals(key.name) : key.name != null);
419 }
420
421 @Override
422 public int hashCode() {
423 return name != null ? name.hashCode() : 0;
424 }
425
426 @Override
427 public String toString() {
428 return "Key{name='" + name + "'}";
429 }
zhangkun2b116ef2014-12-03 20:28:00 -0800430
431 /**
432 * Serialize a metadata value to bytes.
433 * @param value to serialize
434 * @return serialized version of value
435 */
436 abstract byte[] toBytes(T value);
437
438 /**
439 * Parse a serialized metadata value from bytes.
440 * @param serialized value of metadata to parse
441 * @return a parsed instance of type T
442 */
443 abstract T parseBytes(byte[] serialized);
444 }
445
446 private static class BinaryKey<T> extends Key<T> {
447 private final BinaryMarshaller<T> marshaller;
448
449 /**
450 * Keys have a name and a binary marshaller used for serialization.
451 */
452 private BinaryKey(String name, BinaryMarshaller<T> marshaller) {
453 super(name);
454 Preconditions.checkArgument(name.endsWith(BINARY_HEADER_SUFFIX),
455 "Binary header is named " + name + ". It must end with " + BINARY_HEADER_SUFFIX);
456 this.marshaller = Preconditions.checkNotNull(marshaller);
457 }
458
459 @Override
460 byte[] toBytes(T value) {
461 return marshaller.toBytes(value);
462 }
463
464 @Override
465 T parseBytes(byte[] serialized) {
466 return marshaller.parseBytes(serialized);
467 }
468 }
469
470 private static class AsciiKey<T> extends Key<T> {
471 private final AsciiMarshaller<T> marshaller;
472
473 /**
474 * Keys have a name and an ASCII marshaller used for serialization.
475 */
476 private AsciiKey(String name, AsciiMarshaller<T> marshaller) {
477 super(name);
478 Preconditions.checkArgument(!name.endsWith(BINARY_HEADER_SUFFIX),
479 "ASCII header is named " + name + ". It must not end with " + BINARY_HEADER_SUFFIX);
480 this.marshaller = Preconditions.checkNotNull(marshaller);
481 }
482
483 @Override
484 byte[] toBytes(T value) {
485 return marshaller.toAsciiString(value).getBytes(US_ASCII);
486 }
487
488 @Override
489 T parseBytes(byte[] serialized) {
490 return marshaller.parseAsciiString(new String(serialized, US_ASCII));
491 }
lryane4bd1c72014-09-08 14:03:35 -0700492 }
493
494 private static class MetadataEntry {
495 Object parsed;
nathanmittler0304b3d2014-10-24 13:39:13 -0700496
497 @SuppressWarnings("rawtypes")
lryane4bd1c72014-09-08 14:03:35 -0700498 Key key;
499 byte[] serializedBinary;
lryane4bd1c72014-09-08 14:03:35 -0700500
501 /**
502 * Constructor used when application layer adds a parsed value.
503 */
nathanmittler0304b3d2014-10-24 13:39:13 -0700504 private MetadataEntry(Key<?> key, Object parsed) {
lryane4bd1c72014-09-08 14:03:35 -0700505 this.parsed = Preconditions.checkNotNull(parsed);
506 this.key = Preconditions.checkNotNull(key);
507 }
508
509 /**
510 * Constructor used when reading a value from the transport.
511 */
512 private MetadataEntry(byte[] serialized) {
513 Preconditions.checkNotNull(serialized);
514 this.serializedBinary = serialized;
515 }
516
nathanmittler0304b3d2014-10-24 13:39:13 -0700517 @SuppressWarnings("unchecked")
lryane4bd1c72014-09-08 14:03:35 -0700518 public <T> T getParsed(Key<T> key) {
lryane4bd1c72014-09-08 14:03:35 -0700519 T value = (T) parsed;
520 if (value != null) {
521 if (this.key != key) {
522 // Keys don't match so serialize using the old key
zhangkun2b116ef2014-12-03 20:28:00 -0800523 serializedBinary = this.key.toBytes(value);
lryane4bd1c72014-09-08 14:03:35 -0700524 } else {
525 return value;
526 }
527 }
528 this.key = key;
529 if (serializedBinary != null) {
zhangkun2b116ef2014-12-03 20:28:00 -0800530 value = key.parseBytes(serializedBinary);
lryane4bd1c72014-09-08 14:03:35 -0700531 }
532 parsed = value;
533 return value;
534 }
535
536 @SuppressWarnings("unchecked")
537 public byte[] getSerialized() {
538 return serializedBinary =
539 serializedBinary == null
zhangkun2b116ef2014-12-03 20:28:00 -0800540 ? key.toBytes(parsed) : serializedBinary;
lryane4bd1c72014-09-08 14:03:35 -0700541 }
542 }
543}