001package io.jstach.opt.spring.webflux;
002
003import java.util.Map;
004
005import org.eclipse.jdt.annotation.Nullable;
006import org.springframework.core.ResolvableType;
007import org.springframework.core.codec.AbstractSingleValueEncoder;
008import org.springframework.core.codec.Hints;
009import org.springframework.core.io.buffer.DataBuffer;
010import org.springframework.core.io.buffer.DataBufferFactory;
011import org.springframework.http.MediaType;
012import org.springframework.util.MimeType;
013
014import io.jstach.jstachio.JStachio;
015import io.jstach.jstachio.Template;
016import reactor.core.publisher.Flux;
017
018/**
019 * Encodes a JStachio model into a bytes to be used as output from a webflux reactive
020 * controller.
021 *
022 * @author agentgt
023 * @author dsyer
024 */
025@SuppressWarnings("exports")
026public class JStachioEncoder extends AbstractSingleValueEncoder<Object> {
027
028        private final JStachio jstachio;
029
030        private final int allocateBufferSize;
031
032        /**
033         * Create the encoder from a JStachio
034         * @param jstachio not <code>null</code>.
035         */
036        public JStachioEncoder(JStachio jstachio) {
037                this(jstachio, 4 * 1024);
038        }
039
040        /**
041         * Create the encoder from a JStachio
042         * @param jstachio not <code>null</code>.
043         * @param allocateBufferSize how much to initially allocate from the buffer factory
044         */
045        public JStachioEncoder(JStachio jstachio, int allocateBufferSize) {
046                super(MediaType.TEXT_HTML);
047                this.jstachio = jstachio;
048                this.allocateBufferSize = allocateBufferSize;
049        }
050
051        @Override
052        public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) {
053                Class<?> clazz = elementType.toClass();
054                return clazz != Object.class && !CharSequence.class.isAssignableFrom(clazz) && jstachio.supportsType(clazz);
055        }
056
057        @Override
058        protected Flux<DataBuffer> encode(Object event, DataBufferFactory bufferFactory, ResolvableType type,
059                        @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
060                return Flux.just(encodeValue(event, bufferFactory, type, mimeType, hints));
061        }
062
063        @Override
064        public DataBuffer encodeValue(Object event, DataBufferFactory bufferFactory, ResolvableType valueType,
065                        MimeType mimeType, Map<String, Object> hints) {
066                if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
067                        String logPrefix = Hints.getLogPrefix(hints);
068                        logger.debug(logPrefix + "Writing [" + event + "]");
069                }
070
071                Template<Object> template;
072                try {
073                        template = jstachio.findTemplate(event);
074                }
075                catch (Exception e) {
076                        throw new RuntimeException(e);
077                }
078
079                DataBufferOutput output = new DataBufferOutput(bufferFactory.allocateBuffer(allocateBufferSize),
080                                template.templateCharset());
081
082                return template.write(event, output).getBuffer();
083
084        }
085
086}