All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.messaging.rsocket.DefaultMetadataExtractor Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2019 the original author or 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
 *
 *      https://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 org.springframework.messaging.rsocket;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.rsocket.Payload;
import io.rsocket.metadata.CompositeMetadata;
import io.rsocket.metadata.RoutingMetadata;
import io.rsocket.metadata.WellKnownMimeType;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Decoder;
import org.springframework.core.io.buffer.NettyDataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.MimeType;

/**
 * Default {@link MetadataExtractor} implementation that relies on
 * {@link Decoder}s to deserialize the content of metadata entries.
 * 

By default only {@code "message/x.rsocket.routing.v0""} is extracted and * saved under {@link MetadataExtractor#ROUTE_KEY}. Use {@code metadataToExtract} * methods to specify other metadata mime types of interest to extract. * * @author Rossen Stoyanchev * @since 5.2 */ public class DefaultMetadataExtractor implements MetadataExtractor, MetadataExtractorRegistry { private final List> decoders; private final Map> registrations = new HashMap<>(); /** * Constructor with decoders for de-serializing metadata entries. */ public DefaultMetadataExtractor(Decoder... decoders) { this(Arrays.asList(decoders)); } /** * Constructor with list of decoders for de-serializing metadata entries. */ public DefaultMetadataExtractor(List> decoders) { this.decoders = Collections.unmodifiableList(new ArrayList<>(decoders)); } /** * Return a read-only list with the configured decoders. */ public List> getDecoders() { return this.decoders; } @Override public void metadataToExtract( MimeType mimeType, Class targetType, BiConsumer> mapper) { registerMetadata(mimeType, ResolvableType.forClass(targetType), mapper); } @Override public void metadataToExtract( MimeType mimeType, ParameterizedTypeReference type, BiConsumer> mapper) { registerMetadata(mimeType, ResolvableType.forType(type), mapper); } @SuppressWarnings("unchecked") private void registerMetadata( MimeType mimeType, ResolvableType targetType, BiConsumer> mapper) { for (Decoder decoder : this.decoders) { if (decoder.canDecode(targetType, mimeType)) { this.registrations.put(mimeType.toString(), new EntryExtractor<>((Decoder) decoder, mimeType, targetType, mapper)); return; } } throw new IllegalArgumentException("No decoder for " + mimeType + " and " + targetType); } @Override public Map extract(Payload payload, MimeType metadataMimeType) { Map result = new HashMap<>(); if (metadataMimeType.toString().equals(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.toString())) { for (CompositeMetadata.Entry entry : new CompositeMetadata(payload.metadata(), false)) { extractEntry(entry.getContent(), entry.getMimeType(), result); } } else { extractEntry(payload.metadata().slice(), metadataMimeType.toString(), result); } return result; } private void extractEntry(ByteBuf content, @Nullable String mimeType, Map result) { if (content.readableBytes() == 0) { return; } EntryExtractor extractor = this.registrations.get(mimeType); if (extractor != null) { extractor.extract(content, result); return; } if (mimeType != null && mimeType.equals(WellKnownMimeType.MESSAGE_RSOCKET_ROUTING.getString())) { Iterator iterator = new RoutingMetadata(content).iterator(); if (iterator.hasNext()) { result.put(MetadataExtractor.ROUTE_KEY, iterator.next()); } } } private static class EntryExtractor { // We only need this to wrap ByteBufs private final static NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); private final Decoder decoder; private final MimeType mimeType; private final ResolvableType targetType; private final BiConsumer> accumulator; EntryExtractor(Decoder decoder, MimeType mimeType, ResolvableType targetType, BiConsumer> accumulator) { this.decoder = decoder; this.mimeType = mimeType; this.targetType = targetType; this.accumulator = accumulator; } public void extract(ByteBuf content, Map result) { NettyDataBuffer dataBuffer = bufferFactory.wrap(content.retain()); T value = this.decoder.decode(dataBuffer, this.targetType, this.mimeType, Collections.emptyMap()); this.accumulator.accept(value, result); } @Override public String toString() { return "mimeType=" + this.mimeType + ", targetType=" + this.targetType; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy