1/*
2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.nio.charset;
27
28import java.lang.ref.WeakReference;
29import java.nio.*;
30import java.util.Map;
31import java.util.HashMap;
32
33
34/**
35 * A description of the result state of a coder.
36 *
37 * <p> A charset coder, that is, either a decoder or an encoder, consumes bytes
38 * (or characters) from an input buffer, translates them, and writes the
39 * resulting characters (or bytes) to an output buffer.  A coding process
40 * terminates for one of four categories of reasons, which are described by
41 * instances of this class:
42 *
43 * <ul>
44 *
45 *   <li><p> <i>Underflow</i> is reported when there is no more input to be
46 *   processed, or there is insufficient input and additional input is
47 *   required.  This condition is represented by the unique result object
48 *   {@link #UNDERFLOW}, whose {@link #isUnderflow() isUnderflow} method
49 *   returns <tt>true</tt>.  </p></li>
50 *
51 *   <li><p> <i>Overflow</i> is reported when there is insufficient room
52 *   remaining in the output buffer.  This condition is represented by the
53 *   unique result object {@link #OVERFLOW}, whose {@link #isOverflow()
54 *   isOverflow} method returns <tt>true</tt>.  </p></li>
55 *
56 *   <li><p> A <i>malformed-input error</i> is reported when a sequence of
57 *   input units is not well-formed.  Such errors are described by instances of
58 *   this class whose {@link #isMalformed() isMalformed} method returns
59 *   <tt>true</tt> and whose {@link #length() length} method returns the length
60 *   of the malformed sequence.  There is one unique instance of this class for
61 *   all malformed-input errors of a given length.  </p></li>
62 *
63 *   <li><p> An <i>unmappable-character error</i> is reported when a sequence
64 *   of input units denotes a character that cannot be represented in the
65 *   output charset.  Such errors are described by instances of this class
66 *   whose {@link #isUnmappable() isUnmappable} method returns <tt>true</tt> and
67 *   whose {@link #length() length} method returns the length of the input
68 *   sequence denoting the unmappable character.  There is one unique instance
69 *   of this class for all unmappable-character errors of a given length.
70 *   </p></li>
71 *
72 * </ul>
73 *
74 * <p> For convenience, the {@link #isError() isError} method returns <tt>true</tt>
75 * for result objects that describe malformed-input and unmappable-character
76 * errors but <tt>false</tt> for those that describe underflow or overflow
77 * conditions.  </p>
78 *
79 *
80 * @author Mark Reinhold
81 * @author JSR-51 Expert Group
82 * @since 1.4
83 */
84
85public class CoderResult {
86
87    private static final int CR_UNDERFLOW  = 0;
88    private static final int CR_OVERFLOW   = 1;
89    private static final int CR_ERROR_MIN  = 2;
90    private static final int CR_MALFORMED  = 2;
91    private static final int CR_UNMAPPABLE = 3;
92
93    private static final String[] names
94        = { "UNDERFLOW", "OVERFLOW", "MALFORMED", "UNMAPPABLE" };
95
96    private final int type;
97    private final int length;
98
99    private CoderResult(int type, int length) {
100        this.type = type;
101        this.length = length;
102    }
103
104    /**
105     * Returns a string describing this coder result.
106     *
107     * @return  A descriptive string
108     */
109    public String toString() {
110        String nm = names[type];
111        return isError() ? nm + "[" + length + "]" : nm;
112    }
113
114    /**
115     * Tells whether or not this object describes an underflow condition.
116     *
117     * @return  <tt>true</tt> if, and only if, this object denotes underflow
118     */
119    public boolean isUnderflow() {
120        return (type == CR_UNDERFLOW);
121    }
122
123    /**
124     * Tells whether or not this object describes an overflow condition.
125     *
126     * @return  <tt>true</tt> if, and only if, this object denotes overflow
127     */
128    public boolean isOverflow() {
129        return (type == CR_OVERFLOW);
130    }
131
132    /**
133     * Tells whether or not this object describes an error condition.
134     *
135     * @return  <tt>true</tt> if, and only if, this object denotes either a
136     *          malformed-input error or an unmappable-character error
137     */
138    public boolean isError() {
139        return (type >= CR_ERROR_MIN);
140    }
141
142    /**
143     * Tells whether or not this object describes a malformed-input error.
144     *
145     * @return  <tt>true</tt> if, and only if, this object denotes a
146     *          malformed-input error
147     */
148    public boolean isMalformed() {
149        return (type == CR_MALFORMED);
150    }
151
152    /**
153     * Tells whether or not this object describes an unmappable-character
154     * error.
155     *
156     * @return  <tt>true</tt> if, and only if, this object denotes an
157     *          unmappable-character error
158     */
159    public boolean isUnmappable() {
160        return (type == CR_UNMAPPABLE);
161    }
162
163    /**
164     * Returns the length of the erroneous input described by this
165     * object&nbsp;&nbsp;<i>(optional operation)</i>.
166     *
167     * @return  The length of the erroneous input, a positive integer
168     *
169     * @throws  UnsupportedOperationException
170     *          If this object does not describe an error condition, that is,
171     *          if the {@link #isError() isError} does not return <tt>true</tt>
172     */
173    public int length() {
174        if (!isError())
175            throw new UnsupportedOperationException();
176        return length;
177    }
178
179    /**
180     * Result object indicating underflow, meaning that either the input buffer
181     * has been completely consumed or, if the input buffer is not yet empty,
182     * that additional input is required.
183     */
184    public static final CoderResult UNDERFLOW
185        = new CoderResult(CR_UNDERFLOW, 0);
186
187    /**
188     * Result object indicating overflow, meaning that there is insufficient
189     * room in the output buffer.
190     */
191    public static final CoderResult OVERFLOW
192        = new CoderResult(CR_OVERFLOW, 0);
193
194    private static abstract class Cache {
195
196        private Map<Integer,WeakReference<CoderResult>> cache = null;
197
198        protected abstract CoderResult create(int len);
199
200        private synchronized CoderResult get(int len) {
201            if (len <= 0)
202                throw new IllegalArgumentException("Non-positive length");
203            Integer k = new Integer(len);
204            WeakReference<CoderResult> w;
205            CoderResult e = null;
206            if (cache == null) {
207                cache = new HashMap<Integer,WeakReference<CoderResult>>();
208            } else if ((w = cache.get(k)) != null) {
209                e = w.get();
210            }
211            if (e == null) {
212                e = create(len);
213                cache.put(k, new WeakReference<CoderResult>(e));
214            }
215            return e;
216        }
217
218    }
219
220    private static Cache malformedCache
221        = new Cache() {
222                public CoderResult create(int len) {
223                    return new CoderResult(CR_MALFORMED, len);
224                }};
225
226    /**
227     * Static factory method that returns the unique object describing a
228     * malformed-input error of the given length.
229     *
230     * @param   length
231     *          The given length
232     *
233     * @return  The requested coder-result object
234     */
235    public static CoderResult malformedForLength(int length) {
236        return malformedCache.get(length);
237    }
238
239    private static Cache unmappableCache
240        = new Cache() {
241                public CoderResult create(int len) {
242                    return new CoderResult(CR_UNMAPPABLE, len);
243                }};
244
245    /**
246     * Static factory method that returns the unique result object describing
247     * an unmappable-character error of the given length.
248     *
249     * @param   length
250     *          The given length
251     *
252     * @return  The requested coder-result object
253     */
254    public static CoderResult unmappableForLength(int length) {
255        return unmappableCache.get(length);
256    }
257
258    /**
259     * Throws an exception appropriate to the result described by this object.
260     *
261     * @throws  BufferUnderflowException
262     *          If this object is {@link #UNDERFLOW}
263     *
264     * @throws  BufferOverflowException
265     *          If this object is {@link #OVERFLOW}
266     *
267     * @throws  MalformedInputException
268     *          If this object represents a malformed-input error; the
269     *          exception's length value will be that of this object
270     *
271     * @throws  UnmappableCharacterException
272     *          If this object represents an unmappable-character error; the
273     *          exceptions length value will be that of this object
274     */
275    public void throwException()
276        throws CharacterCodingException
277    {
278        switch (type) {
279        case CR_UNDERFLOW:   throw new BufferUnderflowException();
280        case CR_OVERFLOW:    throw new BufferOverflowException();
281        case CR_MALFORMED:   throw new MalformedInputException(length);
282        case CR_UNMAPPABLE:  throw new UnmappableCharacterException(length);
283        default:
284            assert false;
285        }
286    }
287
288}
289