View Javadoc
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  
26  package java.nio.charset;
27  
28  import java.lang.ref.WeakReference;
29  import java.nio.*;
30  import java.util.Map;
31  import 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  
85  public 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 }