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
025/**
026 * The general interface of a decoder.
027 * 
028 * @param <T> the type of message decoded by this decoder
029 * @param <R> the type of message that may be generated as response
030 * (see {@link Decoder.Result#response()})
031 */
032public interface Decoder<T extends MessageHeader,
033        R extends MessageHeader> extends Codec {
034
035        /**
036         * Sets the peer encoder. Some decoders need to know the state of 
037         * the encoder or the last encoded message.
038         *
039         * @param encoder the encoder
040         * @return the decoder
041         */
042        Decoder<T, R> setPeerEncoder(Encoder<R, T> encoder);
043        
044        /**
045         * Returns the type of the messages decoded by this decoder.
046         * 
047         * @return the value
048         */
049        Class<T> decoding();
050        
051        /**
052         * Decodes the next chunk of data. This method will never leave
053         * remaining data in the `in` buffer unless a header has been
054         * decoded completely and/or the `out` buffer is full. In either case, 
055         * decoding will therefore continue when the method is invoked again
056         * with the same `in` buffer and another (or emptied) `out` buffer.
057         * It is never necessary (though possible) to add data to an existing 
058         * `in` buffer.
059         * 
060         * @param in
061         *            holds the data to be decoded
062         * @param out
063         *            gets the body data (if any) written to it
064         * @param endOfInput
065         *            {@code true} if there is no input left beyond the data
066         *            currently in the {@code in} buffer (indicates end of body or
067         *            no body at all)
068         * @return the result
069         * @throws ProtocolException
070         *             if the message violates the HTTP
071         */
072        public Result<R> decode(ByteBuffer in, Buffer out, boolean endOfInput)
073                throws ProtocolException;
074        
075        /**
076         * Returns the last message (header) received. 
077         * If a header is completed during a 
078         * {@link #decode(ByteBuffer, Buffer, boolean)} invocation,
079         * the result's {@link Result#isHeaderCompleted()} is `true`
080         * and the header can be retrieved using this method.
081         * It remains available until `decode` is invoked for a new message
082         * (i.e. is invoked again after returning a result with
083         * {@link Codec.Result#isUnderflow()} being `false`.
084         * 
085         * @return the result
086         */
087        public Optional<T> header();
088        
089        /**
090         * The result from decoding. In addition to the common codec result, this
091         * includes the information wheteher a complete message header has been
092         * received and it can include a response that is to be sent back to the
093         * sender in order to fulfill the requirements of the protocol. As the
094         * decoder can (obviously) not sent back this response by itself, it is
095         * included in the result.
096         *
097         * The class is declared abstract to promote the usage of the factory
098         * method.
099         *
100         * @param <R>
101         *            the type of the optionally generated response message
102         */
103        public abstract static class Result<R extends MessageHeader> 
104                extends Codec.Result {
105
106                private boolean headerCompleted;
107                private Optional<R> response;
108                private boolean responseOnly;
109
110                /**
111                 * Creates a new result.
112                 * @param overflow {@code true} if the data didn't fit in the out buffer
113                 * @param underflow {@code true} if more data is expected
114                 * @param closeConnection
115                 *       {@code true} if the connection should be closed
116                 * @param headerCompleted {@code true} if the header has completely
117                 * been decoded
118                 * @param response a response to send due to an error
119                 * @param responseOnly if the result includes a response 
120                 * this flag indicates that no further processing besides 
121                 * sending the response is required
122                 */
123                protected Result(boolean overflow, boolean underflow, 
124                                boolean closeConnection, boolean headerCompleted, 
125                                R response, boolean responseOnly) {
126                        super(overflow, underflow, closeConnection);
127                        this.headerCompleted =  headerCompleted;
128                        this.response = Optional.ofNullable(response);
129                        this.responseOnly = responseOnly;
130                }
131
132                /**
133                 * Returns {@code true} if the message header has been decoded 
134                 * completely during the decoder invocation that returned this 
135                 * result and is now available. Note that not only the header may
136                 * heve been decoded, but that the output buffer may also
137                 * already contain decoded data.
138                 * 
139                 * @return the result
140                 */
141                public boolean isHeaderCompleted() {
142                        return headerCompleted;
143                }
144
145                /**
146                 * Returns the response if a response exists. A response in
147                 * the decoder result indicates that some information
148                 * must be signaled back to the sender.
149                 * 
150                 * @return the response
151                 */
152                public Optional<R> response() {
153                        return response;
154                }
155
156                /**
157                 * If the result includes a response (see {@link #response()})
158                 * and this method returns {@code true} then no
159                 * further processing of the received data is required. After sending
160                 * the response data, the decode method should be invoked 
161                 * again with the same parameters. 
162                 * 
163                 * @return the result
164                 */
165                public boolean isResponseOnly() {
166                        return responseOnly;
167                }
168
169                /* (non-Javadoc)
170                 * @see java.lang.Object#hashCode()
171                 */
172                @Override
173                public int hashCode() {
174                        final int prime = 31;
175                        int result = super.hashCode();
176                        result = prime * result + (headerCompleted ? 1231 : 1237);
177                        result = prime * result
178                                + ((response == null) ? 0 : response.hashCode());
179                        result = prime * result + (responseOnly ? 1231 : 1237);
180                        return result;
181                }
182
183                /* (non-Javadoc)
184                 * @see java.lang.Object#equals(java.lang.Object)
185                 */
186                @Override
187                public boolean equals(Object obj) {
188                        if (this == obj) {
189                                return true;
190                        }
191                        if (!super.equals(obj)) {
192                                return false;
193                        }
194                        if (!(obj instanceof Result)) {
195                                return false;
196                        }
197                        @SuppressWarnings("rawtypes")
198                        Result other = (Result) obj;
199                        if (headerCompleted != other.headerCompleted) {
200                                return false;
201                        }
202                        if (response == null) {
203                                if (other.response != null) {
204                                        return false;
205                                }
206                        } else if (!response.equals(other.response)) {
207                                return false;
208                        }
209                        if (responseOnly != other.responseOnly) {
210                                return false;
211                        }
212                        return true;
213                }
214
215                /* (non-Javadoc)
216                 * @see java.lang.Object#toString()
217                 */
218                @Override
219                public String toString() {
220                        StringBuilder builder = new StringBuilder();
221                        builder.append("Decoder.Result [overflow=");
222                        builder.append(isOverflow());
223                        builder.append(", underflow=");
224                        builder.append(isUnderflow());
225                        builder.append(", closeConnection=");
226                        builder.append(closeConnection());
227                        builder.append(", headerCompleted=");
228                        builder.append(headerCompleted);
229                        builder.append(", ");
230                        if (response != null) {
231                                builder.append("response=");
232                                builder.append(response);
233                                builder.append(", ");
234                        }
235                        builder.append("responseOnly=");
236                        builder.append(responseOnly);
237                        builder.append("]");
238                        return builder.toString();
239                }
240
241
242                /**
243                 * The Factory for (extended) results.
244                 */
245                protected abstract static class Factory<R extends MessageHeader> 
246                        extends Codec.Result.Factory {
247                }
248        }
249        
250}