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.ByteBuffer;
022
023/**
024 * The base interface for all coders and decoders.
025 */
026public interface Codec {
027
028        /**
029         * An empty input buffer that can be used for codec invocations
030         * when the (expected) body data is not yet available.
031         */
032        public static final ByteBuffer EMPTY_IN = ByteBuffer.allocate(0);
033
034        /**
035         * The common properties of the result types returned by the various codecs.
036         * Derived classes add their respective additional values.
037         * 
038         * The class is declared abstract to promote the usage of the factory
039         * method.
040         */
041        public abstract static class Result {
042
043                private boolean overflow;
044                private boolean underflow;
045                private boolean closeConnection;
046
047                /**
048                 * Creates a new result with the given values.
049                 * 
050                 * @param overflow
051                 *            {@code true} if the data didn't fit in the out buffer
052                 * @param underflow
053                 *            {@code true} if more data is expected
054                 * @param closeConnection
055                 *            {@code true} if the connection should be closed
056                 */
057                protected Result(boolean overflow, boolean underflow,
058                                boolean closeConnection) {
059                        super();
060                        this.overflow = overflow;
061                        this.underflow = underflow;
062                        this.closeConnection = closeConnection;
063                }
064
065                /**
066                 * Indicates that the data didn't fit in the out buffer. The encoding
067                 * method that has returned this result should be re-invoked with the
068                 * same parameters except for a new (or cleared) output buffer.
069                 * 
070                 * @return {@code true} if overflow occurred
071                 * @see #isUnderflow()
072                 */
073                public boolean isOverflow() {
074                        return overflow;
075                }
076
077                /**
078                 * Indicates that more data is needed to complete the encoding or
079                 * decoding of the entity. 
080                 * <P>
081                 * {@code Codec}s may report an underflow 
082                 * condition even if there is still data available in the input 
083                 * buffer in order to report some special condition in an extended 
084                 * result type. In this case, the encode or decode method should 
085                 * be reinvoked with the same parameters after handling the special 
086                 * condition that has been reported.
087                 * <P>
088                 * If underflow is reported and the input buffer is empty, the
089                 * encode or decode method should be reinvoked with the same parameters
090                 * except for an input buffer with additional information.
091                 * <P>
092                 * A result with both overflow and underflow set to false indicates
093                 * the completion of the encoding or decoding process of the entity.
094                 * In this case, the input buffer may still contain data that belongs
095                 * to the next entity that is to be encoded or decoded. 
096                 * 
097                 * @return {@code true} if underflow occurred
098                 */
099                public boolean isUnderflow() {
100                        return underflow;
101                }
102
103                /**
104                 * Indicates that the connection to the receiver of the response must be
105                 * closed after sending any remaining data in the out buffer.
106                 * 
107                 * @return the value
108                 */
109                public boolean closeConnection() {
110                        return closeConnection;
111                }
112
113                /* (non-Javadoc)
114                 * @see java.lang.Object#hashCode()
115                 */
116                @Override
117                public int hashCode() {
118                        final int prime = 31;
119                        int result = 1;
120                        result = prime * result + (closeConnection ? 1231 : 1237);
121                        result = prime * result + (overflow ? 1231 : 1237);
122                        result = prime * result + (underflow ? 1231 : 1237);
123                        return result;
124                }
125
126                /* (non-Javadoc)
127                 * @see java.lang.Object#equals(java.lang.Object)
128                 */
129                @Override
130                public boolean equals(Object obj) {
131                        if (this == obj) {
132                                return true;
133                        }
134                        if (obj == null) {
135                                return false;
136                        }
137                        if (!(obj instanceof Result)) {
138                                return false;
139                        }
140                        Result other = (Result) obj;
141                        if (closeConnection != other.closeConnection) {
142                                return false;
143                        }
144                        if (overflow != other.overflow) {
145                                return false;
146                        }
147                        if (underflow != other.underflow) {
148                                return false;
149                        }
150                        return true;
151                }
152
153                /* (non-Javadoc)
154                 * @see java.lang.Object#toString()
155                 */
156                @Override
157                public String toString() {
158                        StringBuilder builder = new StringBuilder();
159                        builder.append("Codec.Result [overflow=");
160                        builder.append(overflow);
161                        builder.append(", underflow=");
162                        builder.append(underflow);
163                        builder.append(", closeConnection=");
164                        builder.append(closeConnection);
165                        builder.append("]");
166                        return builder.toString();
167                }
168
169                /**
170                 * A base class for a factory that creates results. Factories
171                 * are only used internally by the codec implementation
172                 * and therefore defined as protected inner classes
173                 * so that they don't appear as part of the public API.
174                 * 
175                 * Factories are refined whenever the {@link Result} type
176                 * is refined. Factories define methods only if they are 
177                 * actually needed by the codec in which they are defined.
178                 */
179                protected static class Factory {
180                }
181        }
182
183        /**
184         * Results that indicate a protocol switch must implement this interface.
185         */
186        public interface ProtocolSwitchResult {
187                
188                /**
189                 * The name of the protocol to be used for the next request
190                 * if a protocol switch occured.
191                 * 
192                 * @return the name or {@code null} if no protocol switch occured
193                 */
194                public String newProtocol();
195                
196                /**
197                 * The encoder to be used for the next message
198                 * if a protocol switch occured.
199                 * 
200                 * @return the encoder or {@code null} if no protocol switch occurred
201                 */
202                public Encoder<?, ?> newEncoder();
203                
204                /**
205                 * The decoder to be used for the next message
206                 * if a protocol switch occured.
207                 * 
208                 * @return the decoder or {@code null} if no protocol switch occurred
209                 */
210                public Decoder<?, ?> newDecoder();
211        }
212}