001/* 002 * This file is part of the JDrupes non-blocking HTTP Codec 003 * Copyright (C) 2016, 2017 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Lesser General Public License as published 007 * by the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 013 * License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.httpcodec; 020 021import java.nio.Buffer; 022import java.nio.ByteBuffer; 023import java.util.Optional; 024 025import org.jdrupes.httpcodec.Codec.ProtocolSwitchResult; 026 027/** 028 * An engine that can be used as a server. It has an associated 029 * request decoder and response encoder. Using a {@link ServerEngine} 030 * has two main advantages over using an encoder and decoder 031 * directly. It links encoder and decoder (see 032 * {@link Encoder#setPeerDecoder(Decoder)} and 033 * {@link Decoder#setPeerEncoder(Encoder)}) and it replaces the encoder 034 * and decoder if the encoded result indicates a switch. 035 * 036 * @param <Q> the message header type handled by the decoder (the request) 037 * @param <R> the message header type handled be the encoder (the response) 038 */ 039public class ServerEngine<Q extends MessageHeader, R extends MessageHeader> 040 extends Engine { 041 042 private Decoder<?, ?> requestDecoder; 043 private Encoder<?, ?> responseEncoder; 044 045 /** 046 * Creates a new instance. 047 * 048 * @param requestDecoder the decoder for the request 049 * @param responseEncoder the encoder for the response 050 */ 051 public ServerEngine(Decoder<Q, R> requestDecoder, 052 Encoder<R, Q> responseEncoder) { 053 this.requestDecoder = requestDecoder; 054 this.responseEncoder = responseEncoder; 055 responseEncoder.setPeerDecoder(requestDecoder); 056 requestDecoder.setPeerEncoder(responseEncoder); 057 } 058 059 /** 060 * Returns the request decoder. 061 * 062 * @return the request decoder 063 */ 064 @SuppressWarnings("unchecked") 065 public Decoder<Q, R> requestDecoder() { 066 return (Decoder<Q, R>)requestDecoder; 067 } 068 069 /** 070 * Returns the response encoder. 071 * 072 * @return the response encoder 073 */ 074 @SuppressWarnings("unchecked") 075 public Encoder<R, Q> responseEncoder() { 076 return (Encoder<R, Q>)responseEncoder; 077 } 078 079 /** 080 * Returns the type of the messages decoded by this server. 081 * 082 * @return the value 083 */ 084 public Class<? extends MessageHeader> decoding() { 085 return requestDecoder.decoding(); 086 } 087 088 /** 089 * Returns the type of the messages encoded by this server. 090 * 091 * @return the value 092 */ 093 public Class<? extends MessageHeader> encoding() { 094 return responseEncoder.encoding(); 095 } 096 097 /** 098 * Decodes a request sent to the server. 099 * 100 * @param in the data to decode 101 * @param out the decoded data 102 * @param endOfInput {@code true} if this invocation finishes the message 103 * @return the result 104 * @throws ProtocolException if the input violates the protocol 105 */ 106 @SuppressWarnings("unchecked") 107 public Decoder.Result<R> decode( 108 ByteBuffer in, Buffer out, boolean endOfInput) 109 throws ProtocolException { 110 return (Decoder.Result<R>)requestDecoder.decode(in, out, endOfInput); 111 } 112 113 /** 114 * Encodes a response generated by the server. This method must be used 115 * instead of the encoder's method if the encoder and decoder should adapt 116 * to a protocol switch automatically. 117 * 118 * @param messageHeader 119 * the message header 120 * @see Encoder#encode(MessageHeader) 121 */ 122 @SuppressWarnings("unchecked") 123 public void encode(R messageHeader) { 124 ((Encoder<R, Q>)responseEncoder).encode(messageHeader); 125 } 126 127 /** 128 * Invokes the encoder's encode method. This method must be used instead of 129 * encoder's method if the encoder and decoder should adapt to a protocol 130 * switch automatically. 131 * 132 * @param out 133 * the decoded data 134 * @return the result 135 * @see Encoder#encode(ByteBuffer) 136 */ 137 public Encoder.Result encode(ByteBuffer out) { 138 return encode(Codec.EMPTY_IN, out, true); 139 } 140 141 /** 142 * Invokes the encoder's encode method. This method must be used 143 * instead of decoding the encoder's method directly to allow derived 144 * server classes to adapt to any information contained in the message. 145 * 146 * @param in the data to encode 147 * @param out the encoded data 148 * @param endOfInput {@code true} if this invocation finishes the message 149 * @return the result 150 * @see Encoder#encode(Buffer, ByteBuffer, boolean) 151 */ 152 @SuppressWarnings("unchecked") 153 public Encoder.Result encode( 154 Buffer in, ByteBuffer out, boolean endOfInput) { 155 Encoder.Result result = responseEncoder.encode(in, out, endOfInput); 156 if (result instanceof ProtocolSwitchResult) { 157 ProtocolSwitchResult res = (ProtocolSwitchResult)result; 158 if (res.newProtocol() != null) { 159 setSwitchedTo(res.newProtocol()); 160 requestDecoder = res.newDecoder(); 161 responseEncoder = res.newEncoder(); 162 ((Decoder<MessageHeader, MessageHeader>)requestDecoder) 163 .setPeerEncoder((Encoder<MessageHeader, MessageHeader>) 164 responseEncoder); 165 ((Encoder<MessageHeader, MessageHeader>)responseEncoder) 166 .setPeerDecoder((Decoder<MessageHeader, MessageHeader>) 167 requestDecoder); 168 } 169 } 170 return result; 171 } 172 173 /** 174 * Returns the last fully decoded request if it exists. 175 * 176 * @return the request 177 */ 178 @SuppressWarnings("unchecked") 179 public Optional<Q> currentRequest() { 180 return (Optional<Q>)requestDecoder.header(); 181 } 182 183}