1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/io/BufferedInputStream.java Thu Oct 03 15:43:10 2013 +0200
1.3 @@ -0,0 +1,478 @@
1.4 +/*
1.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package java.io;
1.30 +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
1.31 +
1.32 +/**
1.33 + * A <code>BufferedInputStream</code> adds
1.34 + * functionality to another input stream-namely,
1.35 + * the ability to buffer the input and to
1.36 + * support the <code>mark</code> and <code>reset</code>
1.37 + * methods. When the <code>BufferedInputStream</code>
1.38 + * is created, an internal buffer array is
1.39 + * created. As bytes from the stream are read
1.40 + * or skipped, the internal buffer is refilled
1.41 + * as necessary from the contained input stream,
1.42 + * many bytes at a time. The <code>mark</code>
1.43 + * operation remembers a point in the input
1.44 + * stream and the <code>reset</code> operation
1.45 + * causes all the bytes read since the most
1.46 + * recent <code>mark</code> operation to be
1.47 + * reread before new bytes are taken from
1.48 + * the contained input stream.
1.49 + *
1.50 + * @author Arthur van Hoff
1.51 + * @since JDK1.0
1.52 + */
1.53 +public
1.54 +class BufferedInputStream extends FilterInputStream {
1.55 +
1.56 + private static int defaultBufferSize = 8192;
1.57 +
1.58 + /**
1.59 + * The internal buffer array where the data is stored. When necessary,
1.60 + * it may be replaced by another array of
1.61 + * a different size.
1.62 + */
1.63 + protected volatile byte buf[];
1.64 +
1.65 + /**
1.66 + * Atomic updater to provide compareAndSet for buf. This is
1.67 + * necessary because closes can be asynchronous. We use nullness
1.68 + * of buf[] as primary indicator that this stream is closed. (The
1.69 + * "in" field is also nulled out on close.)
1.70 + */
1.71 + private static final
1.72 + AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
1.73 + AtomicReferenceFieldUpdater.newUpdater
1.74 + (BufferedInputStream.class, byte[].class, "buf");
1.75 +
1.76 + /**
1.77 + * The index one greater than the index of the last valid byte in
1.78 + * the buffer.
1.79 + * This value is always
1.80 + * in the range <code>0</code> through <code>buf.length</code>;
1.81 + * elements <code>buf[0]</code> through <code>buf[count-1]
1.82 + * </code>contain buffered input data obtained
1.83 + * from the underlying input stream.
1.84 + */
1.85 + protected int count;
1.86 +
1.87 + /**
1.88 + * The current position in the buffer. This is the index of the next
1.89 + * character to be read from the <code>buf</code> array.
1.90 + * <p>
1.91 + * This value is always in the range <code>0</code>
1.92 + * through <code>count</code>. If it is less
1.93 + * than <code>count</code>, then <code>buf[pos]</code>
1.94 + * is the next byte to be supplied as input;
1.95 + * if it is equal to <code>count</code>, then
1.96 + * the next <code>read</code> or <code>skip</code>
1.97 + * operation will require more bytes to be
1.98 + * read from the contained input stream.
1.99 + *
1.100 + * @see java.io.BufferedInputStream#buf
1.101 + */
1.102 + protected int pos;
1.103 +
1.104 + /**
1.105 + * The value of the <code>pos</code> field at the time the last
1.106 + * <code>mark</code> method was called.
1.107 + * <p>
1.108 + * This value is always
1.109 + * in the range <code>-1</code> through <code>pos</code>.
1.110 + * If there is no marked position in the input
1.111 + * stream, this field is <code>-1</code>. If
1.112 + * there is a marked position in the input
1.113 + * stream, then <code>buf[markpos]</code>
1.114 + * is the first byte to be supplied as input
1.115 + * after a <code>reset</code> operation. If
1.116 + * <code>markpos</code> is not <code>-1</code>,
1.117 + * then all bytes from positions <code>buf[markpos]</code>
1.118 + * through <code>buf[pos-1]</code> must remain
1.119 + * in the buffer array (though they may be
1.120 + * moved to another place in the buffer array,
1.121 + * with suitable adjustments to the values
1.122 + * of <code>count</code>, <code>pos</code>,
1.123 + * and <code>markpos</code>); they may not
1.124 + * be discarded unless and until the difference
1.125 + * between <code>pos</code> and <code>markpos</code>
1.126 + * exceeds <code>marklimit</code>.
1.127 + *
1.128 + * @see java.io.BufferedInputStream#mark(int)
1.129 + * @see java.io.BufferedInputStream#pos
1.130 + */
1.131 + protected int markpos = -1;
1.132 +
1.133 + /**
1.134 + * The maximum read ahead allowed after a call to the
1.135 + * <code>mark</code> method before subsequent calls to the
1.136 + * <code>reset</code> method fail.
1.137 + * Whenever the difference between <code>pos</code>
1.138 + * and <code>markpos</code> exceeds <code>marklimit</code>,
1.139 + * then the mark may be dropped by setting
1.140 + * <code>markpos</code> to <code>-1</code>.
1.141 + *
1.142 + * @see java.io.BufferedInputStream#mark(int)
1.143 + * @see java.io.BufferedInputStream#reset()
1.144 + */
1.145 + protected int marklimit;
1.146 +
1.147 + /**
1.148 + * Check to make sure that underlying input stream has not been
1.149 + * nulled out due to close; if not return it;
1.150 + */
1.151 + private InputStream getInIfOpen() throws IOException {
1.152 + InputStream input = in;
1.153 + if (input == null)
1.154 + throw new IOException("Stream closed");
1.155 + return input;
1.156 + }
1.157 +
1.158 + /**
1.159 + * Check to make sure that buffer has not been nulled out due to
1.160 + * close; if not return it;
1.161 + */
1.162 + private byte[] getBufIfOpen() throws IOException {
1.163 + byte[] buffer = buf;
1.164 + if (buffer == null)
1.165 + throw new IOException("Stream closed");
1.166 + return buffer;
1.167 + }
1.168 +
1.169 + /**
1.170 + * Creates a <code>BufferedInputStream</code>
1.171 + * and saves its argument, the input stream
1.172 + * <code>in</code>, for later use. An internal
1.173 + * buffer array is created and stored in <code>buf</code>.
1.174 + *
1.175 + * @param in the underlying input stream.
1.176 + */
1.177 + public BufferedInputStream(InputStream in) {
1.178 + this(in, defaultBufferSize);
1.179 + }
1.180 +
1.181 + /**
1.182 + * Creates a <code>BufferedInputStream</code>
1.183 + * with the specified buffer size,
1.184 + * and saves its argument, the input stream
1.185 + * <code>in</code>, for later use. An internal
1.186 + * buffer array of length <code>size</code>
1.187 + * is created and stored in <code>buf</code>.
1.188 + *
1.189 + * @param in the underlying input stream.
1.190 + * @param size the buffer size.
1.191 + * @exception IllegalArgumentException if size <= 0.
1.192 + */
1.193 + public BufferedInputStream(InputStream in, int size) {
1.194 + super(in);
1.195 + if (size <= 0) {
1.196 + throw new IllegalArgumentException("Buffer size <= 0");
1.197 + }
1.198 + buf = new byte[size];
1.199 + }
1.200 +
1.201 + /**
1.202 + * Fills the buffer with more data, taking into account
1.203 + * shuffling and other tricks for dealing with marks.
1.204 + * Assumes that it is being called by a synchronized method.
1.205 + * This method also assumes that all data has already been read in,
1.206 + * hence pos > count.
1.207 + */
1.208 + private void fill() throws IOException {
1.209 + byte[] buffer = getBufIfOpen();
1.210 + if (markpos < 0)
1.211 + pos = 0; /* no mark: throw away the buffer */
1.212 + else if (pos >= buffer.length) /* no room left in buffer */
1.213 + if (markpos > 0) { /* can throw away early part of the buffer */
1.214 + int sz = pos - markpos;
1.215 + System.arraycopy(buffer, markpos, buffer, 0, sz);
1.216 + pos = sz;
1.217 + markpos = 0;
1.218 + } else if (buffer.length >= marklimit) {
1.219 + markpos = -1; /* buffer got too big, invalidate mark */
1.220 + pos = 0; /* drop buffer contents */
1.221 + } else { /* grow buffer */
1.222 + int nsz = pos * 2;
1.223 + if (nsz > marklimit)
1.224 + nsz = marklimit;
1.225 + byte nbuf[] = new byte[nsz];
1.226 + System.arraycopy(buffer, 0, nbuf, 0, pos);
1.227 + if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
1.228 + // Can't replace buf if there was an async close.
1.229 + // Note: This would need to be changed if fill()
1.230 + // is ever made accessible to multiple threads.
1.231 + // But for now, the only way CAS can fail is via close.
1.232 + // assert buf == null;
1.233 + throw new IOException("Stream closed");
1.234 + }
1.235 + buffer = nbuf;
1.236 + }
1.237 + count = pos;
1.238 + int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
1.239 + if (n > 0)
1.240 + count = n + pos;
1.241 + }
1.242 +
1.243 + /**
1.244 + * See
1.245 + * the general contract of the <code>read</code>
1.246 + * method of <code>InputStream</code>.
1.247 + *
1.248 + * @return the next byte of data, or <code>-1</code> if the end of the
1.249 + * stream is reached.
1.250 + * @exception IOException if this input stream has been closed by
1.251 + * invoking its {@link #close()} method,
1.252 + * or an I/O error occurs.
1.253 + * @see java.io.FilterInputStream#in
1.254 + */
1.255 + public synchronized int read() throws IOException {
1.256 + if (pos >= count) {
1.257 + fill();
1.258 + if (pos >= count)
1.259 + return -1;
1.260 + }
1.261 + return getBufIfOpen()[pos++] & 0xff;
1.262 + }
1.263 +
1.264 + /**
1.265 + * Read characters into a portion of an array, reading from the underlying
1.266 + * stream at most once if necessary.
1.267 + */
1.268 + private int read1(byte[] b, int off, int len) throws IOException {
1.269 + int avail = count - pos;
1.270 + if (avail <= 0) {
1.271 + /* If the requested length is at least as large as the buffer, and
1.272 + if there is no mark/reset activity, do not bother to copy the
1.273 + bytes into the local buffer. In this way buffered streams will
1.274 + cascade harmlessly. */
1.275 + if (len >= getBufIfOpen().length && markpos < 0) {
1.276 + return getInIfOpen().read(b, off, len);
1.277 + }
1.278 + fill();
1.279 + avail = count - pos;
1.280 + if (avail <= 0) return -1;
1.281 + }
1.282 + int cnt = (avail < len) ? avail : len;
1.283 + System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
1.284 + pos += cnt;
1.285 + return cnt;
1.286 + }
1.287 +
1.288 + /**
1.289 + * Reads bytes from this byte-input stream into the specified byte array,
1.290 + * starting at the given offset.
1.291 + *
1.292 + * <p> This method implements the general contract of the corresponding
1.293 + * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
1.294 + * the <code>{@link InputStream}</code> class. As an additional
1.295 + * convenience, it attempts to read as many bytes as possible by repeatedly
1.296 + * invoking the <code>read</code> method of the underlying stream. This
1.297 + * iterated <code>read</code> continues until one of the following
1.298 + * conditions becomes true: <ul>
1.299 + *
1.300 + * <li> The specified number of bytes have been read,
1.301 + *
1.302 + * <li> The <code>read</code> method of the underlying stream returns
1.303 + * <code>-1</code>, indicating end-of-file, or
1.304 + *
1.305 + * <li> The <code>available</code> method of the underlying stream
1.306 + * returns zero, indicating that further input requests would block.
1.307 + *
1.308 + * </ul> If the first <code>read</code> on the underlying stream returns
1.309 + * <code>-1</code> to indicate end-of-file then this method returns
1.310 + * <code>-1</code>. Otherwise this method returns the number of bytes
1.311 + * actually read.
1.312 + *
1.313 + * <p> Subclasses of this class are encouraged, but not required, to
1.314 + * attempt to read as many bytes as possible in the same fashion.
1.315 + *
1.316 + * @param b destination buffer.
1.317 + * @param off offset at which to start storing bytes.
1.318 + * @param len maximum number of bytes to read.
1.319 + * @return the number of bytes read, or <code>-1</code> if the end of
1.320 + * the stream has been reached.
1.321 + * @exception IOException if this input stream has been closed by
1.322 + * invoking its {@link #close()} method,
1.323 + * or an I/O error occurs.
1.324 + */
1.325 + public synchronized int read(byte b[], int off, int len)
1.326 + throws IOException
1.327 + {
1.328 + getBufIfOpen(); // Check for closed stream
1.329 + if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
1.330 + throw new IndexOutOfBoundsException();
1.331 + } else if (len == 0) {
1.332 + return 0;
1.333 + }
1.334 +
1.335 + int n = 0;
1.336 + for (;;) {
1.337 + int nread = read1(b, off + n, len - n);
1.338 + if (nread <= 0)
1.339 + return (n == 0) ? nread : n;
1.340 + n += nread;
1.341 + if (n >= len)
1.342 + return n;
1.343 + // if not closed but no bytes available, return
1.344 + InputStream input = in;
1.345 + if (input != null && input.available() <= 0)
1.346 + return n;
1.347 + }
1.348 + }
1.349 +
1.350 + /**
1.351 + * See the general contract of the <code>skip</code>
1.352 + * method of <code>InputStream</code>.
1.353 + *
1.354 + * @exception IOException if the stream does not support seek,
1.355 + * or if this input stream has been closed by
1.356 + * invoking its {@link #close()} method, or an
1.357 + * I/O error occurs.
1.358 + */
1.359 + public synchronized long skip(long n) throws IOException {
1.360 + getBufIfOpen(); // Check for closed stream
1.361 + if (n <= 0) {
1.362 + return 0;
1.363 + }
1.364 + long avail = count - pos;
1.365 +
1.366 + if (avail <= 0) {
1.367 + // If no mark position set then don't keep in buffer
1.368 + if (markpos <0)
1.369 + return getInIfOpen().skip(n);
1.370 +
1.371 + // Fill in buffer to save bytes for reset
1.372 + fill();
1.373 + avail = count - pos;
1.374 + if (avail <= 0)
1.375 + return 0;
1.376 + }
1.377 +
1.378 + long skipped = (avail < n) ? avail : n;
1.379 + pos += skipped;
1.380 + return skipped;
1.381 + }
1.382 +
1.383 + /**
1.384 + * Returns an estimate of the number of bytes that can be read (or
1.385 + * skipped over) from this input stream without blocking by the next
1.386 + * invocation of a method for this input stream. The next invocation might be
1.387 + * the same thread or another thread. A single read or skip of this
1.388 + * many bytes will not block, but may read or skip fewer bytes.
1.389 + * <p>
1.390 + * This method returns the sum of the number of bytes remaining to be read in
1.391 + * the buffer (<code>count - pos</code>) and the result of calling the
1.392 + * {@link java.io.FilterInputStream#in in}.available().
1.393 + *
1.394 + * @return an estimate of the number of bytes that can be read (or skipped
1.395 + * over) from this input stream without blocking.
1.396 + * @exception IOException if this input stream has been closed by
1.397 + * invoking its {@link #close()} method,
1.398 + * or an I/O error occurs.
1.399 + */
1.400 + public synchronized int available() throws IOException {
1.401 + int n = count - pos;
1.402 + int avail = getInIfOpen().available();
1.403 + return n > (Integer.MAX_VALUE - avail)
1.404 + ? Integer.MAX_VALUE
1.405 + : n + avail;
1.406 + }
1.407 +
1.408 + /**
1.409 + * See the general contract of the <code>mark</code>
1.410 + * method of <code>InputStream</code>.
1.411 + *
1.412 + * @param readlimit the maximum limit of bytes that can be read before
1.413 + * the mark position becomes invalid.
1.414 + * @see java.io.BufferedInputStream#reset()
1.415 + */
1.416 + public synchronized void mark(int readlimit) {
1.417 + marklimit = readlimit;
1.418 + markpos = pos;
1.419 + }
1.420 +
1.421 + /**
1.422 + * See the general contract of the <code>reset</code>
1.423 + * method of <code>InputStream</code>.
1.424 + * <p>
1.425 + * If <code>markpos</code> is <code>-1</code>
1.426 + * (no mark has been set or the mark has been
1.427 + * invalidated), an <code>IOException</code>
1.428 + * is thrown. Otherwise, <code>pos</code> is
1.429 + * set equal to <code>markpos</code>.
1.430 + *
1.431 + * @exception IOException if this stream has not been marked or,
1.432 + * if the mark has been invalidated, or the stream
1.433 + * has been closed by invoking its {@link #close()}
1.434 + * method, or an I/O error occurs.
1.435 + * @see java.io.BufferedInputStream#mark(int)
1.436 + */
1.437 + public synchronized void reset() throws IOException {
1.438 + getBufIfOpen(); // Cause exception if closed
1.439 + if (markpos < 0)
1.440 + throw new IOException("Resetting to invalid mark");
1.441 + pos = markpos;
1.442 + }
1.443 +
1.444 + /**
1.445 + * Tests if this input stream supports the <code>mark</code>
1.446 + * and <code>reset</code> methods. The <code>markSupported</code>
1.447 + * method of <code>BufferedInputStream</code> returns
1.448 + * <code>true</code>.
1.449 + *
1.450 + * @return a <code>boolean</code> indicating if this stream type supports
1.451 + * the <code>mark</code> and <code>reset</code> methods.
1.452 + * @see java.io.InputStream#mark(int)
1.453 + * @see java.io.InputStream#reset()
1.454 + */
1.455 + public boolean markSupported() {
1.456 + return true;
1.457 + }
1.458 +
1.459 + /**
1.460 + * Closes this input stream and releases any system resources
1.461 + * associated with the stream.
1.462 + * Once the stream has been closed, further read(), available(), reset(),
1.463 + * or skip() invocations will throw an IOException.
1.464 + * Closing a previously closed stream has no effect.
1.465 + *
1.466 + * @exception IOException if an I/O error occurs.
1.467 + */
1.468 + public void close() throws IOException {
1.469 + byte[] buffer;
1.470 + while ( (buffer = buf) != null) {
1.471 + if (bufUpdater.compareAndSet(this, buffer, null)) {
1.472 + InputStream input = in;
1.473 + in = null;
1.474 + if (input != null)
1.475 + input.close();
1.476 + return;
1.477 + }
1.478 + // Else retry in case a new buf was CASed in fill()
1.479 + }
1.480 + }
1.481 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/rt/emul/compact/src/main/java/java/io/FileDescriptor.java Thu Oct 03 15:43:10 2013 +0200
2.3 @@ -0,0 +1,176 @@
2.4 +/*
2.5 + * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
2.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
2.7 + *
2.8 + *
2.9 + *
2.10 + *
2.11 + *
2.12 + *
2.13 + *
2.14 + *
2.15 + *
2.16 + *
2.17 + *
2.18 + *
2.19 + *
2.20 + *
2.21 + *
2.22 + *
2.23 + *
2.24 + *
2.25 + *
2.26 + *
2.27 + */
2.28 +
2.29 +package java.io;
2.30 +
2.31 +import java.util.concurrent.atomic.AtomicInteger;
2.32 +
2.33 +/**
2.34 + * Instances of the file descriptor class serve as an opaque handle
2.35 + * to the underlying machine-specific structure representing an open
2.36 + * file, an open socket, or another source or sink of bytes. The
2.37 + * main practical use for a file descriptor is to create a
2.38 + * <code>FileInputStream</code> or <code>FileOutputStream</code> to
2.39 + * contain it.
2.40 + * <p>
2.41 + * Applications should not create their own file descriptors.
2.42 + *
2.43 + * @author Pavani Diwanji
2.44 + * @see java.io.FileInputStream
2.45 + * @see java.io.FileOutputStream
2.46 + * @since JDK1.0
2.47 + */
2.48 +public final class FileDescriptor {
2.49 +
2.50 + private int fd;
2.51 +
2.52 + /**
2.53 + * A counter for tracking the FIS/FOS/RAF instances that
2.54 + * use this FileDescriptor. The FIS/FOS.finalize() will not release
2.55 + * the FileDescriptor if it is still under user by a stream.
2.56 + */
2.57 + private AtomicInteger useCount;
2.58 +
2.59 + /**
2.60 + * Constructs an (invalid) FileDescriptor
2.61 + * object.
2.62 + */
2.63 + public /**/ FileDescriptor() {
2.64 + fd = -1;
2.65 + useCount = new AtomicInteger();
2.66 + }
2.67 +
2.68 + private /* */ FileDescriptor(int fd) {
2.69 + this.fd = fd;
2.70 + useCount = new AtomicInteger();
2.71 + }
2.72 +
2.73 + /**
2.74 + * A handle to the standard input stream. Usually, this file
2.75 + * descriptor is not used directly, but rather via the input stream
2.76 + * known as <code>System.in</code>.
2.77 + *
2.78 + * @see java.lang.System#in
2.79 + */
2.80 + public static final FileDescriptor in = new FileDescriptor(0);
2.81 +
2.82 + /**
2.83 + * A handle to the standard output stream. Usually, this file
2.84 + * descriptor is not used directly, but rather via the output stream
2.85 + * known as <code>System.out</code>.
2.86 + * @see java.lang.System#out
2.87 + */
2.88 + public static final FileDescriptor out = new FileDescriptor(1);
2.89 +
2.90 + /**
2.91 + * A handle to the standard error stream. Usually, this file
2.92 + * descriptor is not used directly, but rather via the output stream
2.93 + * known as <code>System.err</code>.
2.94 + *
2.95 + * @see java.lang.System#err
2.96 + */
2.97 + public static final FileDescriptor err = new FileDescriptor(2);
2.98 +
2.99 + /**
2.100 + * Tests if this file descriptor object is valid.
2.101 + *
2.102 + * @return <code>true</code> if the file descriptor object represents a
2.103 + * valid, open file, socket, or other active I/O connection;
2.104 + * <code>false</code> otherwise.
2.105 + */
2.106 + public boolean valid() {
2.107 + return fd != -1;
2.108 + }
2.109 +
2.110 + /**
2.111 + * Force all system buffers to synchronize with the underlying
2.112 + * device. This method returns after all modified data and
2.113 + * attributes of this FileDescriptor have been written to the
2.114 + * relevant device(s). In particular, if this FileDescriptor
2.115 + * refers to a physical storage medium, such as a file in a file
2.116 + * system, sync will not return until all in-memory modified copies
2.117 + * of buffers associated with this FileDescriptor have been
2.118 + * written to the physical medium.
2.119 + *
2.120 + * sync is meant to be used by code that requires physical
2.121 + * storage (such as a file) to be in a known state For
2.122 + * example, a class that provided a simple transaction facility
2.123 + * might use sync to ensure that all changes to a file caused
2.124 + * by a given transaction were recorded on a storage medium.
2.125 + *
2.126 + * sync only affects buffers downstream of this FileDescriptor. If
2.127 + * any in-memory buffering is being done by the application (for
2.128 + * example, by a BufferedOutputStream object), those buffers must
2.129 + * be flushed into the FileDescriptor (for example, by invoking
2.130 + * OutputStream.flush) before that data will be affected by sync.
2.131 + *
2.132 + * @exception SyncFailedException
2.133 + * Thrown when the buffers cannot be flushed,
2.134 + * or because the system cannot guarantee that all the
2.135 + * buffers have been synchronized with physical media.
2.136 + * @since JDK1.1
2.137 + */
2.138 + public native void sync() throws SyncFailedException;
2.139 +
2.140 + /* This routine initializes JNI field offsets for the class */
2.141 + private static native void initIDs();
2.142 +
2.143 + static {
2.144 + initIDs();
2.145 + }
2.146 +
2.147 + // Set up JavaIOFileDescriptorAccess in SharedSecrets
2.148 + static {
2.149 + sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess(
2.150 + new sun.misc.JavaIOFileDescriptorAccess() {
2.151 + public void set(FileDescriptor obj, int fd) {
2.152 + obj.fd = fd;
2.153 + }
2.154 +
2.155 + public int get(FileDescriptor obj) {
2.156 + return obj.fd;
2.157 + }
2.158 +
2.159 + public void setHandle(FileDescriptor obj, long handle) {
2.160 + throw new UnsupportedOperationException();
2.161 + }
2.162 +
2.163 + public long getHandle(FileDescriptor obj) {
2.164 + throw new UnsupportedOperationException();
2.165 + }
2.166 + }
2.167 + );
2.168 + }
2.169 +
2.170 + // package private methods used by FIS, FOS and RAF
2.171 +
2.172 + int incrementAndGetUseCount() {
2.173 + return useCount.incrementAndGet();
2.174 + }
2.175 +
2.176 + int decrementAndGetUseCount() {
2.177 + return useCount.decrementAndGet();
2.178 + }
2.179 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/rt/emul/compact/src/main/java/java/io/FileInputStream.java Thu Oct 03 15:43:10 2013 +0200
3.3 @@ -0,0 +1,408 @@
3.4 +/*
3.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3.7 + *
3.8 + * This code is free software; you can redistribute it and/or modify it
3.9 + * under the terms of the GNU General Public License version 2 only, as
3.10 + * published by the Free Software Foundation. Oracle designates this
3.11 + * particular file as subject to the "Classpath" exception as provided
3.12 + * by Oracle in the LICENSE file that accompanied this code.
3.13 + *
3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3.17 + * version 2 for more details (a copy is included in the LICENSE file that
3.18 + * accompanied this code).
3.19 + *
3.20 + * You should have received a copy of the GNU General Public License version
3.21 + * 2 along with this work; if not, write to the Free Software Foundation,
3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3.23 + *
3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
3.25 + * or visit www.oracle.com if you need additional information or have any
3.26 + * questions.
3.27 + */
3.28 +
3.29 +package java.io;
3.30 +
3.31 +import java.nio.channels.FileChannel;
3.32 +import sun.nio.ch.FileChannelImpl;
3.33 +
3.34 +
3.35 +/**
3.36 + * A <code>FileInputStream</code> obtains input bytes
3.37 + * from a file in a file system. What files
3.38 + * are available depends on the host environment.
3.39 + *
3.40 + * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
3.41 + * such as image data. For reading streams of characters, consider using
3.42 + * <code>FileReader</code>.
3.43 + *
3.44 + * @author Arthur van Hoff
3.45 + * @see java.io.File
3.46 + * @see java.io.FileDescriptor
3.47 + * @see java.io.FileOutputStream
3.48 + * @see java.nio.file.Files#newInputStream
3.49 + * @since JDK1.0
3.50 + */
3.51 +public
3.52 +class FileInputStream extends InputStream
3.53 +{
3.54 + /* File Descriptor - handle to the open file */
3.55 + private final FileDescriptor fd;
3.56 +
3.57 + private FileChannel channel = null;
3.58 +
3.59 + private final Object closeLock = new Object();
3.60 + private volatile boolean closed = false;
3.61 +
3.62 + private static final ThreadLocal<Boolean> runningFinalize =
3.63 + new ThreadLocal<>();
3.64 +
3.65 + private static boolean isRunningFinalize() {
3.66 + Boolean val;
3.67 + if ((val = runningFinalize.get()) != null)
3.68 + return val.booleanValue();
3.69 + return false;
3.70 + }
3.71 +
3.72 + /**
3.73 + * Creates a <code>FileInputStream</code> by
3.74 + * opening a connection to an actual file,
3.75 + * the file named by the path name <code>name</code>
3.76 + * in the file system. A new <code>FileDescriptor</code>
3.77 + * object is created to represent this file
3.78 + * connection.
3.79 + * <p>
3.80 + * First, if there is a security
3.81 + * manager, its <code>checkRead</code> method
3.82 + * is called with the <code>name</code> argument
3.83 + * as its argument.
3.84 + * <p>
3.85 + * If the named file does not exist, is a directory rather than a regular
3.86 + * file, or for some other reason cannot be opened for reading then a
3.87 + * <code>FileNotFoundException</code> is thrown.
3.88 + *
3.89 + * @param name the system-dependent file name.
3.90 + * @exception FileNotFoundException if the file does not exist,
3.91 + * is a directory rather than a regular file,
3.92 + * or for some other reason cannot be opened for
3.93 + * reading.
3.94 + * @exception SecurityException if a security manager exists and its
3.95 + * <code>checkRead</code> method denies read access
3.96 + * to the file.
3.97 + * @see java.lang.SecurityManager#checkRead(java.lang.String)
3.98 + */
3.99 + public FileInputStream(String name) throws FileNotFoundException {
3.100 + this(name != null ? new File(name) : null);
3.101 + }
3.102 +
3.103 + /**
3.104 + * Creates a <code>FileInputStream</code> by
3.105 + * opening a connection to an actual file,
3.106 + * the file named by the <code>File</code>
3.107 + * object <code>file</code> in the file system.
3.108 + * A new <code>FileDescriptor</code> object
3.109 + * is created to represent this file connection.
3.110 + * <p>
3.111 + * First, if there is a security manager,
3.112 + * its <code>checkRead</code> method is called
3.113 + * with the path represented by the <code>file</code>
3.114 + * argument as its argument.
3.115 + * <p>
3.116 + * If the named file does not exist, is a directory rather than a regular
3.117 + * file, or for some other reason cannot be opened for reading then a
3.118 + * <code>FileNotFoundException</code> is thrown.
3.119 + *
3.120 + * @param file the file to be opened for reading.
3.121 + * @exception FileNotFoundException if the file does not exist,
3.122 + * is a directory rather than a regular file,
3.123 + * or for some other reason cannot be opened for
3.124 + * reading.
3.125 + * @exception SecurityException if a security manager exists and its
3.126 + * <code>checkRead</code> method denies read access to the file.
3.127 + * @see java.io.File#getPath()
3.128 + * @see java.lang.SecurityManager#checkRead(java.lang.String)
3.129 + */
3.130 + public FileInputStream(File file) throws FileNotFoundException {
3.131 + String name = (file != null ? file.getPath() : null);
3.132 + SecurityManager security = System.getSecurityManager();
3.133 + if (security != null) {
3.134 + security.checkRead(name);
3.135 + }
3.136 + if (name == null) {
3.137 + throw new NullPointerException();
3.138 + }
3.139 + fd = new FileDescriptor();
3.140 + fd.incrementAndGetUseCount();
3.141 + open(name);
3.142 + }
3.143 +
3.144 + /**
3.145 + * Creates a <code>FileInputStream</code> by using the file descriptor
3.146 + * <code>fdObj</code>, which represents an existing connection to an
3.147 + * actual file in the file system.
3.148 + * <p>
3.149 + * If there is a security manager, its <code>checkRead</code> method is
3.150 + * called with the file descriptor <code>fdObj</code> as its argument to
3.151 + * see if it's ok to read the file descriptor. If read access is denied
3.152 + * to the file descriptor a <code>SecurityException</code> is thrown.
3.153 + * <p>
3.154 + * If <code>fdObj</code> is null then a <code>NullPointerException</code>
3.155 + * is thrown.
3.156 + * <p>
3.157 + * This constructor does not throw an exception if <code>fdObj</code>
3.158 + * is {@link java.io.FileDescriptor#valid() invalid}.
3.159 + * However, if the methods are invoked on the resulting stream to attempt
3.160 + * I/O on the stream, an <code>IOException</code> is thrown.
3.161 + *
3.162 + * @param fdObj the file descriptor to be opened for reading.
3.163 + * @throws SecurityException if a security manager exists and its
3.164 + * <code>checkRead</code> method denies read access to the
3.165 + * file descriptor.
3.166 + * @see SecurityManager#checkRead(java.io.FileDescriptor)
3.167 + */
3.168 + public FileInputStream(FileDescriptor fdObj) {
3.169 + SecurityManager security = System.getSecurityManager();
3.170 + if (fdObj == null) {
3.171 + throw new NullPointerException();
3.172 + }
3.173 + if (security != null) {
3.174 + security.checkRead(fdObj);
3.175 + }
3.176 + fd = fdObj;
3.177 +
3.178 + /*
3.179 + * FileDescriptor is being shared by streams.
3.180 + * Ensure that it's GC'ed only when all the streams/channels are done
3.181 + * using it.
3.182 + */
3.183 + fd.incrementAndGetUseCount();
3.184 + }
3.185 +
3.186 + /**
3.187 + * Opens the specified file for reading.
3.188 + * @param name the name of the file
3.189 + */
3.190 + private native void open(String name) throws FileNotFoundException;
3.191 +
3.192 + /**
3.193 + * Reads a byte of data from this input stream. This method blocks
3.194 + * if no input is yet available.
3.195 + *
3.196 + * @return the next byte of data, or <code>-1</code> if the end of the
3.197 + * file is reached.
3.198 + * @exception IOException if an I/O error occurs.
3.199 + */
3.200 + public native int read() throws IOException;
3.201 +
3.202 + /**
3.203 + * Reads a subarray as a sequence of bytes.
3.204 + * @param b the data to be written
3.205 + * @param off the start offset in the data
3.206 + * @param len the number of bytes that are written
3.207 + * @exception IOException If an I/O error has occurred.
3.208 + */
3.209 + private native int readBytes(byte b[], int off, int len) throws IOException;
3.210 +
3.211 + /**
3.212 + * Reads up to <code>b.length</code> bytes of data from this input
3.213 + * stream into an array of bytes. This method blocks until some input
3.214 + * is available.
3.215 + *
3.216 + * @param b the buffer into which the data is read.
3.217 + * @return the total number of bytes read into the buffer, or
3.218 + * <code>-1</code> if there is no more data because the end of
3.219 + * the file has been reached.
3.220 + * @exception IOException if an I/O error occurs.
3.221 + */
3.222 + public int read(byte b[]) throws IOException {
3.223 + return readBytes(b, 0, b.length);
3.224 + }
3.225 +
3.226 + /**
3.227 + * Reads up to <code>len</code> bytes of data from this input stream
3.228 + * into an array of bytes. If <code>len</code> is not zero, the method
3.229 + * blocks until some input is available; otherwise, no
3.230 + * bytes are read and <code>0</code> is returned.
3.231 + *
3.232 + * @param b the buffer into which the data is read.
3.233 + * @param off the start offset in the destination array <code>b</code>
3.234 + * @param len the maximum number of bytes read.
3.235 + * @return the total number of bytes read into the buffer, or
3.236 + * <code>-1</code> if there is no more data because the end of
3.237 + * the file has been reached.
3.238 + * @exception NullPointerException If <code>b</code> is <code>null</code>.
3.239 + * @exception IndexOutOfBoundsException If <code>off</code> is negative,
3.240 + * <code>len</code> is negative, or <code>len</code> is greater than
3.241 + * <code>b.length - off</code>
3.242 + * @exception IOException if an I/O error occurs.
3.243 + */
3.244 + public int read(byte b[], int off, int len) throws IOException {
3.245 + return readBytes(b, off, len);
3.246 + }
3.247 +
3.248 + /**
3.249 + * Skips over and discards <code>n</code> bytes of data from the
3.250 + * input stream.
3.251 + *
3.252 + * <p>The <code>skip</code> method may, for a variety of
3.253 + * reasons, end up skipping over some smaller number of bytes,
3.254 + * possibly <code>0</code>. If <code>n</code> is negative, an
3.255 + * <code>IOException</code> is thrown, even though the <code>skip</code>
3.256 + * method of the {@link InputStream} superclass does nothing in this case.
3.257 + * The actual number of bytes skipped is returned.
3.258 + *
3.259 + * <p>This method may skip more bytes than are remaining in the backing
3.260 + * file. This produces no exception and the number of bytes skipped
3.261 + * may include some number of bytes that were beyond the EOF of the
3.262 + * backing file. Attempting to read from the stream after skipping past
3.263 + * the end will result in -1 indicating the end of the file.
3.264 + *
3.265 + * @param n the number of bytes to be skipped.
3.266 + * @return the actual number of bytes skipped.
3.267 + * @exception IOException if n is negative, if the stream does not
3.268 + * support seek, or if an I/O error occurs.
3.269 + */
3.270 + public native long skip(long n) throws IOException;
3.271 +
3.272 + /**
3.273 + * Returns an estimate of the number of remaining bytes that can be read (or
3.274 + * skipped over) from this input stream without blocking by the next
3.275 + * invocation of a method for this input stream. The next invocation might be
3.276 + * the same thread or another thread. A single read or skip of this
3.277 + * many bytes will not block, but may read or skip fewer bytes.
3.278 + *
3.279 + * <p> In some cases, a non-blocking read (or skip) may appear to be
3.280 + * blocked when it is merely slow, for example when reading large
3.281 + * files over slow networks.
3.282 + *
3.283 + * @return an estimate of the number of remaining bytes that can be read
3.284 + * (or skipped over) from this input stream without blocking.
3.285 + * @exception IOException if this file input stream has been closed by calling
3.286 + * {@code close} or an I/O error occurs.
3.287 + */
3.288 + public native int available() throws IOException;
3.289 +
3.290 + /**
3.291 + * Closes this file input stream and releases any system resources
3.292 + * associated with the stream.
3.293 + *
3.294 + * <p> If this stream has an associated channel then the channel is closed
3.295 + * as well.
3.296 + *
3.297 + * @exception IOException if an I/O error occurs.
3.298 + *
3.299 + * @revised 1.4
3.300 + * @spec JSR-51
3.301 + */
3.302 + public void close() throws IOException {
3.303 + synchronized (closeLock) {
3.304 + if (closed) {
3.305 + return;
3.306 + }
3.307 + closed = true;
3.308 + }
3.309 + if (channel != null) {
3.310 + /*
3.311 + * Decrement the FD use count associated with the channel
3.312 + * The use count is incremented whenever a new channel
3.313 + * is obtained from this stream.
3.314 + */
3.315 + fd.decrementAndGetUseCount();
3.316 + channel.close();
3.317 + }
3.318 +
3.319 + /*
3.320 + * Decrement the FD use count associated with this stream
3.321 + */
3.322 + int useCount = fd.decrementAndGetUseCount();
3.323 +
3.324 + /*
3.325 + * If FileDescriptor is still in use by another stream, the finalizer
3.326 + * will not close it.
3.327 + */
3.328 + if ((useCount <= 0) || !isRunningFinalize()) {
3.329 + close0();
3.330 + }
3.331 + }
3.332 +
3.333 + /**
3.334 + * Returns the <code>FileDescriptor</code>
3.335 + * object that represents the connection to
3.336 + * the actual file in the file system being
3.337 + * used by this <code>FileInputStream</code>.
3.338 + *
3.339 + * @return the file descriptor object associated with this stream.
3.340 + * @exception IOException if an I/O error occurs.
3.341 + * @see java.io.FileDescriptor
3.342 + */
3.343 + public final FileDescriptor getFD() throws IOException {
3.344 + if (fd != null) return fd;
3.345 + throw new IOException();
3.346 + }
3.347 +
3.348 + /**
3.349 + * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
3.350 + * object associated with this file input stream.
3.351 + *
3.352 + * <p> The initial {@link java.nio.channels.FileChannel#position()
3.353 + * </code>position<code>} of the returned channel will be equal to the
3.354 + * number of bytes read from the file so far. Reading bytes from this
3.355 + * stream will increment the channel's position. Changing the channel's
3.356 + * position, either explicitly or by reading, will change this stream's
3.357 + * file position.
3.358 + *
3.359 + * @return the file channel associated with this file input stream
3.360 + *
3.361 + * @since 1.4
3.362 + * @spec JSR-51
3.363 + */
3.364 + public FileChannel getChannel() {
3.365 + synchronized (this) {
3.366 + if (channel == null) {
3.367 + channel = FileChannelImpl.open(fd, true, false, this);
3.368 +
3.369 + /*
3.370 + * Increment fd's use count. Invoking the channel's close()
3.371 + * method will result in decrementing the use count set for
3.372 + * the channel.
3.373 + */
3.374 + fd.incrementAndGetUseCount();
3.375 + }
3.376 + return channel;
3.377 + }
3.378 + }
3.379 +
3.380 + private static native void initIDs();
3.381 +
3.382 + private native void close0() throws IOException;
3.383 +
3.384 + static {
3.385 + initIDs();
3.386 + }
3.387 +
3.388 + /**
3.389 + * Ensures that the <code>close</code> method of this file input stream is
3.390 + * called when there are no more references to it.
3.391 + *
3.392 + * @exception IOException if an I/O error occurs.
3.393 + * @see java.io.FileInputStream#close()
3.394 + */
3.395 + protected void finalize() throws IOException {
3.396 + if ((fd != null) && (fd != FileDescriptor.in)) {
3.397 +
3.398 + /*
3.399 + * Finalizer should not release the FileDescriptor if another
3.400 + * stream is still using it. If the user directly invokes
3.401 + * close() then the FileDescriptor is also released.
3.402 + */
3.403 + runningFinalize.set(Boolean.TRUE);
3.404 + try {
3.405 + close();
3.406 + } finally {
3.407 + runningFinalize.set(Boolean.FALSE);
3.408 + }
3.409 + }
3.410 + }
3.411 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/rt/emul/compact/src/main/java/java/io/FileOutputStream.java Thu Oct 03 15:43:10 2013 +0200
4.3 @@ -0,0 +1,451 @@
4.4 +/*
4.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4.7 + *
4.8 + * This code is free software; you can redistribute it and/or modify it
4.9 + * under the terms of the GNU General Public License version 2 only, as
4.10 + * published by the Free Software Foundation. Oracle designates this
4.11 + * particular file as subject to the "Classpath" exception as provided
4.12 + * by Oracle in the LICENSE file that accompanied this code.
4.13 + *
4.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
4.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4.17 + * version 2 for more details (a copy is included in the LICENSE file that
4.18 + * accompanied this code).
4.19 + *
4.20 + * You should have received a copy of the GNU General Public License version
4.21 + * 2 along with this work; if not, write to the Free Software Foundation,
4.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4.23 + *
4.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4.25 + * or visit www.oracle.com if you need additional information or have any
4.26 + * questions.
4.27 + */
4.28 +
4.29 +package java.io;
4.30 +
4.31 +import java.nio.channels.FileChannel;
4.32 +import sun.nio.ch.FileChannelImpl;
4.33 +
4.34 +
4.35 +/**
4.36 + * A file output stream is an output stream for writing data to a
4.37 + * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
4.38 + * a file is available or may be created depends upon the underlying
4.39 + * platform. Some platforms, in particular, allow a file to be opened
4.40 + * for writing by only one <tt>FileOutputStream</tt> (or other
4.41 + * file-writing object) at a time. In such situations the constructors in
4.42 + * this class will fail if the file involved is already open.
4.43 + *
4.44 + * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
4.45 + * such as image data. For writing streams of characters, consider using
4.46 + * <code>FileWriter</code>.
4.47 + *
4.48 + * @author Arthur van Hoff
4.49 + * @see java.io.File
4.50 + * @see java.io.FileDescriptor
4.51 + * @see java.io.FileInputStream
4.52 + * @see java.nio.file.Files#newOutputStream
4.53 + * @since JDK1.0
4.54 + */
4.55 +public
4.56 +class FileOutputStream extends OutputStream
4.57 +{
4.58 + /**
4.59 + * The system dependent file descriptor.
4.60 + */
4.61 + private final FileDescriptor fd;
4.62 +
4.63 + /**
4.64 + * True if the file is opened for append.
4.65 + */
4.66 + private final boolean append;
4.67 +
4.68 + /**
4.69 + * The associated channel, initalized lazily.
4.70 + */
4.71 + private FileChannel channel;
4.72 +
4.73 + private final Object closeLock = new Object();
4.74 + private volatile boolean closed = false;
4.75 + private static final ThreadLocal<Boolean> runningFinalize =
4.76 + new ThreadLocal<>();
4.77 +
4.78 + private static boolean isRunningFinalize() {
4.79 + Boolean val;
4.80 + if ((val = runningFinalize.get()) != null)
4.81 + return val.booleanValue();
4.82 + return false;
4.83 + }
4.84 +
4.85 + /**
4.86 + * Creates a file output stream to write to the file with the
4.87 + * specified name. A new <code>FileDescriptor</code> object is
4.88 + * created to represent this file connection.
4.89 + * <p>
4.90 + * First, if there is a security manager, its <code>checkWrite</code>
4.91 + * method is called with <code>name</code> as its argument.
4.92 + * <p>
4.93 + * If the file exists but is a directory rather than a regular file, does
4.94 + * not exist but cannot be created, or cannot be opened for any other
4.95 + * reason then a <code>FileNotFoundException</code> is thrown.
4.96 + *
4.97 + * @param name the system-dependent filename
4.98 + * @exception FileNotFoundException if the file exists but is a directory
4.99 + * rather than a regular file, does not exist but cannot
4.100 + * be created, or cannot be opened for any other reason
4.101 + * @exception SecurityException if a security manager exists and its
4.102 + * <code>checkWrite</code> method denies write access
4.103 + * to the file.
4.104 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
4.105 + */
4.106 + public FileOutputStream(String name) throws FileNotFoundException {
4.107 + this(name != null ? new File(name) : null, false);
4.108 + }
4.109 +
4.110 + /**
4.111 + * Creates a file output stream to write to the file with the specified
4.112 + * name. If the second argument is <code>true</code>, then
4.113 + * bytes will be written to the end of the file rather than the beginning.
4.114 + * A new <code>FileDescriptor</code> object is created to represent this
4.115 + * file connection.
4.116 + * <p>
4.117 + * First, if there is a security manager, its <code>checkWrite</code>
4.118 + * method is called with <code>name</code> as its argument.
4.119 + * <p>
4.120 + * If the file exists but is a directory rather than a regular file, does
4.121 + * not exist but cannot be created, or cannot be opened for any other
4.122 + * reason then a <code>FileNotFoundException</code> is thrown.
4.123 + *
4.124 + * @param name the system-dependent file name
4.125 + * @param append if <code>true</code>, then bytes will be written
4.126 + * to the end of the file rather than the beginning
4.127 + * @exception FileNotFoundException if the file exists but is a directory
4.128 + * rather than a regular file, does not exist but cannot
4.129 + * be created, or cannot be opened for any other reason.
4.130 + * @exception SecurityException if a security manager exists and its
4.131 + * <code>checkWrite</code> method denies write access
4.132 + * to the file.
4.133 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
4.134 + * @since JDK1.1
4.135 + */
4.136 + public FileOutputStream(String name, boolean append)
4.137 + throws FileNotFoundException
4.138 + {
4.139 + this(name != null ? new File(name) : null, append);
4.140 + }
4.141 +
4.142 + /**
4.143 + * Creates a file output stream to write to the file represented by
4.144 + * the specified <code>File</code> object. A new
4.145 + * <code>FileDescriptor</code> object is created to represent this
4.146 + * file connection.
4.147 + * <p>
4.148 + * First, if there is a security manager, its <code>checkWrite</code>
4.149 + * method is called with the path represented by the <code>file</code>
4.150 + * argument as its argument.
4.151 + * <p>
4.152 + * If the file exists but is a directory rather than a regular file, does
4.153 + * not exist but cannot be created, or cannot be opened for any other
4.154 + * reason then a <code>FileNotFoundException</code> is thrown.
4.155 + *
4.156 + * @param file the file to be opened for writing.
4.157 + * @exception FileNotFoundException if the file exists but is a directory
4.158 + * rather than a regular file, does not exist but cannot
4.159 + * be created, or cannot be opened for any other reason
4.160 + * @exception SecurityException if a security manager exists and its
4.161 + * <code>checkWrite</code> method denies write access
4.162 + * to the file.
4.163 + * @see java.io.File#getPath()
4.164 + * @see java.lang.SecurityException
4.165 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
4.166 + */
4.167 + public FileOutputStream(File file) throws FileNotFoundException {
4.168 + this(file, false);
4.169 + }
4.170 +
4.171 + /**
4.172 + * Creates a file output stream to write to the file represented by
4.173 + * the specified <code>File</code> object. If the second argument is
4.174 + * <code>true</code>, then bytes will be written to the end of the file
4.175 + * rather than the beginning. A new <code>FileDescriptor</code> object is
4.176 + * created to represent this file connection.
4.177 + * <p>
4.178 + * First, if there is a security manager, its <code>checkWrite</code>
4.179 + * method is called with the path represented by the <code>file</code>
4.180 + * argument as its argument.
4.181 + * <p>
4.182 + * If the file exists but is a directory rather than a regular file, does
4.183 + * not exist but cannot be created, or cannot be opened for any other
4.184 + * reason then a <code>FileNotFoundException</code> is thrown.
4.185 + *
4.186 + * @param file the file to be opened for writing.
4.187 + * @param append if <code>true</code>, then bytes will be written
4.188 + * to the end of the file rather than the beginning
4.189 + * @exception FileNotFoundException if the file exists but is a directory
4.190 + * rather than a regular file, does not exist but cannot
4.191 + * be created, or cannot be opened for any other reason
4.192 + * @exception SecurityException if a security manager exists and its
4.193 + * <code>checkWrite</code> method denies write access
4.194 + * to the file.
4.195 + * @see java.io.File#getPath()
4.196 + * @see java.lang.SecurityException
4.197 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
4.198 + * @since 1.4
4.199 + */
4.200 + public FileOutputStream(File file, boolean append)
4.201 + throws FileNotFoundException
4.202 + {
4.203 + String name = (file != null ? file.getPath() : null);
4.204 + SecurityManager security = System.getSecurityManager();
4.205 + if (security != null) {
4.206 + security.checkWrite(name);
4.207 + }
4.208 + if (name == null) {
4.209 + throw new NullPointerException();
4.210 + }
4.211 + this.fd = new FileDescriptor();
4.212 + this.append = append;
4.213 +
4.214 + fd.incrementAndGetUseCount();
4.215 + open(name, append);
4.216 + }
4.217 +
4.218 + /**
4.219 + * Creates a file output stream to write to the specified file
4.220 + * descriptor, which represents an existing connection to an actual
4.221 + * file in the file system.
4.222 + * <p>
4.223 + * First, if there is a security manager, its <code>checkWrite</code>
4.224 + * method is called with the file descriptor <code>fdObj</code>
4.225 + * argument as its argument.
4.226 + * <p>
4.227 + * If <code>fdObj</code> is null then a <code>NullPointerException</code>
4.228 + * is thrown.
4.229 + * <p>
4.230 + * This constructor does not throw an exception if <code>fdObj</code>
4.231 + * is {@link java.io.FileDescriptor#valid() invalid}.
4.232 + * However, if the methods are invoked on the resulting stream to attempt
4.233 + * I/O on the stream, an <code>IOException</code> is thrown.
4.234 + *
4.235 + * @param fdObj the file descriptor to be opened for writing
4.236 + * @exception SecurityException if a security manager exists and its
4.237 + * <code>checkWrite</code> method denies
4.238 + * write access to the file descriptor
4.239 + * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
4.240 + */
4.241 + public FileOutputStream(FileDescriptor fdObj) {
4.242 + SecurityManager security = System.getSecurityManager();
4.243 + if (fdObj == null) {
4.244 + throw new NullPointerException();
4.245 + }
4.246 + if (security != null) {
4.247 + security.checkWrite(fdObj);
4.248 + }
4.249 + this.fd = fdObj;
4.250 + this.append = false;
4.251 +
4.252 + /*
4.253 + * FileDescriptor is being shared by streams.
4.254 + * Ensure that it's GC'ed only when all the streams/channels are done
4.255 + * using it.
4.256 + */
4.257 + fd.incrementAndGetUseCount();
4.258 + }
4.259 +
4.260 + /**
4.261 + * Opens a file, with the specified name, for overwriting or appending.
4.262 + * @param name name of file to be opened
4.263 + * @param append whether the file is to be opened in append mode
4.264 + */
4.265 + private native void open(String name, boolean append)
4.266 + throws FileNotFoundException;
4.267 +
4.268 + /**
4.269 + * Writes the specified byte to this file output stream.
4.270 + *
4.271 + * @param b the byte to be written.
4.272 + * @param append {@code true} if the write operation first
4.273 + * advances the position to the end of file
4.274 + */
4.275 + private native void write(int b, boolean append) throws IOException;
4.276 +
4.277 + /**
4.278 + * Writes the specified byte to this file output stream. Implements
4.279 + * the <code>write</code> method of <code>OutputStream</code>.
4.280 + *
4.281 + * @param b the byte to be written.
4.282 + * @exception IOException if an I/O error occurs.
4.283 + */
4.284 + public void write(int b) throws IOException {
4.285 + write(b, append);
4.286 + }
4.287 +
4.288 + /**
4.289 + * Writes a sub array as a sequence of bytes.
4.290 + * @param b the data to be written
4.291 + * @param off the start offset in the data
4.292 + * @param len the number of bytes that are written
4.293 + * @param append {@code true} to first advance the position to the
4.294 + * end of file
4.295 + * @exception IOException If an I/O error has occurred.
4.296 + */
4.297 + private native void writeBytes(byte b[], int off, int len, boolean append)
4.298 + throws IOException;
4.299 +
4.300 + /**
4.301 + * Writes <code>b.length</code> bytes from the specified byte array
4.302 + * to this file output stream.
4.303 + *
4.304 + * @param b the data.
4.305 + * @exception IOException if an I/O error occurs.
4.306 + */
4.307 + public void write(byte b[]) throws IOException {
4.308 + writeBytes(b, 0, b.length, append);
4.309 + }
4.310 +
4.311 + /**
4.312 + * Writes <code>len</code> bytes from the specified byte array
4.313 + * starting at offset <code>off</code> to this file output stream.
4.314 + *
4.315 + * @param b the data.
4.316 + * @param off the start offset in the data.
4.317 + * @param len the number of bytes to write.
4.318 + * @exception IOException if an I/O error occurs.
4.319 + */
4.320 + public void write(byte b[], int off, int len) throws IOException {
4.321 + writeBytes(b, off, len, append);
4.322 + }
4.323 +
4.324 + /**
4.325 + * Closes this file output stream and releases any system resources
4.326 + * associated with this stream. This file output stream may no longer
4.327 + * be used for writing bytes.
4.328 + *
4.329 + * <p> If this stream has an associated channel then the channel is closed
4.330 + * as well.
4.331 + *
4.332 + * @exception IOException if an I/O error occurs.
4.333 + *
4.334 + * @revised 1.4
4.335 + * @spec JSR-51
4.336 + */
4.337 + public void close() throws IOException {
4.338 + synchronized (closeLock) {
4.339 + if (closed) {
4.340 + return;
4.341 + }
4.342 + closed = true;
4.343 + }
4.344 +
4.345 + if (channel != null) {
4.346 + /*
4.347 + * Decrement FD use count associated with the channel
4.348 + * The use count is incremented whenever a new channel
4.349 + * is obtained from this stream.
4.350 + */
4.351 + fd.decrementAndGetUseCount();
4.352 + channel.close();
4.353 + }
4.354 +
4.355 + /*
4.356 + * Decrement FD use count associated with this stream
4.357 + */
4.358 + int useCount = fd.decrementAndGetUseCount();
4.359 +
4.360 + /*
4.361 + * If FileDescriptor is still in use by another stream, the finalizer
4.362 + * will not close it.
4.363 + */
4.364 + if ((useCount <= 0) || !isRunningFinalize()) {
4.365 + close0();
4.366 + }
4.367 + }
4.368 +
4.369 + /**
4.370 + * Returns the file descriptor associated with this stream.
4.371 + *
4.372 + * @return the <code>FileDescriptor</code> object that represents
4.373 + * the connection to the file in the file system being used
4.374 + * by this <code>FileOutputStream</code> object.
4.375 + *
4.376 + * @exception IOException if an I/O error occurs.
4.377 + * @see java.io.FileDescriptor
4.378 + */
4.379 + public final FileDescriptor getFD() throws IOException {
4.380 + if (fd != null) return fd;
4.381 + throw new IOException();
4.382 + }
4.383 +
4.384 + /**
4.385 + * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
4.386 + * object associated with this file output stream. </p>
4.387 + *
4.388 + * <p> The initial {@link java.nio.channels.FileChannel#position()
4.389 + * </code>position<code>} of the returned channel will be equal to the
4.390 + * number of bytes written to the file so far unless this stream is in
4.391 + * append mode, in which case it will be equal to the size of the file.
4.392 + * Writing bytes to this stream will increment the channel's position
4.393 + * accordingly. Changing the channel's position, either explicitly or by
4.394 + * writing, will change this stream's file position.
4.395 + *
4.396 + * @return the file channel associated with this file output stream
4.397 + *
4.398 + * @since 1.4
4.399 + * @spec JSR-51
4.400 + */
4.401 + public FileChannel getChannel() {
4.402 + synchronized (this) {
4.403 + if (channel == null) {
4.404 + channel = FileChannelImpl.open(fd, false, true, append, this);
4.405 +
4.406 + /*
4.407 + * Increment fd's use count. Invoking the channel's close()
4.408 + * method will result in decrementing the use count set for
4.409 + * the channel.
4.410 + */
4.411 + fd.incrementAndGetUseCount();
4.412 + }
4.413 + return channel;
4.414 + }
4.415 + }
4.416 +
4.417 + /**
4.418 + * Cleans up the connection to the file, and ensures that the
4.419 + * <code>close</code> method of this file output stream is
4.420 + * called when there are no more references to this stream.
4.421 + *
4.422 + * @exception IOException if an I/O error occurs.
4.423 + * @see java.io.FileInputStream#close()
4.424 + */
4.425 + protected void finalize() throws IOException {
4.426 + if (fd != null) {
4.427 + if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
4.428 + flush();
4.429 + } else {
4.430 +
4.431 + /*
4.432 + * Finalizer should not release the FileDescriptor if another
4.433 + * stream is still using it. If the user directly invokes
4.434 + * close() then the FileDescriptor is also released.
4.435 + */
4.436 + runningFinalize.set(Boolean.TRUE);
4.437 + try {
4.438 + close();
4.439 + } finally {
4.440 + runningFinalize.set(Boolean.FALSE);
4.441 + }
4.442 + }
4.443 + }
4.444 + }
4.445 +
4.446 + private native void close0() throws IOException;
4.447 +
4.448 + private static native void initIDs();
4.449 +
4.450 + static {
4.451 + initIDs();
4.452 + }
4.453 +
4.454 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/rt/emul/compact/src/main/java/java/io/FileReader.java Thu Oct 03 15:43:10 2013 +0200
5.3 @@ -0,0 +1,85 @@
5.4 +/*
5.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5.7 + *
5.8 + * This code is free software; you can redistribute it and/or modify it
5.9 + * under the terms of the GNU General Public License version 2 only, as
5.10 + * published by the Free Software Foundation. Oracle designates this
5.11 + * particular file as subject to the "Classpath" exception as provided
5.12 + * by Oracle in the LICENSE file that accompanied this code.
5.13 + *
5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5.17 + * version 2 for more details (a copy is included in the LICENSE file that
5.18 + * accompanied this code).
5.19 + *
5.20 + * You should have received a copy of the GNU General Public License version
5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5.23 + *
5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5.25 + * or visit www.oracle.com if you need additional information or have any
5.26 + * questions.
5.27 + */
5.28 +
5.29 +package java.io;
5.30 +
5.31 +
5.32 +/**
5.33 + * Convenience class for reading character files. The constructors of this
5.34 + * class assume that the default character encoding and the default byte-buffer
5.35 + * size are appropriate. To specify these values yourself, construct an
5.36 + * InputStreamReader on a FileInputStream.
5.37 + *
5.38 + * <p><code>FileReader</code> is meant for reading streams of characters.
5.39 + * For reading streams of raw bytes, consider using a
5.40 + * <code>FileInputStream</code>.
5.41 + *
5.42 + * @see InputStreamReader
5.43 + * @see FileInputStream
5.44 + *
5.45 + * @author Mark Reinhold
5.46 + * @since JDK1.1
5.47 + */
5.48 +public class FileReader extends InputStreamReader {
5.49 +
5.50 + /**
5.51 + * Creates a new <tt>FileReader</tt>, given the name of the
5.52 + * file to read from.
5.53 + *
5.54 + * @param fileName the name of the file to read from
5.55 + * @exception FileNotFoundException if the named file does not exist,
5.56 + * is a directory rather than a regular file,
5.57 + * or for some other reason cannot be opened for
5.58 + * reading.
5.59 + */
5.60 + public FileReader(String fileName) throws FileNotFoundException {
5.61 + super(new FileInputStream(fileName));
5.62 + }
5.63 +
5.64 + /**
5.65 + * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
5.66 + * to read from.
5.67 + *
5.68 + * @param file the <tt>File</tt> to read from
5.69 + * @exception FileNotFoundException if the file does not exist,
5.70 + * is a directory rather than a regular file,
5.71 + * or for some other reason cannot be opened for
5.72 + * reading.
5.73 + */
5.74 + public FileReader(File file) throws FileNotFoundException {
5.75 + super(new FileInputStream(file));
5.76 + }
5.77 +
5.78 + /**
5.79 + * Creates a new <tt>FileReader</tt>, given the
5.80 + * <tt>FileDescriptor</tt> to read from.
5.81 + *
5.82 + * @param fd the FileDescriptor to read from
5.83 + */
5.84 + public FileReader(FileDescriptor fd) {
5.85 + super(new FileInputStream(fd));
5.86 + }
5.87 +
5.88 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/rt/emul/compact/src/main/java/java/io/FileWriter.java Thu Oct 03 15:43:10 2013 +0200
6.3 @@ -0,0 +1,119 @@
6.4 +/*
6.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6.7 + *
6.8 + * This code is free software; you can redistribute it and/or modify it
6.9 + * under the terms of the GNU General Public License version 2 only, as
6.10 + * published by the Free Software Foundation. Oracle designates this
6.11 + * particular file as subject to the "Classpath" exception as provided
6.12 + * by Oracle in the LICENSE file that accompanied this code.
6.13 + *
6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6.17 + * version 2 for more details (a copy is included in the LICENSE file that
6.18 + * accompanied this code).
6.19 + *
6.20 + * You should have received a copy of the GNU General Public License version
6.21 + * 2 along with this work; if not, write to the Free Software Foundation,
6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
6.23 + *
6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
6.25 + * or visit www.oracle.com if you need additional information or have any
6.26 + * questions.
6.27 + */
6.28 +
6.29 +package java.io;
6.30 +
6.31 +
6.32 +/**
6.33 + * Convenience class for writing character files. The constructors of this
6.34 + * class assume that the default character encoding and the default byte-buffer
6.35 + * size are acceptable. To specify these values yourself, construct an
6.36 + * OutputStreamWriter on a FileOutputStream.
6.37 + *
6.38 + * <p>Whether or not a file is available or may be created depends upon the
6.39 + * underlying platform. Some platforms, in particular, allow a file to be
6.40 + * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
6.41 + * object) at a time. In such situations the constructors in this class
6.42 + * will fail if the file involved is already open.
6.43 + *
6.44 + * <p><code>FileWriter</code> is meant for writing streams of characters.
6.45 + * For writing streams of raw bytes, consider using a
6.46 + * <code>FileOutputStream</code>.
6.47 + *
6.48 + * @see OutputStreamWriter
6.49 + * @see FileOutputStream
6.50 + *
6.51 + * @author Mark Reinhold
6.52 + * @since JDK1.1
6.53 + */
6.54 +
6.55 +public class FileWriter extends OutputStreamWriter {
6.56 +
6.57 + /**
6.58 + * Constructs a FileWriter object given a file name.
6.59 + *
6.60 + * @param fileName String The system-dependent filename.
6.61 + * @throws IOException if the named file exists but is a directory rather
6.62 + * than a regular file, does not exist but cannot be
6.63 + * created, or cannot be opened for any other reason
6.64 + */
6.65 + public FileWriter(String fileName) throws IOException {
6.66 + super(new FileOutputStream(fileName));
6.67 + }
6.68 +
6.69 + /**
6.70 + * Constructs a FileWriter object given a file name with a boolean
6.71 + * indicating whether or not to append the data written.
6.72 + *
6.73 + * @param fileName String The system-dependent filename.
6.74 + * @param append boolean if <code>true</code>, then data will be written
6.75 + * to the end of the file rather than the beginning.
6.76 + * @throws IOException if the named file exists but is a directory rather
6.77 + * than a regular file, does not exist but cannot be
6.78 + * created, or cannot be opened for any other reason
6.79 + */
6.80 + public FileWriter(String fileName, boolean append) throws IOException {
6.81 + super(new FileOutputStream(fileName, append));
6.82 + }
6.83 +
6.84 + /**
6.85 + * Constructs a FileWriter object given a File object.
6.86 + *
6.87 + * @param file a File object to write to.
6.88 + * @throws IOException if the file exists but is a directory rather than
6.89 + * a regular file, does not exist but cannot be created,
6.90 + * or cannot be opened for any other reason
6.91 + */
6.92 + public FileWriter(File file) throws IOException {
6.93 + super(new FileOutputStream(file));
6.94 + }
6.95 +
6.96 + /**
6.97 + * Constructs a FileWriter object given a File object. If the second
6.98 + * argument is <code>true</code>, then bytes will be written to the end
6.99 + * of the file rather than the beginning.
6.100 + *
6.101 + * @param file a File object to write to
6.102 + * @param append if <code>true</code>, then bytes will be written
6.103 + * to the end of the file rather than the beginning
6.104 + * @throws IOException if the file exists but is a directory rather than
6.105 + * a regular file, does not exist but cannot be created,
6.106 + * or cannot be opened for any other reason
6.107 + * @since 1.4
6.108 + */
6.109 + public FileWriter(File file, boolean append) throws IOException {
6.110 + super(new FileOutputStream(file, append));
6.111 + }
6.112 +
6.113 + /**
6.114 + * Constructs a FileWriter object associated with a file descriptor.
6.115 + *
6.116 + * @param fd FileDescriptor object to write to.
6.117 + */
6.118 + public FileWriter(FileDescriptor fd) {
6.119 + super(new FileOutputStream(fd));
6.120 + }
6.121 +
6.122 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberInputStream.java Thu Oct 03 15:43:10 2013 +0200
7.3 @@ -0,0 +1,292 @@
7.4 +/*
7.5 + * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7.7 + *
7.8 + * This code is free software; you can redistribute it and/or modify it
7.9 + * under the terms of the GNU General Public License version 2 only, as
7.10 + * published by the Free Software Foundation. Oracle designates this
7.11 + * particular file as subject to the "Classpath" exception as provided
7.12 + * by Oracle in the LICENSE file that accompanied this code.
7.13 + *
7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
7.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
7.17 + * version 2 for more details (a copy is included in the LICENSE file that
7.18 + * accompanied this code).
7.19 + *
7.20 + * You should have received a copy of the GNU General Public License version
7.21 + * 2 along with this work; if not, write to the Free Software Foundation,
7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
7.23 + *
7.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
7.25 + * or visit www.oracle.com if you need additional information or have any
7.26 + * questions.
7.27 + */
7.28 +
7.29 +package java.io;
7.30 +
7.31 +/**
7.32 + * This class is an input stream filter that provides the added
7.33 + * functionality of keeping track of the current line number.
7.34 + * <p>
7.35 + * A line is a sequence of bytes ending with a carriage return
7.36 + * character (<code>'\r'</code>), a newline character
7.37 + * (<code>'\n'</code>), or a carriage return character followed
7.38 + * immediately by a linefeed character. In all three cases, the line
7.39 + * terminating character(s) are returned as a single newline character.
7.40 + * <p>
7.41 + * The line number begins at <code>0</code>, and is incremented by
7.42 + * <code>1</code> when a <code>read</code> returns a newline character.
7.43 + *
7.44 + * @author Arthur van Hoff
7.45 + * @see java.io.LineNumberReader
7.46 + * @since JDK1.0
7.47 + * @deprecated This class incorrectly assumes that bytes adequately represent
7.48 + * characters. As of JDK 1.1, the preferred way to operate on
7.49 + * character streams is via the new character-stream classes, which
7.50 + * include a class for counting line numbers.
7.51 + */
7.52 +@Deprecated
7.53 +public
7.54 +class LineNumberInputStream extends FilterInputStream {
7.55 + int pushBack = -1;
7.56 + int lineNumber;
7.57 + int markLineNumber;
7.58 + int markPushBack = -1;
7.59 +
7.60 + /**
7.61 + * Constructs a newline number input stream that reads its input
7.62 + * from the specified input stream.
7.63 + *
7.64 + * @param in the underlying input stream.
7.65 + */
7.66 + public LineNumberInputStream(InputStream in) {
7.67 + super(in);
7.68 + }
7.69 +
7.70 + /**
7.71 + * Reads the next byte of data from this input stream. The value
7.72 + * byte is returned as an <code>int</code> in the range
7.73 + * <code>0</code> to <code>255</code>. If no byte is available
7.74 + * because the end of the stream has been reached, the value
7.75 + * <code>-1</code> is returned. This method blocks until input data
7.76 + * is available, the end of the stream is detected, or an exception
7.77 + * is thrown.
7.78 + * <p>
7.79 + * The <code>read</code> method of
7.80 + * <code>LineNumberInputStream</code> calls the <code>read</code>
7.81 + * method of the underlying input stream. It checks for carriage
7.82 + * returns and newline characters in the input, and modifies the
7.83 + * current line number as appropriate. A carriage-return character or
7.84 + * a carriage return followed by a newline character are both
7.85 + * converted into a single newline character.
7.86 + *
7.87 + * @return the next byte of data, or <code>-1</code> if the end of this
7.88 + * stream is reached.
7.89 + * @exception IOException if an I/O error occurs.
7.90 + * @see java.io.FilterInputStream#in
7.91 + * @see java.io.LineNumberInputStream#getLineNumber()
7.92 + */
7.93 + public int read() throws IOException {
7.94 + int c = pushBack;
7.95 +
7.96 + if (c != -1) {
7.97 + pushBack = -1;
7.98 + } else {
7.99 + c = in.read();
7.100 + }
7.101 +
7.102 + switch (c) {
7.103 + case '\r':
7.104 + pushBack = in.read();
7.105 + if (pushBack == '\n') {
7.106 + pushBack = -1;
7.107 + }
7.108 + case '\n':
7.109 + lineNumber++;
7.110 + return '\n';
7.111 + }
7.112 + return c;
7.113 + }
7.114 +
7.115 + /**
7.116 + * Reads up to <code>len</code> bytes of data from this input stream
7.117 + * into an array of bytes. This method blocks until some input is available.
7.118 + * <p>
7.119 + * The <code>read</code> method of
7.120 + * <code>LineNumberInputStream</code> repeatedly calls the
7.121 + * <code>read</code> method of zero arguments to fill in the byte array.
7.122 + *
7.123 + * @param b the buffer into which the data is read.
7.124 + * @param off the start offset of the data.
7.125 + * @param len the maximum number of bytes read.
7.126 + * @return the total number of bytes read into the buffer, or
7.127 + * <code>-1</code> if there is no more data because the end of
7.128 + * this stream has been reached.
7.129 + * @exception IOException if an I/O error occurs.
7.130 + * @see java.io.LineNumberInputStream#read()
7.131 + */
7.132 + public int read(byte b[], int off, int len) throws IOException {
7.133 + if (b == null) {
7.134 + throw new NullPointerException();
7.135 + } else if ((off < 0) || (off > b.length) || (len < 0) ||
7.136 + ((off + len) > b.length) || ((off + len) < 0)) {
7.137 + throw new IndexOutOfBoundsException();
7.138 + } else if (len == 0) {
7.139 + return 0;
7.140 + }
7.141 +
7.142 + int c = read();
7.143 + if (c == -1) {
7.144 + return -1;
7.145 + }
7.146 + b[off] = (byte)c;
7.147 +
7.148 + int i = 1;
7.149 + try {
7.150 + for (; i < len ; i++) {
7.151 + c = read();
7.152 + if (c == -1) {
7.153 + break;
7.154 + }
7.155 + if (b != null) {
7.156 + b[off + i] = (byte)c;
7.157 + }
7.158 + }
7.159 + } catch (IOException ee) {
7.160 + }
7.161 + return i;
7.162 + }
7.163 +
7.164 + /**
7.165 + * Skips over and discards <code>n</code> bytes of data from this
7.166 + * input stream. The <code>skip</code> method may, for a variety of
7.167 + * reasons, end up skipping over some smaller number of bytes,
7.168 + * possibly <code>0</code>. The actual number of bytes skipped is
7.169 + * returned. If <code>n</code> is negative, no bytes are skipped.
7.170 + * <p>
7.171 + * The <code>skip</code> method of <code>LineNumberInputStream</code> creates
7.172 + * a byte array and then repeatedly reads into it until
7.173 + * <code>n</code> bytes have been read or the end of the stream has
7.174 + * been reached.
7.175 + *
7.176 + * @param n the number of bytes to be skipped.
7.177 + * @return the actual number of bytes skipped.
7.178 + * @exception IOException if an I/O error occurs.
7.179 + * @see java.io.FilterInputStream#in
7.180 + */
7.181 + public long skip(long n) throws IOException {
7.182 + int chunk = 2048;
7.183 + long remaining = n;
7.184 + byte data[];
7.185 + int nr;
7.186 +
7.187 + if (n <= 0) {
7.188 + return 0;
7.189 + }
7.190 +
7.191 + data = new byte[chunk];
7.192 + while (remaining > 0) {
7.193 + nr = read(data, 0, (int) Math.min(chunk, remaining));
7.194 + if (nr < 0) {
7.195 + break;
7.196 + }
7.197 + remaining -= nr;
7.198 + }
7.199 +
7.200 + return n - remaining;
7.201 + }
7.202 +
7.203 + /**
7.204 + * Sets the line number to the specified argument.
7.205 + *
7.206 + * @param lineNumber the new line number.
7.207 + * @see #getLineNumber
7.208 + */
7.209 + public void setLineNumber(int lineNumber) {
7.210 + this.lineNumber = lineNumber;
7.211 + }
7.212 +
7.213 + /**
7.214 + * Returns the current line number.
7.215 + *
7.216 + * @return the current line number.
7.217 + * @see #setLineNumber
7.218 + */
7.219 + public int getLineNumber() {
7.220 + return lineNumber;
7.221 + }
7.222 +
7.223 +
7.224 + /**
7.225 + * Returns the number of bytes that can be read from this input
7.226 + * stream without blocking.
7.227 + * <p>
7.228 + * Note that if the underlying input stream is able to supply
7.229 + * <i>k</i> input characters without blocking, the
7.230 + * <code>LineNumberInputStream</code> can guarantee only to provide
7.231 + * <i>k</i>/2 characters without blocking, because the
7.232 + * <i>k</i> characters from the underlying input stream might
7.233 + * consist of <i>k</i>/2 pairs of <code>'\r'</code> and
7.234 + * <code>'\n'</code>, which are converted to just
7.235 + * <i>k</i>/2 <code>'\n'</code> characters.
7.236 + *
7.237 + * @return the number of bytes that can be read from this input stream
7.238 + * without blocking.
7.239 + * @exception IOException if an I/O error occurs.
7.240 + * @see java.io.FilterInputStream#in
7.241 + */
7.242 + public int available() throws IOException {
7.243 + return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1;
7.244 + }
7.245 +
7.246 + /**
7.247 + * Marks the current position in this input stream. A subsequent
7.248 + * call to the <code>reset</code> method repositions this stream at
7.249 + * the last marked position so that subsequent reads re-read the same bytes.
7.250 + * <p>
7.251 + * The <code>mark</code> method of
7.252 + * <code>LineNumberInputStream</code> remembers the current line
7.253 + * number in a private variable, and then calls the <code>mark</code>
7.254 + * method of the underlying input stream.
7.255 + *
7.256 + * @param readlimit the maximum limit of bytes that can be read before
7.257 + * the mark position becomes invalid.
7.258 + * @see java.io.FilterInputStream#in
7.259 + * @see java.io.LineNumberInputStream#reset()
7.260 + */
7.261 + public void mark(int readlimit) {
7.262 + markLineNumber = lineNumber;
7.263 + markPushBack = pushBack;
7.264 + in.mark(readlimit);
7.265 + }
7.266 +
7.267 + /**
7.268 + * Repositions this stream to the position at the time the
7.269 + * <code>mark</code> method was last called on this input stream.
7.270 + * <p>
7.271 + * The <code>reset</code> method of
7.272 + * <code>LineNumberInputStream</code> resets the line number to be
7.273 + * the line number at the time the <code>mark</code> method was
7.274 + * called, and then calls the <code>reset</code> method of the
7.275 + * underlying input stream.
7.276 + * <p>
7.277 + * Stream marks are intended to be used in
7.278 + * situations where you need to read ahead a little to see what's in
7.279 + * the stream. Often this is most easily done by invoking some
7.280 + * general parser. If the stream is of the type handled by the
7.281 + * parser, it just chugs along happily. If the stream is not of
7.282 + * that type, the parser should toss an exception when it fails,
7.283 + * which, if it happens within readlimit bytes, allows the outer
7.284 + * code to reset the stream and try another parser.
7.285 + *
7.286 + * @exception IOException if an I/O error occurs.
7.287 + * @see java.io.FilterInputStream#in
7.288 + * @see java.io.LineNumberInputStream#mark(int)
7.289 + */
7.290 + public void reset() throws IOException {
7.291 + lineNumber = markLineNumber;
7.292 + pushBack = markPushBack;
7.293 + in.reset();
7.294 + }
7.295 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberReader.java Thu Oct 03 15:43:10 2013 +0200
8.3 @@ -0,0 +1,281 @@
8.4 +/*
8.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8.7 + *
8.8 + * This code is free software; you can redistribute it and/or modify it
8.9 + * under the terms of the GNU General Public License version 2 only, as
8.10 + * published by the Free Software Foundation. Oracle designates this
8.11 + * particular file as subject to the "Classpath" exception as provided
8.12 + * by Oracle in the LICENSE file that accompanied this code.
8.13 + *
8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
8.17 + * version 2 for more details (a copy is included in the LICENSE file that
8.18 + * accompanied this code).
8.19 + *
8.20 + * You should have received a copy of the GNU General Public License version
8.21 + * 2 along with this work; if not, write to the Free Software Foundation,
8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
8.23 + *
8.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
8.25 + * or visit www.oracle.com if you need additional information or have any
8.26 + * questions.
8.27 + */
8.28 +
8.29 +package java.io;
8.30 +
8.31 +
8.32 +/**
8.33 + * A buffered character-input stream that keeps track of line numbers. This
8.34 + * class defines methods {@link #setLineNumber(int)} and {@link
8.35 + * #getLineNumber()} for setting and getting the current line number
8.36 + * respectively.
8.37 + *
8.38 + * <p> By default, line numbering begins at 0. This number increments at every
8.39 + * <a href="#lt">line terminator</a> as the data is read, and can be changed
8.40 + * with a call to <tt>setLineNumber(int)</tt>. Note however, that
8.41 + * <tt>setLineNumber(int)</tt> does not actually change the current position in
8.42 + * the stream; it only changes the value that will be returned by
8.43 + * <tt>getLineNumber()</tt>.
8.44 + *
8.45 + * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
8.46 + * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
8.47 + * immediately by a linefeed.
8.48 + *
8.49 + * @author Mark Reinhold
8.50 + * @since JDK1.1
8.51 + */
8.52 +
8.53 +public class LineNumberReader extends BufferedReader {
8.54 +
8.55 + /** The current line number */
8.56 + private int lineNumber = 0;
8.57 +
8.58 + /** The line number of the mark, if any */
8.59 + private int markedLineNumber; // Defaults to 0
8.60 +
8.61 + /** If the next character is a line feed, skip it */
8.62 + private boolean skipLF;
8.63 +
8.64 + /** The skipLF flag when the mark was set */
8.65 + private boolean markedSkipLF;
8.66 +
8.67 + /**
8.68 + * Create a new line-numbering reader, using the default input-buffer
8.69 + * size.
8.70 + *
8.71 + * @param in
8.72 + * A Reader object to provide the underlying stream
8.73 + */
8.74 + public LineNumberReader(Reader in) {
8.75 + super(in);
8.76 + }
8.77 +
8.78 + /**
8.79 + * Create a new line-numbering reader, reading characters into a buffer of
8.80 + * the given size.
8.81 + *
8.82 + * @param in
8.83 + * A Reader object to provide the underlying stream
8.84 + *
8.85 + * @param sz
8.86 + * An int specifying the size of the buffer
8.87 + */
8.88 + public LineNumberReader(Reader in, int sz) {
8.89 + super(in, sz);
8.90 + }
8.91 +
8.92 + /**
8.93 + * Set the current line number.
8.94 + *
8.95 + * @param lineNumber
8.96 + * An int specifying the line number
8.97 + *
8.98 + * @see #getLineNumber
8.99 + */
8.100 + public void setLineNumber(int lineNumber) {
8.101 + this.lineNumber = lineNumber;
8.102 + }
8.103 +
8.104 + /**
8.105 + * Get the current line number.
8.106 + *
8.107 + * @return The current line number
8.108 + *
8.109 + * @see #setLineNumber
8.110 + */
8.111 + public int getLineNumber() {
8.112 + return lineNumber;
8.113 + }
8.114 +
8.115 + /**
8.116 + * Read a single character. <a href="#lt">Line terminators</a> are
8.117 + * compressed into single newline ('\n') characters. Whenever a line
8.118 + * terminator is read the current line number is incremented.
8.119 + *
8.120 + * @return The character read, or -1 if the end of the stream has been
8.121 + * reached
8.122 + *
8.123 + * @throws IOException
8.124 + * If an I/O error occurs
8.125 + */
8.126 + public int read() throws IOException {
8.127 + synchronized (lock) {
8.128 + int c = super.read();
8.129 + if (skipLF) {
8.130 + if (c == '\n')
8.131 + c = super.read();
8.132 + skipLF = false;
8.133 + }
8.134 + switch (c) {
8.135 + case '\r':
8.136 + skipLF = true;
8.137 + case '\n': /* Fall through */
8.138 + lineNumber++;
8.139 + return '\n';
8.140 + }
8.141 + return c;
8.142 + }
8.143 + }
8.144 +
8.145 + /**
8.146 + * Read characters into a portion of an array. Whenever a <a
8.147 + * href="#lt">line terminator</a> is read the current line number is
8.148 + * incremented.
8.149 + *
8.150 + * @param cbuf
8.151 + * Destination buffer
8.152 + *
8.153 + * @param off
8.154 + * Offset at which to start storing characters
8.155 + *
8.156 + * @param len
8.157 + * Maximum number of characters to read
8.158 + *
8.159 + * @return The number of bytes read, or -1 if the end of the stream has
8.160 + * already been reached
8.161 + *
8.162 + * @throws IOException
8.163 + * If an I/O error occurs
8.164 + */
8.165 + public int read(char cbuf[], int off, int len) throws IOException {
8.166 + synchronized (lock) {
8.167 + int n = super.read(cbuf, off, len);
8.168 +
8.169 + for (int i = off; i < off + n; i++) {
8.170 + int c = cbuf[i];
8.171 + if (skipLF) {
8.172 + skipLF = false;
8.173 + if (c == '\n')
8.174 + continue;
8.175 + }
8.176 + switch (c) {
8.177 + case '\r':
8.178 + skipLF = true;
8.179 + case '\n': /* Fall through */
8.180 + lineNumber++;
8.181 + break;
8.182 + }
8.183 + }
8.184 +
8.185 + return n;
8.186 + }
8.187 + }
8.188 +
8.189 + /**
8.190 + * Read a line of text. Whenever a <a href="#lt">line terminator</a> is
8.191 + * read the current line number is incremented.
8.192 + *
8.193 + * @return A String containing the contents of the line, not including
8.194 + * any <a href="#lt">line termination characters</a>, or
8.195 + * <tt>null</tt> if the end of the stream has been reached
8.196 + *
8.197 + * @throws IOException
8.198 + * If an I/O error occurs
8.199 + */
8.200 + public String readLine() throws IOException {
8.201 + synchronized (lock) {
8.202 + String l = super.readLine(skipLF);
8.203 + skipLF = false;
8.204 + if (l != null)
8.205 + lineNumber++;
8.206 + return l;
8.207 + }
8.208 + }
8.209 +
8.210 + /** Maximum skip-buffer size */
8.211 + private static final int maxSkipBufferSize = 8192;
8.212 +
8.213 + /** Skip buffer, null until allocated */
8.214 + private char skipBuffer[] = null;
8.215 +
8.216 + /**
8.217 + * Skip characters.
8.218 + *
8.219 + * @param n
8.220 + * The number of characters to skip
8.221 + *
8.222 + * @return The number of characters actually skipped
8.223 + *
8.224 + * @throws IOException
8.225 + * If an I/O error occurs
8.226 + *
8.227 + * @throws IllegalArgumentException
8.228 + * If <tt>n</tt> is negative
8.229 + */
8.230 + public long skip(long n) throws IOException {
8.231 + if (n < 0)
8.232 + throw new IllegalArgumentException("skip() value is negative");
8.233 + int nn = (int) Math.min(n, maxSkipBufferSize);
8.234 + synchronized (lock) {
8.235 + if ((skipBuffer == null) || (skipBuffer.length < nn))
8.236 + skipBuffer = new char[nn];
8.237 + long r = n;
8.238 + while (r > 0) {
8.239 + int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
8.240 + if (nc == -1)
8.241 + break;
8.242 + r -= nc;
8.243 + }
8.244 + return n - r;
8.245 + }
8.246 + }
8.247 +
8.248 + /**
8.249 + * Mark the present position in the stream. Subsequent calls to reset()
8.250 + * will attempt to reposition the stream to this point, and will also reset
8.251 + * the line number appropriately.
8.252 + *
8.253 + * @param readAheadLimit
8.254 + * Limit on the number of characters that may be read while still
8.255 + * preserving the mark. After reading this many characters,
8.256 + * attempting to reset the stream may fail.
8.257 + *
8.258 + * @throws IOException
8.259 + * If an I/O error occurs
8.260 + */
8.261 + public void mark(int readAheadLimit) throws IOException {
8.262 + synchronized (lock) {
8.263 + super.mark(readAheadLimit);
8.264 + markedLineNumber = lineNumber;
8.265 + markedSkipLF = skipLF;
8.266 + }
8.267 + }
8.268 +
8.269 + /**
8.270 + * Reset the stream to the most recent mark.
8.271 + *
8.272 + * @throws IOException
8.273 + * If the stream has not been marked, or if the mark has been
8.274 + * invalidated
8.275 + */
8.276 + public void reset() throws IOException {
8.277 + synchronized (lock) {
8.278 + super.reset();
8.279 + lineNumber = markedLineNumber;
8.280 + skipLF = markedSkipLF;
8.281 + }
8.282 + }
8.283 +
8.284 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/rt/emul/compact/src/main/java/java/io/StringReader.java Thu Oct 03 15:43:10 2013 +0200
9.3 @@ -0,0 +1,201 @@
9.4 +/*
9.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9.7 + *
9.8 + * This code is free software; you can redistribute it and/or modify it
9.9 + * under the terms of the GNU General Public License version 2 only, as
9.10 + * published by the Free Software Foundation. Oracle designates this
9.11 + * particular file as subject to the "Classpath" exception as provided
9.12 + * by Oracle in the LICENSE file that accompanied this code.
9.13 + *
9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9.17 + * version 2 for more details (a copy is included in the LICENSE file that
9.18 + * accompanied this code).
9.19 + *
9.20 + * You should have received a copy of the GNU General Public License version
9.21 + * 2 along with this work; if not, write to the Free Software Foundation,
9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
9.23 + *
9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
9.25 + * or visit www.oracle.com if you need additional information or have any
9.26 + * questions.
9.27 + */
9.28 +
9.29 +package java.io;
9.30 +
9.31 +
9.32 +/**
9.33 + * A character stream whose source is a string.
9.34 + *
9.35 + * @author Mark Reinhold
9.36 + * @since JDK1.1
9.37 + */
9.38 +
9.39 +public class StringReader extends Reader {
9.40 +
9.41 + private String str;
9.42 + private int length;
9.43 + private int next = 0;
9.44 + private int mark = 0;
9.45 +
9.46 + /**
9.47 + * Creates a new string reader.
9.48 + *
9.49 + * @param s String providing the character stream.
9.50 + */
9.51 + public StringReader(String s) {
9.52 + this.str = s;
9.53 + this.length = s.length();
9.54 + }
9.55 +
9.56 + /** Check to make sure that the stream has not been closed */
9.57 + private void ensureOpen() throws IOException {
9.58 + if (str == null)
9.59 + throw new IOException("Stream closed");
9.60 + }
9.61 +
9.62 + /**
9.63 + * Reads a single character.
9.64 + *
9.65 + * @return The character read, or -1 if the end of the stream has been
9.66 + * reached
9.67 + *
9.68 + * @exception IOException If an I/O error occurs
9.69 + */
9.70 + public int read() throws IOException {
9.71 + synchronized (lock) {
9.72 + ensureOpen();
9.73 + if (next >= length)
9.74 + return -1;
9.75 + return str.charAt(next++);
9.76 + }
9.77 + }
9.78 +
9.79 + /**
9.80 + * Reads characters into a portion of an array.
9.81 + *
9.82 + * @param cbuf Destination buffer
9.83 + * @param off Offset at which to start writing characters
9.84 + * @param len Maximum number of characters to read
9.85 + *
9.86 + * @return The number of characters read, or -1 if the end of the
9.87 + * stream has been reached
9.88 + *
9.89 + * @exception IOException If an I/O error occurs
9.90 + */
9.91 + public int read(char cbuf[], int off, int len) throws IOException {
9.92 + synchronized (lock) {
9.93 + ensureOpen();
9.94 + if ((off < 0) || (off > cbuf.length) || (len < 0) ||
9.95 + ((off + len) > cbuf.length) || ((off + len) < 0)) {
9.96 + throw new IndexOutOfBoundsException();
9.97 + } else if (len == 0) {
9.98 + return 0;
9.99 + }
9.100 + if (next >= length)
9.101 + return -1;
9.102 + int n = Math.min(length - next, len);
9.103 + str.getChars(next, next + n, cbuf, off);
9.104 + next += n;
9.105 + return n;
9.106 + }
9.107 + }
9.108 +
9.109 + /**
9.110 + * Skips the specified number of characters in the stream. Returns
9.111 + * the number of characters that were skipped.
9.112 + *
9.113 + * <p>The <code>ns</code> parameter may be negative, even though the
9.114 + * <code>skip</code> method of the {@link Reader} superclass throws
9.115 + * an exception in this case. Negative values of <code>ns</code> cause the
9.116 + * stream to skip backwards. Negative return values indicate a skip
9.117 + * backwards. It is not possible to skip backwards past the beginning of
9.118 + * the string.
9.119 + *
9.120 + * <p>If the entire string has been read or skipped, then this method has
9.121 + * no effect and always returns 0.
9.122 + *
9.123 + * @exception IOException If an I/O error occurs
9.124 + */
9.125 + public long skip(long ns) throws IOException {
9.126 + synchronized (lock) {
9.127 + ensureOpen();
9.128 + if (next >= length)
9.129 + return 0;
9.130 + // Bound skip by beginning and end of the source
9.131 + long n = Math.min(length - next, ns);
9.132 + n = Math.max(-next, n);
9.133 + next += n;
9.134 + return n;
9.135 + }
9.136 + }
9.137 +
9.138 + /**
9.139 + * Tells whether this stream is ready to be read.
9.140 + *
9.141 + * @return True if the next read() is guaranteed not to block for input
9.142 + *
9.143 + * @exception IOException If the stream is closed
9.144 + */
9.145 + public boolean ready() throws IOException {
9.146 + synchronized (lock) {
9.147 + ensureOpen();
9.148 + return true;
9.149 + }
9.150 + }
9.151 +
9.152 + /**
9.153 + * Tells whether this stream supports the mark() operation, which it does.
9.154 + */
9.155 + public boolean markSupported() {
9.156 + return true;
9.157 + }
9.158 +
9.159 + /**
9.160 + * Marks the present position in the stream. Subsequent calls to reset()
9.161 + * will reposition the stream to this point.
9.162 + *
9.163 + * @param readAheadLimit Limit on the number of characters that may be
9.164 + * read while still preserving the mark. Because
9.165 + * the stream's input comes from a string, there
9.166 + * is no actual limit, so this argument must not
9.167 + * be negative, but is otherwise ignored.
9.168 + *
9.169 + * @exception IllegalArgumentException If readAheadLimit is < 0
9.170 + * @exception IOException If an I/O error occurs
9.171 + */
9.172 + public void mark(int readAheadLimit) throws IOException {
9.173 + if (readAheadLimit < 0){
9.174 + throw new IllegalArgumentException("Read-ahead limit < 0");
9.175 + }
9.176 + synchronized (lock) {
9.177 + ensureOpen();
9.178 + mark = next;
9.179 + }
9.180 + }
9.181 +
9.182 + /**
9.183 + * Resets the stream to the most recent mark, or to the beginning of the
9.184 + * string if it has never been marked.
9.185 + *
9.186 + * @exception IOException If an I/O error occurs
9.187 + */
9.188 + public void reset() throws IOException {
9.189 + synchronized (lock) {
9.190 + ensureOpen();
9.191 + next = mark;
9.192 + }
9.193 + }
9.194 +
9.195 + /**
9.196 + * Closes the stream and releases any system resources associated with
9.197 + * it. Once the stream has been closed, further read(),
9.198 + * ready(), mark(), or reset() invocations will throw an IOException.
9.199 + * Closing a previously closed stream has no effect.
9.200 + */
9.201 + public void close() {
9.202 + str = null;
9.203 + }
9.204 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/rt/emul/compact/src/main/java/java/io/StringWriter.java Thu Oct 03 15:43:10 2013 +0200
10.3 @@ -0,0 +1,236 @@
10.4 +/*
10.5 + * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10.7 + *
10.8 + * This code is free software; you can redistribute it and/or modify it
10.9 + * under the terms of the GNU General Public License version 2 only, as
10.10 + * published by the Free Software Foundation. Oracle designates this
10.11 + * particular file as subject to the "Classpath" exception as provided
10.12 + * by Oracle in the LICENSE file that accompanied this code.
10.13 + *
10.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
10.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10.17 + * version 2 for more details (a copy is included in the LICENSE file that
10.18 + * accompanied this code).
10.19 + *
10.20 + * You should have received a copy of the GNU General Public License version
10.21 + * 2 along with this work; if not, write to the Free Software Foundation,
10.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
10.23 + *
10.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
10.25 + * or visit www.oracle.com if you need additional information or have any
10.26 + * questions.
10.27 + */
10.28 +
10.29 +package java.io;
10.30 +
10.31 +
10.32 +/**
10.33 + * A character stream that collects its output in a string buffer, which can
10.34 + * then be used to construct a string.
10.35 + * <p>
10.36 + * Closing a <tt>StringWriter</tt> has no effect. The methods in this class
10.37 + * can be called after the stream has been closed without generating an
10.38 + * <tt>IOException</tt>.
10.39 + *
10.40 + * @author Mark Reinhold
10.41 + * @since JDK1.1
10.42 + */
10.43 +
10.44 +public class StringWriter extends Writer {
10.45 +
10.46 + private StringBuffer buf;
10.47 +
10.48 + /**
10.49 + * Create a new string writer using the default initial string-buffer
10.50 + * size.
10.51 + */
10.52 + public StringWriter() {
10.53 + buf = new StringBuffer();
10.54 + lock = buf;
10.55 + }
10.56 +
10.57 + /**
10.58 + * Create a new string writer using the specified initial string-buffer
10.59 + * size.
10.60 + *
10.61 + * @param initialSize
10.62 + * The number of <tt>char</tt> values that will fit into this buffer
10.63 + * before it is automatically expanded
10.64 + *
10.65 + * @throws IllegalArgumentException
10.66 + * If <tt>initialSize</tt> is negative
10.67 + */
10.68 + public StringWriter(int initialSize) {
10.69 + if (initialSize < 0) {
10.70 + throw new IllegalArgumentException("Negative buffer size");
10.71 + }
10.72 + buf = new StringBuffer(initialSize);
10.73 + lock = buf;
10.74 + }
10.75 +
10.76 + /**
10.77 + * Write a single character.
10.78 + */
10.79 + public void write(int c) {
10.80 + buf.append((char) c);
10.81 + }
10.82 +
10.83 + /**
10.84 + * Write a portion of an array of characters.
10.85 + *
10.86 + * @param cbuf Array of characters
10.87 + * @param off Offset from which to start writing characters
10.88 + * @param len Number of characters to write
10.89 + */
10.90 + public void write(char cbuf[], int off, int len) {
10.91 + if ((off < 0) || (off > cbuf.length) || (len < 0) ||
10.92 + ((off + len) > cbuf.length) || ((off + len) < 0)) {
10.93 + throw new IndexOutOfBoundsException();
10.94 + } else if (len == 0) {
10.95 + return;
10.96 + }
10.97 + buf.append(cbuf, off, len);
10.98 + }
10.99 +
10.100 + /**
10.101 + * Write a string.
10.102 + */
10.103 + public void write(String str) {
10.104 + buf.append(str);
10.105 + }
10.106 +
10.107 + /**
10.108 + * Write a portion of a string.
10.109 + *
10.110 + * @param str String to be written
10.111 + * @param off Offset from which to start writing characters
10.112 + * @param len Number of characters to write
10.113 + */
10.114 + public void write(String str, int off, int len) {
10.115 + buf.append(str.substring(off, off + len));
10.116 + }
10.117 +
10.118 + /**
10.119 + * Appends the specified character sequence to this writer.
10.120 + *
10.121 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
10.122 + * behaves in exactly the same way as the invocation
10.123 + *
10.124 + * <pre>
10.125 + * out.write(csq.toString()) </pre>
10.126 + *
10.127 + * <p> Depending on the specification of <tt>toString</tt> for the
10.128 + * character sequence <tt>csq</tt>, the entire sequence may not be
10.129 + * appended. For instance, invoking the <tt>toString</tt> method of a
10.130 + * character buffer will return a subsequence whose content depends upon
10.131 + * the buffer's position and limit.
10.132 + *
10.133 + * @param csq
10.134 + * The character sequence to append. If <tt>csq</tt> is
10.135 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
10.136 + * appended to this writer.
10.137 + *
10.138 + * @return This writer
10.139 + *
10.140 + * @since 1.5
10.141 + */
10.142 + public StringWriter append(CharSequence csq) {
10.143 + if (csq == null)
10.144 + write("null");
10.145 + else
10.146 + write(csq.toString());
10.147 + return this;
10.148 + }
10.149 +
10.150 + /**
10.151 + * Appends a subsequence of the specified character sequence to this writer.
10.152 + *
10.153 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
10.154 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
10.155 + * exactly the same way as the invocation
10.156 + *
10.157 + * <pre>
10.158 + * out.write(csq.subSequence(start, end).toString()) </pre>
10.159 + *
10.160 + * @param csq
10.161 + * The character sequence from which a subsequence will be
10.162 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
10.163 + * will be appended as if <tt>csq</tt> contained the four
10.164 + * characters <tt>"null"</tt>.
10.165 + *
10.166 + * @param start
10.167 + * The index of the first character in the subsequence
10.168 + *
10.169 + * @param end
10.170 + * The index of the character following the last character in the
10.171 + * subsequence
10.172 + *
10.173 + * @return This writer
10.174 + *
10.175 + * @throws IndexOutOfBoundsException
10.176 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
10.177 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
10.178 + * <tt>csq.length()</tt>
10.179 + *
10.180 + * @since 1.5
10.181 + */
10.182 + public StringWriter append(CharSequence csq, int start, int end) {
10.183 + CharSequence cs = (csq == null ? "null" : csq);
10.184 + write(cs.subSequence(start, end).toString());
10.185 + return this;
10.186 + }
10.187 +
10.188 + /**
10.189 + * Appends the specified character to this writer.
10.190 + *
10.191 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
10.192 + * behaves in exactly the same way as the invocation
10.193 + *
10.194 + * <pre>
10.195 + * out.write(c) </pre>
10.196 + *
10.197 + * @param c
10.198 + * The 16-bit character to append
10.199 + *
10.200 + * @return This writer
10.201 + *
10.202 + * @since 1.5
10.203 + */
10.204 + public StringWriter append(char c) {
10.205 + write(c);
10.206 + return this;
10.207 + }
10.208 +
10.209 + /**
10.210 + * Return the buffer's current value as a string.
10.211 + */
10.212 + public String toString() {
10.213 + return buf.toString();
10.214 + }
10.215 +
10.216 + /**
10.217 + * Return the string buffer itself.
10.218 + *
10.219 + * @return StringBuffer holding the current buffer value.
10.220 + */
10.221 + public StringBuffer getBuffer() {
10.222 + return buf;
10.223 + }
10.224 +
10.225 + /**
10.226 + * Flush the stream.
10.227 + */
10.228 + public void flush() {
10.229 + }
10.230 +
10.231 + /**
10.232 + * Closing a <tt>StringWriter</tt> has no effect. The methods in this
10.233 + * class can be called after the stream has been closed without generating
10.234 + * an <tt>IOException</tt>.
10.235 + */
10.236 + public void close() throws IOException {
10.237 + }
10.238 +
10.239 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/rt/emul/compact/src/main/java/java/io/SyncFailedException.java Thu Oct 03 15:43:10 2013 +0200
11.3 @@ -0,0 +1,48 @@
11.4 +/*
11.5 + * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
11.7 + *
11.8 + * This code is free software; you can redistribute it and/or modify it
11.9 + * under the terms of the GNU General Public License version 2 only, as
11.10 + * published by the Free Software Foundation. Oracle designates this
11.11 + * particular file as subject to the "Classpath" exception as provided
11.12 + * by Oracle in the LICENSE file that accompanied this code.
11.13 + *
11.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
11.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11.17 + * version 2 for more details (a copy is included in the LICENSE file that
11.18 + * accompanied this code).
11.19 + *
11.20 + * You should have received a copy of the GNU General Public License version
11.21 + * 2 along with this work; if not, write to the Free Software Foundation,
11.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
11.23 + *
11.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
11.25 + * or visit www.oracle.com if you need additional information or have any
11.26 + * questions.
11.27 + */
11.28 +
11.29 +package java.io;
11.30 +
11.31 +/**
11.32 + * Signals that a sync operation has failed.
11.33 + *
11.34 + * @author Ken Arnold
11.35 + * @see java.io.FileDescriptor#sync
11.36 + * @see java.io.IOException
11.37 + * @since JDK1.1
11.38 + */
11.39 +public class SyncFailedException extends IOException {
11.40 + private static final long serialVersionUID = -2353342684412443330L;
11.41 +
11.42 + /**
11.43 + * Constructs an SyncFailedException with a detail message.
11.44 + * A detail message is a String that describes this particular exception.
11.45 + *
11.46 + * @param desc a String describing the exception.
11.47 + */
11.48 + public SyncFailedException(String desc) {
11.49 + super(desc);
11.50 + }
11.51 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/Charset.java Thu Oct 03 15:43:10 2013 +0200
12.3 @@ -0,0 +1,923 @@
12.4 +/*
12.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
12.7 + *
12.8 + * This code is free software; you can redistribute it and/or modify it
12.9 + * under the terms of the GNU General Public License version 2 only, as
12.10 + * published by the Free Software Foundation. Oracle designates this
12.11 + * particular file as subject to the "Classpath" exception as provided
12.12 + * by Oracle in the LICENSE file that accompanied this code.
12.13 + *
12.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
12.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12.17 + * version 2 for more details (a copy is included in the LICENSE file that
12.18 + * accompanied this code).
12.19 + *
12.20 + * You should have received a copy of the GNU General Public License version
12.21 + * 2 along with this work; if not, write to the Free Software Foundation,
12.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
12.23 + *
12.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
12.25 + * or visit www.oracle.com if you need additional information or have any
12.26 + * questions.
12.27 + */
12.28 +
12.29 +package java.nio.charset;
12.30 +
12.31 +import java.nio.ByteBuffer;
12.32 +import java.nio.CharBuffer;
12.33 +import java.nio.charset.spi.CharsetProvider;
12.34 +import java.security.AccessController;
12.35 +import java.security.AccessControlException;
12.36 +import java.security.PrivilegedAction;
12.37 +import java.util.Collections;
12.38 +import java.util.HashSet;
12.39 +import java.util.Iterator;
12.40 +import java.util.Locale;
12.41 +import java.util.Map;
12.42 +import java.util.NoSuchElementException;
12.43 +import java.util.Set;
12.44 +import java.util.ServiceLoader;
12.45 +import java.util.ServiceConfigurationError;
12.46 +import java.util.SortedMap;
12.47 +import java.util.TreeMap;
12.48 +import sun.misc.ASCIICaseInsensitiveComparator;
12.49 +import sun.nio.cs.StandardCharsets;
12.50 +import sun.nio.cs.ThreadLocalCoders;
12.51 +import sun.security.action.GetPropertyAction;
12.52 +
12.53 +
12.54 +/**
12.55 + * A named mapping between sequences of sixteen-bit Unicode <a
12.56 + * href="../../lang/Character.html#unicode">code units</a> and sequences of
12.57 + * bytes. This class defines methods for creating decoders and encoders and
12.58 + * for retrieving the various names associated with a charset. Instances of
12.59 + * this class are immutable.
12.60 + *
12.61 + * <p> This class also defines static methods for testing whether a particular
12.62 + * charset is supported, for locating charset instances by name, and for
12.63 + * constructing a map that contains every charset for which support is
12.64 + * available in the current Java virtual machine. Support for new charsets can
12.65 + * be added via the service-provider interface defined in the {@link
12.66 + * java.nio.charset.spi.CharsetProvider} class.
12.67 + *
12.68 + * <p> All of the methods defined in this class are safe for use by multiple
12.69 + * concurrent threads.
12.70 + *
12.71 + *
12.72 + * <a name="names"><a name="charenc">
12.73 + * <h4>Charset names</h4>
12.74 + *
12.75 + * <p> Charsets are named by strings composed of the following characters:
12.76 + *
12.77 + * <ul>
12.78 + *
12.79 + * <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
12.80 + * (<tt>'\u0041'</tt> through <tt>'\u005a'</tt>),
12.81 + *
12.82 + * <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
12.83 + * (<tt>'\u0061'</tt> through <tt>'\u007a'</tt>),
12.84 + *
12.85 + * <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
12.86 + * (<tt>'\u0030'</tt> through <tt>'\u0039'</tt>),
12.87 + *
12.88 + * <li> The dash character <tt>'-'</tt>
12.89 + * (<tt>'\u002d'</tt>, <small>HYPHEN-MINUS</small>),
12.90 + *
12.91 + * <li> The plus character <tt>'+'</tt>
12.92 + * (<tt>'\u002b'</tt>, <small>PLUS SIGN</small>),
12.93 + *
12.94 + * <li> The period character <tt>'.'</tt>
12.95 + * (<tt>'\u002e'</tt>, <small>FULL STOP</small>),
12.96 + *
12.97 + * <li> The colon character <tt>':'</tt>
12.98 + * (<tt>'\u003a'</tt>, <small>COLON</small>), and
12.99 + *
12.100 + * <li> The underscore character <tt>'_'</tt>
12.101 + * (<tt>'\u005f'</tt>, <small>LOW LINE</small>).
12.102 + *
12.103 + * </ul>
12.104 + *
12.105 + * A charset name must begin with either a letter or a digit. The empty string
12.106 + * is not a legal charset name. Charset names are not case-sensitive; that is,
12.107 + * case is always ignored when comparing charset names. Charset names
12.108 + * generally follow the conventions documented in <a
12.109 + * href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC 2278: IANA Charset
12.110 + * Registration Procedures</i></a>.
12.111 + *
12.112 + * <p> Every charset has a <i>canonical name</i> and may also have one or more
12.113 + * <i>aliases</i>. The canonical name is returned by the {@link #name() name} method
12.114 + * of this class. Canonical names are, by convention, usually in upper case.
12.115 + * The aliases of a charset are returned by the {@link #aliases() aliases}
12.116 + * method.
12.117 + *
12.118 + * <a name="hn">
12.119 + *
12.120 + * <p> Some charsets have an <i>historical name</i> that is defined for
12.121 + * compatibility with previous versions of the Java platform. A charset's
12.122 + * historical name is either its canonical name or one of its aliases. The
12.123 + * historical name is returned by the <tt>getEncoding()</tt> methods of the
12.124 + * {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link
12.125 + * java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes.
12.126 + *
12.127 + * <a name="iana">
12.128 + *
12.129 + * <p> If a charset listed in the <a
12.130 + * href="http://www.iana.org/assignments/character-sets"><i>IANA Charset
12.131 + * Registry</i></a> is supported by an implementation of the Java platform then
12.132 + * its canonical name must be the name listed in the registry. Many charsets
12.133 + * are given more than one name in the registry, in which case the registry
12.134 + * identifies one of the names as <i>MIME-preferred</i>. If a charset has more
12.135 + * than one registry name then its canonical name must be the MIME-preferred
12.136 + * name and the other names in the registry must be valid aliases. If a
12.137 + * supported charset is not listed in the IANA registry then its canonical name
12.138 + * must begin with one of the strings <tt>"X-"</tt> or <tt>"x-"</tt>.
12.139 + *
12.140 + * <p> The IANA charset registry does change over time, and so the canonical
12.141 + * name and the aliases of a particular charset may also change over time. To
12.142 + * ensure compatibility it is recommended that no alias ever be removed from a
12.143 + * charset, and that if the canonical name of a charset is changed then its
12.144 + * previous canonical name be made into an alias.
12.145 + *
12.146 + *
12.147 + * <h4>Standard charsets</h4>
12.148 + *
12.149 + * <a name="standard">
12.150 + *
12.151 + * <p> Every implementation of the Java platform is required to support the
12.152 + * following standard charsets. Consult the release documentation for your
12.153 + * implementation to see if any other charsets are supported. The behavior
12.154 + * of such optional charsets may differ between implementations.
12.155 + *
12.156 + * <blockquote><table width="80%" summary="Description of standard charsets">
12.157 + * <tr><th><p align="left">Charset</p></th><th><p align="left">Description</p></th></tr>
12.158 + * <tr><td valign=top><tt>US-ASCII</tt></td>
12.159 + * <td>Seven-bit ASCII, a.k.a. <tt>ISO646-US</tt>,
12.160 + * a.k.a. the Basic Latin block of the Unicode character set</td></tr>
12.161 + * <tr><td valign=top><tt>ISO-8859-1 </tt></td>
12.162 + * <td>ISO Latin Alphabet No. 1, a.k.a. <tt>ISO-LATIN-1</tt></td></tr>
12.163 + * <tr><td valign=top><tt>UTF-8</tt></td>
12.164 + * <td>Eight-bit UCS Transformation Format</td></tr>
12.165 + * <tr><td valign=top><tt>UTF-16BE</tt></td>
12.166 + * <td>Sixteen-bit UCS Transformation Format,
12.167 + * big-endian byte order</td></tr>
12.168 + * <tr><td valign=top><tt>UTF-16LE</tt></td>
12.169 + * <td>Sixteen-bit UCS Transformation Format,
12.170 + * little-endian byte order</td></tr>
12.171 + * <tr><td valign=top><tt>UTF-16</tt></td>
12.172 + * <td>Sixteen-bit UCS Transformation Format,
12.173 + * byte order identified by an optional byte-order mark</td></tr>
12.174 + * </table></blockquote>
12.175 + *
12.176 + * <p> The <tt>UTF-8</tt> charset is specified by <a
12.177 + * href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC 2279</i></a>; the
12.178 + * transformation format upon which it is based is specified in
12.179 + * Amendment 2 of ISO 10646-1 and is also described in the <a
12.180 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
12.181 + * Standard</i></a>.
12.182 + *
12.183 + * <p> The <tt>UTF-16</tt> charsets are specified by <a
12.184 + * href="http://www.ietf.org/rfc/rfc2781.txt"><i>RFC 2781</i></a>; the
12.185 + * transformation formats upon which they are based are specified in
12.186 + * Amendment 1 of ISO 10646-1 and are also described in the <a
12.187 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
12.188 + * Standard</i></a>.
12.189 + *
12.190 + * <p> The <tt>UTF-16</tt> charsets use sixteen-bit quantities and are
12.191 + * therefore sensitive to byte order. In these encodings the byte order of a
12.192 + * stream may be indicated by an initial <i>byte-order mark</i> represented by
12.193 + * the Unicode character <tt>'\uFEFF'</tt>. Byte-order marks are handled
12.194 + * as follows:
12.195 + *
12.196 + * <ul>
12.197 + *
12.198 + * <li><p> When decoding, the <tt>UTF-16BE</tt> and <tt>UTF-16LE</tt>
12.199 + * charsets interpret the initial byte-order marks as a <small>ZERO-WIDTH
12.200 + * NON-BREAKING SPACE</small>; when encoding, they do not write
12.201 + * byte-order marks. </p></li>
12.202 +
12.203 + *
12.204 + * <li><p> When decoding, the <tt>UTF-16</tt> charset interprets the
12.205 + * byte-order mark at the beginning of the input stream to indicate the
12.206 + * byte-order of the stream but defaults to big-endian if there is no
12.207 + * byte-order mark; when encoding, it uses big-endian byte order and writes
12.208 + * a big-endian byte-order mark. </p></li>
12.209 + *
12.210 + * </ul>
12.211 + *
12.212 + * In any case, byte order marks occuring after the first element of an
12.213 + * input sequence are not omitted since the same code is used to represent
12.214 + * <small>ZERO-WIDTH NON-BREAKING SPACE</small>.
12.215 + *
12.216 + * <p> Every instance of the Java virtual machine has a default charset, which
12.217 + * may or may not be one of the standard charsets. The default charset is
12.218 + * determined during virtual-machine startup and typically depends upon the
12.219 + * locale and charset being used by the underlying operating system. </p>
12.220 + *
12.221 + * <p>The {@link StandardCharsets} class defines constants for each of the
12.222 + * standard charsets.
12.223 + *
12.224 + * <h4>Terminology</h4>
12.225 + *
12.226 + * <p> The name of this class is taken from the terms used in
12.227 + * <a href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC 2278</i></a>.
12.228 + * In that document a <i>charset</i> is defined as the combination of
12.229 + * one or more coded character sets and a character-encoding scheme.
12.230 + * (This definition is confusing; some other software systems define
12.231 + * <i>charset</i> as a synonym for <i>coded character set</i>.)
12.232 + *
12.233 + * <p> A <i>coded character set</i> is a mapping between a set of abstract
12.234 + * characters and a set of integers. US-ASCII, ISO 8859-1,
12.235 + * JIS X 0201, and Unicode are examples of coded character sets.
12.236 + *
12.237 + * <p> Some standards have defined a <i>character set</i> to be simply a
12.238 + * set of abstract characters without an associated assigned numbering.
12.239 + * An alphabet is an example of such a character set. However, the subtle
12.240 + * distinction between <i>character set</i> and <i>coded character set</i>
12.241 + * is rarely used in practice; the former has become a short form for the
12.242 + * latter, including in the Java API specification.
12.243 + *
12.244 + * <p> A <i>character-encoding scheme</i> is a mapping between one or more
12.245 + * coded character sets and a set of octet (eight-bit byte) sequences.
12.246 + * UTF-8, UTF-16, ISO 2022, and EUC are examples of
12.247 + * character-encoding schemes. Encoding schemes are often associated with
12.248 + * a particular coded character set; UTF-8, for example, is used only to
12.249 + * encode Unicode. Some schemes, however, are associated with multiple
12.250 + * coded character sets; EUC, for example, can be used to encode
12.251 + * characters in a variety of Asian coded character sets.
12.252 + *
12.253 + * <p> When a coded character set is used exclusively with a single
12.254 + * character-encoding scheme then the corresponding charset is usually
12.255 + * named for the coded character set; otherwise a charset is usually named
12.256 + * for the encoding scheme and, possibly, the locale of the coded
12.257 + * character sets that it supports. Hence <tt>US-ASCII</tt> is both the
12.258 + * name of a coded character set and of the charset that encodes it, while
12.259 + * <tt>EUC-JP</tt> is the name of the charset that encodes the
12.260 + * JIS X 0201, JIS X 0208, and JIS X 0212
12.261 + * coded character sets for the Japanese language.
12.262 + *
12.263 + * <p> The native character encoding of the Java programming language is
12.264 + * UTF-16. A charset in the Java platform therefore defines a mapping
12.265 + * between sequences of sixteen-bit UTF-16 code units (that is, sequences
12.266 + * of chars) and sequences of bytes. </p>
12.267 + *
12.268 + *
12.269 + * @author Mark Reinhold
12.270 + * @author JSR-51 Expert Group
12.271 + * @since 1.4
12.272 + *
12.273 + * @see CharsetDecoder
12.274 + * @see CharsetEncoder
12.275 + * @see java.nio.charset.spi.CharsetProvider
12.276 + * @see java.lang.Character
12.277 + */
12.278 +
12.279 +public abstract class Charset
12.280 + implements Comparable<Charset>
12.281 +{
12.282 +
12.283 + /* -- Static methods -- */
12.284 +
12.285 + private static volatile String bugLevel = null;
12.286 +
12.287 + static boolean atBugLevel(String bl) { // package-private
12.288 + String level = bugLevel;
12.289 + if (level == null) {
12.290 + if (!sun.misc.VM.isBooted())
12.291 + return false;
12.292 + bugLevel = level = AccessController.doPrivileged(
12.293 + new GetPropertyAction("sun.nio.cs.bugLevel", ""));
12.294 + }
12.295 + return level.equals(bl);
12.296 + }
12.297 +
12.298 + /**
12.299 + * Checks that the given string is a legal charset name. </p>
12.300 + *
12.301 + * @param s
12.302 + * A purported charset name
12.303 + *
12.304 + * @throws IllegalCharsetNameException
12.305 + * If the given name is not a legal charset name
12.306 + */
12.307 + private static void checkName(String s) {
12.308 + int n = s.length();
12.309 + if (!atBugLevel("1.4")) {
12.310 + if (n == 0)
12.311 + throw new IllegalCharsetNameException(s);
12.312 + }
12.313 + for (int i = 0; i < n; i++) {
12.314 + char c = s.charAt(i);
12.315 + if (c >= 'A' && c <= 'Z') continue;
12.316 + if (c >= 'a' && c <= 'z') continue;
12.317 + if (c >= '0' && c <= '9') continue;
12.318 + if (c == '-' && i != 0) continue;
12.319 + if (c == '+' && i != 0) continue;
12.320 + if (c == ':' && i != 0) continue;
12.321 + if (c == '_' && i != 0) continue;
12.322 + if (c == '.' && i != 0) continue;
12.323 + throw new IllegalCharsetNameException(s);
12.324 + }
12.325 + }
12.326 +
12.327 + /* The standard set of charsets */
12.328 + private static CharsetProvider standardProvider = new StandardCharsets();
12.329 +
12.330 + // Cache of the most-recently-returned charsets,
12.331 + // along with the names that were used to find them
12.332 + //
12.333 + private static volatile Object[] cache1 = null; // "Level 1" cache
12.334 + private static volatile Object[] cache2 = null; // "Level 2" cache
12.335 +
12.336 + private static void cache(String charsetName, Charset cs) {
12.337 + cache2 = cache1;
12.338 + cache1 = new Object[] { charsetName, cs };
12.339 + }
12.340 +
12.341 + // Creates an iterator that walks over the available providers, ignoring
12.342 + // those whose lookup or instantiation causes a security exception to be
12.343 + // thrown. Should be invoked with full privileges.
12.344 + //
12.345 + private static Iterator providers() {
12.346 + return new Iterator() {
12.347 +
12.348 + ClassLoader cl = ClassLoader.getSystemClassLoader();
12.349 + ServiceLoader<CharsetProvider> sl =
12.350 + ServiceLoader.load(CharsetProvider.class, cl);
12.351 + Iterator<CharsetProvider> i = sl.iterator();
12.352 +
12.353 + Object next = null;
12.354 +
12.355 + private boolean getNext() {
12.356 + while (next == null) {
12.357 + try {
12.358 + if (!i.hasNext())
12.359 + return false;
12.360 + next = i.next();
12.361 + } catch (ServiceConfigurationError sce) {
12.362 + if (sce.getCause() instanceof SecurityException) {
12.363 + // Ignore security exceptions
12.364 + continue;
12.365 + }
12.366 + throw sce;
12.367 + }
12.368 + }
12.369 + return true;
12.370 + }
12.371 +
12.372 + public boolean hasNext() {
12.373 + return getNext();
12.374 + }
12.375 +
12.376 + public Object next() {
12.377 + if (!getNext())
12.378 + throw new NoSuchElementException();
12.379 + Object n = next;
12.380 + next = null;
12.381 + return n;
12.382 + }
12.383 +
12.384 + public void remove() {
12.385 + throw new UnsupportedOperationException();
12.386 + }
12.387 +
12.388 + };
12.389 + }
12.390 +
12.391 + // Thread-local gate to prevent recursive provider lookups
12.392 + private static ThreadLocal<ThreadLocal> gate = new ThreadLocal<ThreadLocal>();
12.393 +
12.394 + private static Charset lookupViaProviders(final String charsetName) {
12.395 +
12.396 + // The runtime startup sequence looks up standard charsets as a
12.397 + // consequence of the VM's invocation of System.initializeSystemClass
12.398 + // in order to, e.g., set system properties and encode filenames. At
12.399 + // that point the application class loader has not been initialized,
12.400 + // however, so we can't look for providers because doing so will cause
12.401 + // that loader to be prematurely initialized with incomplete
12.402 + // information.
12.403 + //
12.404 + if (!sun.misc.VM.isBooted())
12.405 + return null;
12.406 +
12.407 + if (gate.get() != null)
12.408 + // Avoid recursive provider lookups
12.409 + return null;
12.410 + try {
12.411 + gate.set(gate);
12.412 +
12.413 + return AccessController.doPrivileged(
12.414 + new PrivilegedAction<Charset>() {
12.415 + public Charset run() {
12.416 + for (Iterator i = providers(); i.hasNext();) {
12.417 + CharsetProvider cp = (CharsetProvider)i.next();
12.418 + Charset cs = cp.charsetForName(charsetName);
12.419 + if (cs != null)
12.420 + return cs;
12.421 + }
12.422 + return null;
12.423 + }
12.424 + });
12.425 +
12.426 + } finally {
12.427 + gate.set(null);
12.428 + }
12.429 + }
12.430 +
12.431 + /* The extended set of charsets */
12.432 + private static Object extendedProviderLock = new Object();
12.433 + private static boolean extendedProviderProbed = false;
12.434 + private static CharsetProvider extendedProvider = null;
12.435 +
12.436 + private static void probeExtendedProvider() {
12.437 + AccessController.doPrivileged(new PrivilegedAction<Object>() {
12.438 + public Object run() {
12.439 + try {
12.440 + Class epc
12.441 + = Class.forName("sun.nio.cs.ext.ExtendedCharsets");
12.442 + extendedProvider = (CharsetProvider)epc.newInstance();
12.443 + } catch (ClassNotFoundException x) {
12.444 + // Extended charsets not available
12.445 + // (charsets.jar not present)
12.446 + } catch (InstantiationException x) {
12.447 + throw new Error(x);
12.448 + } catch (IllegalAccessException x) {
12.449 + throw new Error(x);
12.450 + }
12.451 + return null;
12.452 + }
12.453 + });
12.454 + }
12.455 +
12.456 + private static Charset lookupExtendedCharset(String charsetName) {
12.457 + CharsetProvider ecp = null;
12.458 + synchronized (extendedProviderLock) {
12.459 + if (!extendedProviderProbed) {
12.460 + probeExtendedProvider();
12.461 + extendedProviderProbed = true;
12.462 + }
12.463 + ecp = extendedProvider;
12.464 + }
12.465 + return (ecp != null) ? ecp.charsetForName(charsetName) : null;
12.466 + }
12.467 +
12.468 + private static Charset lookup(String charsetName) {
12.469 + if (charsetName == null)
12.470 + throw new IllegalArgumentException("Null charset name");
12.471 +
12.472 + Object[] a;
12.473 + if ((a = cache1) != null && charsetName.equals(a[0]))
12.474 + return (Charset)a[1];
12.475 + // We expect most programs to use one Charset repeatedly.
12.476 + // We convey a hint to this effect to the VM by putting the
12.477 + // level 1 cache miss code in a separate method.
12.478 + return lookup2(charsetName);
12.479 + }
12.480 +
12.481 + private static Charset lookup2(String charsetName) {
12.482 + Object[] a;
12.483 + if ((a = cache2) != null && charsetName.equals(a[0])) {
12.484 + cache2 = cache1;
12.485 + cache1 = a;
12.486 + return (Charset)a[1];
12.487 + }
12.488 +
12.489 + Charset cs;
12.490 + if ((cs = standardProvider.charsetForName(charsetName)) != null ||
12.491 + (cs = lookupExtendedCharset(charsetName)) != null ||
12.492 + (cs = lookupViaProviders(charsetName)) != null)
12.493 + {
12.494 + cache(charsetName, cs);
12.495 + return cs;
12.496 + }
12.497 +
12.498 + /* Only need to check the name if we didn't find a charset for it */
12.499 + checkName(charsetName);
12.500 + return null;
12.501 + }
12.502 +
12.503 + /**
12.504 + * Tells whether the named charset is supported. </p>
12.505 + *
12.506 + * @param charsetName
12.507 + * The name of the requested charset; may be either
12.508 + * a canonical name or an alias
12.509 + *
12.510 + * @return <tt>true</tt> if, and only if, support for the named charset
12.511 + * is available in the current Java virtual machine
12.512 + *
12.513 + * @throws IllegalCharsetNameException
12.514 + * If the given charset name is illegal
12.515 + *
12.516 + * @throws IllegalArgumentException
12.517 + * If the given <tt>charsetName</tt> is null
12.518 + */
12.519 + public static boolean isSupported(String charsetName) {
12.520 + return (lookup(charsetName) != null);
12.521 + }
12.522 +
12.523 + /**
12.524 + * Returns a charset object for the named charset. </p>
12.525 + *
12.526 + * @param charsetName
12.527 + * The name of the requested charset; may be either
12.528 + * a canonical name or an alias
12.529 + *
12.530 + * @return A charset object for the named charset
12.531 + *
12.532 + * @throws IllegalCharsetNameException
12.533 + * If the given charset name is illegal
12.534 + *
12.535 + * @throws IllegalArgumentException
12.536 + * If the given <tt>charsetName</tt> is null
12.537 + *
12.538 + * @throws UnsupportedCharsetException
12.539 + * If no support for the named charset is available
12.540 + * in this instance of the Java virtual machine
12.541 + */
12.542 + public static Charset forName(String charsetName) {
12.543 + Charset cs = lookup(charsetName);
12.544 + if (cs != null)
12.545 + return cs;
12.546 + throw new UnsupportedCharsetException(charsetName);
12.547 + }
12.548 +
12.549 + // Fold charsets from the given iterator into the given map, ignoring
12.550 + // charsets whose names already have entries in the map.
12.551 + //
12.552 + private static void put(Iterator<Charset> i, Map<String,Charset> m) {
12.553 + while (i.hasNext()) {
12.554 + Charset cs = i.next();
12.555 + if (!m.containsKey(cs.name()))
12.556 + m.put(cs.name(), cs);
12.557 + }
12.558 + }
12.559 +
12.560 + /**
12.561 + * Constructs a sorted map from canonical charset names to charset objects.
12.562 + *
12.563 + * <p> The map returned by this method will have one entry for each charset
12.564 + * for which support is available in the current Java virtual machine. If
12.565 + * two or more supported charsets have the same canonical name then the
12.566 + * resulting map will contain just one of them; which one it will contain
12.567 + * is not specified. </p>
12.568 + *
12.569 + * <p> The invocation of this method, and the subsequent use of the
12.570 + * resulting map, may cause time-consuming disk or network I/O operations
12.571 + * to occur. This method is provided for applications that need to
12.572 + * enumerate all of the available charsets, for example to allow user
12.573 + * charset selection. This method is not used by the {@link #forName
12.574 + * forName} method, which instead employs an efficient incremental lookup
12.575 + * algorithm.
12.576 + *
12.577 + * <p> This method may return different results at different times if new
12.578 + * charset providers are dynamically made available to the current Java
12.579 + * virtual machine. In the absence of such changes, the charsets returned
12.580 + * by this method are exactly those that can be retrieved via the {@link
12.581 + * #forName forName} method. </p>
12.582 + *
12.583 + * @return An immutable, case-insensitive map from canonical charset names
12.584 + * to charset objects
12.585 + */
12.586 + public static SortedMap<String,Charset> availableCharsets() {
12.587 + return AccessController.doPrivileged(
12.588 + new PrivilegedAction<SortedMap<String,Charset>>() {
12.589 + public SortedMap<String,Charset> run() {
12.590 + TreeMap<String,Charset> m =
12.591 + new TreeMap<String,Charset>(
12.592 + ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
12.593 + put(standardProvider.charsets(), m);
12.594 + for (Iterator i = providers(); i.hasNext();) {
12.595 + CharsetProvider cp = (CharsetProvider)i.next();
12.596 + put(cp.charsets(), m);
12.597 + }
12.598 + return Collections.unmodifiableSortedMap(m);
12.599 + }
12.600 + });
12.601 + }
12.602 +
12.603 + private static volatile Charset defaultCharset;
12.604 +
12.605 + /**
12.606 + * Returns the default charset of this Java virtual machine.
12.607 + *
12.608 + * <p> The default charset is determined during virtual-machine startup and
12.609 + * typically depends upon the locale and charset of the underlying
12.610 + * operating system.
12.611 + *
12.612 + * @return A charset object for the default charset
12.613 + *
12.614 + * @since 1.5
12.615 + */
12.616 + public static Charset defaultCharset() {
12.617 + if (defaultCharset == null) {
12.618 + synchronized (Charset.class) {
12.619 + String csn = AccessController.doPrivileged(
12.620 + new GetPropertyAction("file.encoding"));
12.621 + Charset cs = lookup(csn);
12.622 + if (cs != null)
12.623 + defaultCharset = cs;
12.624 + else
12.625 + defaultCharset = forName("UTF-8");
12.626 + }
12.627 + }
12.628 + return defaultCharset;
12.629 + }
12.630 +
12.631 +
12.632 + /* -- Instance fields and methods -- */
12.633 +
12.634 + private final String name; // tickles a bug in oldjavac
12.635 + private final String[] aliases; // tickles a bug in oldjavac
12.636 + private Set<String> aliasSet = null;
12.637 +
12.638 + /**
12.639 + * Initializes a new charset with the given canonical name and alias
12.640 + * set. </p>
12.641 + *
12.642 + * @param canonicalName
12.643 + * The canonical name of this charset
12.644 + *
12.645 + * @param aliases
12.646 + * An array of this charset's aliases, or null if it has no aliases
12.647 + *
12.648 + * @throws IllegalCharsetNameException
12.649 + * If the canonical name or any of the aliases are illegal
12.650 + */
12.651 + protected Charset(String canonicalName, String[] aliases) {
12.652 + checkName(canonicalName);
12.653 + String[] as = (aliases == null) ? new String[0] : aliases;
12.654 + for (int i = 0; i < as.length; i++)
12.655 + checkName(as[i]);
12.656 + this.name = canonicalName;
12.657 + this.aliases = as;
12.658 + }
12.659 +
12.660 + /**
12.661 + * Returns this charset's canonical name. </p>
12.662 + *
12.663 + * @return The canonical name of this charset
12.664 + */
12.665 + public final String name() {
12.666 + return name;
12.667 + }
12.668 +
12.669 + /**
12.670 + * Returns a set containing this charset's aliases. </p>
12.671 + *
12.672 + * @return An immutable set of this charset's aliases
12.673 + */
12.674 + public final Set<String> aliases() {
12.675 + if (aliasSet != null)
12.676 + return aliasSet;
12.677 + int n = aliases.length;
12.678 + HashSet<String> hs = new HashSet<String>(n);
12.679 + for (int i = 0; i < n; i++)
12.680 + hs.add(aliases[i]);
12.681 + aliasSet = Collections.unmodifiableSet(hs);
12.682 + return aliasSet;
12.683 + }
12.684 +
12.685 + /**
12.686 + * Returns this charset's human-readable name for the default locale.
12.687 + *
12.688 + * <p> The default implementation of this method simply returns this
12.689 + * charset's canonical name. Concrete subclasses of this class may
12.690 + * override this method in order to provide a localized display name. </p>
12.691 + *
12.692 + * @return The display name of this charset in the default locale
12.693 + */
12.694 + public String displayName() {
12.695 + return name;
12.696 + }
12.697 +
12.698 + /**
12.699 + * Tells whether or not this charset is registered in the <a
12.700 + * href="http://www.iana.org/assignments/character-sets">IANA Charset
12.701 + * Registry</a>. </p>
12.702 + *
12.703 + * @return <tt>true</tt> if, and only if, this charset is known by its
12.704 + * implementor to be registered with the IANA
12.705 + */
12.706 + public final boolean isRegistered() {
12.707 + return !name.startsWith("X-") && !name.startsWith("x-");
12.708 + }
12.709 +
12.710 + /**
12.711 + * Returns this charset's human-readable name for the given locale.
12.712 + *
12.713 + * <p> The default implementation of this method simply returns this
12.714 + * charset's canonical name. Concrete subclasses of this class may
12.715 + * override this method in order to provide a localized display name. </p>
12.716 + *
12.717 + * @param locale
12.718 + * The locale for which the display name is to be retrieved
12.719 + *
12.720 + * @return The display name of this charset in the given locale
12.721 + */
12.722 + public String displayName(Locale locale) {
12.723 + return name;
12.724 + }
12.725 +
12.726 + /**
12.727 + * Tells whether or not this charset contains the given charset.
12.728 + *
12.729 + * <p> A charset <i>C</i> is said to <i>contain</i> a charset <i>D</i> if,
12.730 + * and only if, every character representable in <i>D</i> is also
12.731 + * representable in <i>C</i>. If this relationship holds then it is
12.732 + * guaranteed that every string that can be encoded in <i>D</i> can also be
12.733 + * encoded in <i>C</i> without performing any replacements.
12.734 + *
12.735 + * <p> That <i>C</i> contains <i>D</i> does not imply that each character
12.736 + * representable in <i>C</i> by a particular byte sequence is represented
12.737 + * in <i>D</i> by the same byte sequence, although sometimes this is the
12.738 + * case.
12.739 + *
12.740 + * <p> Every charset contains itself.
12.741 + *
12.742 + * <p> This method computes an approximation of the containment relation:
12.743 + * If it returns <tt>true</tt> then the given charset is known to be
12.744 + * contained by this charset; if it returns <tt>false</tt>, however, then
12.745 + * it is not necessarily the case that the given charset is not contained
12.746 + * in this charset.
12.747 + *
12.748 + * @return <tt>true</tt> if the given charset is contained in this charset
12.749 + */
12.750 + public abstract boolean contains(Charset cs);
12.751 +
12.752 + /**
12.753 + * Constructs a new decoder for this charset. </p>
12.754 + *
12.755 + * @return A new decoder for this charset
12.756 + */
12.757 + public abstract CharsetDecoder newDecoder();
12.758 +
12.759 + /**
12.760 + * Constructs a new encoder for this charset. </p>
12.761 + *
12.762 + * @return A new encoder for this charset
12.763 + *
12.764 + * @throws UnsupportedOperationException
12.765 + * If this charset does not support encoding
12.766 + */
12.767 + public abstract CharsetEncoder newEncoder();
12.768 +
12.769 + /**
12.770 + * Tells whether or not this charset supports encoding.
12.771 + *
12.772 + * <p> Nearly all charsets support encoding. The primary exceptions are
12.773 + * special-purpose <i>auto-detect</i> charsets whose decoders can determine
12.774 + * which of several possible encoding schemes is in use by examining the
12.775 + * input byte sequence. Such charsets do not support encoding because
12.776 + * there is no way to determine which encoding should be used on output.
12.777 + * Implementations of such charsets should override this method to return
12.778 + * <tt>false</tt>. </p>
12.779 + *
12.780 + * @return <tt>true</tt> if, and only if, this charset supports encoding
12.781 + */
12.782 + public boolean canEncode() {
12.783 + return true;
12.784 + }
12.785 +
12.786 + /**
12.787 + * Convenience method that decodes bytes in this charset into Unicode
12.788 + * characters.
12.789 + *
12.790 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
12.791 + * same result as the expression
12.792 + *
12.793 + * <pre>
12.794 + * cs.newDecoder()
12.795 + * .onMalformedInput(CodingErrorAction.REPLACE)
12.796 + * .onUnmappableCharacter(CodingErrorAction.REPLACE)
12.797 + * .decode(bb); </pre>
12.798 + *
12.799 + * except that it is potentially more efficient because it can cache
12.800 + * decoders between successive invocations.
12.801 + *
12.802 + * <p> This method always replaces malformed-input and unmappable-character
12.803 + * sequences with this charset's default replacement byte array. In order
12.804 + * to detect such sequences, use the {@link
12.805 + * CharsetDecoder#decode(java.nio.ByteBuffer)} method directly. </p>
12.806 + *
12.807 + * @param bb The byte buffer to be decoded
12.808 + *
12.809 + * @return A char buffer containing the decoded characters
12.810 + */
12.811 + public final CharBuffer decode(ByteBuffer bb) {
12.812 + try {
12.813 + return ThreadLocalCoders.decoderFor(this)
12.814 + .onMalformedInput(CodingErrorAction.REPLACE)
12.815 + .onUnmappableCharacter(CodingErrorAction.REPLACE)
12.816 + .decode(bb);
12.817 + } catch (CharacterCodingException x) {
12.818 + throw new Error(x); // Can't happen
12.819 + }
12.820 + }
12.821 +
12.822 + /**
12.823 + * Convenience method that encodes Unicode characters into bytes in this
12.824 + * charset.
12.825 + *
12.826 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
12.827 + * same result as the expression
12.828 + *
12.829 + * <pre>
12.830 + * cs.newEncoder()
12.831 + * .onMalformedInput(CodingErrorAction.REPLACE)
12.832 + * .onUnmappableCharacter(CodingErrorAction.REPLACE)
12.833 + * .encode(bb); </pre>
12.834 + *
12.835 + * except that it is potentially more efficient because it can cache
12.836 + * encoders between successive invocations.
12.837 + *
12.838 + * <p> This method always replaces malformed-input and unmappable-character
12.839 + * sequences with this charset's default replacement string. In order to
12.840 + * detect such sequences, use the {@link
12.841 + * CharsetEncoder#encode(java.nio.CharBuffer)} method directly. </p>
12.842 + *
12.843 + * @param cb The char buffer to be encoded
12.844 + *
12.845 + * @return A byte buffer containing the encoded characters
12.846 + */
12.847 + public final ByteBuffer encode(CharBuffer cb) {
12.848 + try {
12.849 + return ThreadLocalCoders.encoderFor(this)
12.850 + .onMalformedInput(CodingErrorAction.REPLACE)
12.851 + .onUnmappableCharacter(CodingErrorAction.REPLACE)
12.852 + .encode(cb);
12.853 + } catch (CharacterCodingException x) {
12.854 + throw new Error(x); // Can't happen
12.855 + }
12.856 + }
12.857 +
12.858 + /**
12.859 + * Convenience method that encodes a string into bytes in this charset.
12.860 + *
12.861 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
12.862 + * same result as the expression
12.863 + *
12.864 + * <pre>
12.865 + * cs.encode(CharBuffer.wrap(s)); </pre>
12.866 + *
12.867 + * @param str The string to be encoded
12.868 + *
12.869 + * @return A byte buffer containing the encoded characters
12.870 + */
12.871 + public final ByteBuffer encode(String str) {
12.872 + return encode(CharBuffer.wrap(str));
12.873 + }
12.874 +
12.875 + /**
12.876 + * Compares this charset to another.
12.877 + *
12.878 + * <p> Charsets are ordered by their canonical names, without regard to
12.879 + * case. </p>
12.880 + *
12.881 + * @param that
12.882 + * The charset to which this charset is to be compared
12.883 + *
12.884 + * @return A negative integer, zero, or a positive integer as this charset
12.885 + * is less than, equal to, or greater than the specified charset
12.886 + */
12.887 + public final int compareTo(Charset that) {
12.888 + return (name().compareToIgnoreCase(that.name()));
12.889 + }
12.890 +
12.891 + /**
12.892 + * Computes a hashcode for this charset. </p>
12.893 + *
12.894 + * @return An integer hashcode
12.895 + */
12.896 + public final int hashCode() {
12.897 + return name().hashCode();
12.898 + }
12.899 +
12.900 + /**
12.901 + * Tells whether or not this object is equal to another.
12.902 + *
12.903 + * <p> Two charsets are equal if, and only if, they have the same canonical
12.904 + * names. A charset is never equal to any other type of object. </p>
12.905 + *
12.906 + * @return <tt>true</tt> if, and only if, this charset is equal to the
12.907 + * given object
12.908 + */
12.909 + public final boolean equals(Object ob) {
12.910 + if (!(ob instanceof Charset))
12.911 + return false;
12.912 + if (this == ob)
12.913 + return true;
12.914 + return name.equals(((Charset)ob).name());
12.915 + }
12.916 +
12.917 + /**
12.918 + * Returns a string describing this charset. </p>
12.919 + *
12.920 + * @return A string describing this charset
12.921 + */
12.922 + public final String toString() {
12.923 + return name();
12.924 + }
12.925 +
12.926 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetDecoder.java Thu Oct 03 15:43:10 2013 +0200
13.3 @@ -0,0 +1,972 @@
13.4 +/*
13.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
13.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
13.7 + *
13.8 + *
13.9 + *
13.10 + *
13.11 + *
13.12 + *
13.13 + *
13.14 + *
13.15 + *
13.16 + *
13.17 + *
13.18 + *
13.19 + *
13.20 + *
13.21 + *
13.22 + *
13.23 + *
13.24 + *
13.25 + *
13.26 + *
13.27 + */
13.28 +
13.29 +// -- This file was mechanically generated: Do not edit! -- //
13.30 +
13.31 +package java.nio.charset;
13.32 +
13.33 +import java.nio.Buffer;
13.34 +import java.nio.ByteBuffer;
13.35 +import java.nio.CharBuffer;
13.36 +import java.nio.BufferOverflowException;
13.37 +import java.nio.BufferUnderflowException;
13.38 +import java.lang.ref.WeakReference;
13.39 +import java.nio.charset.CoderMalfunctionError; // javadoc
13.40 +
13.41 +
13.42 +/**
13.43 + * An engine that can transform a sequence of bytes in a specific charset into a sequence of
13.44 + * sixteen-bit Unicode characters.
13.45 + *
13.46 + * <a name="steps">
13.47 + *
13.48 + * <p> The input byte sequence is provided in a byte buffer or a series
13.49 + * of such buffers. The output character sequence is written to a character buffer
13.50 + * or a series of such buffers. A decoder should always be used by making
13.51 + * the following sequence of method invocations, hereinafter referred to as a
13.52 + * <i>decoding operation</i>:
13.53 + *
13.54 + * <ol>
13.55 + *
13.56 + * <li><p> Reset the decoder via the {@link #reset reset} method, unless it
13.57 + * has not been used before; </p></li>
13.58 + *
13.59 + * <li><p> Invoke the {@link #decode decode} method zero or more times, as
13.60 + * long as additional input may be available, passing <tt>false</tt> for the
13.61 + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
13.62 + * output buffer between invocations; </p></li>
13.63 + *
13.64 + * <li><p> Invoke the {@link #decode decode} method one final time, passing
13.65 + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
13.66 + *
13.67 + * <li><p> Invoke the {@link #flush flush} method so that the decoder can
13.68 + * flush any internal state to the output buffer. </p></li>
13.69 + *
13.70 + * </ol>
13.71 + *
13.72 + * Each invocation of the {@link #decode decode} method will decode as many
13.73 + * bytes as possible from the input buffer, writing the resulting characters
13.74 + * to the output buffer. The {@link #decode decode} method returns when more
13.75 + * input is required, when there is not enough room in the output buffer, or
13.76 + * when a decoding error has occurred. In each case a {@link CoderResult}
13.77 + * object is returned to describe the reason for termination. An invoker can
13.78 + * examine this object and fill the input buffer, flush the output buffer, or
13.79 + * attempt to recover from a decoding error, as appropriate, and try again.
13.80 + *
13.81 + * <a name="ce">
13.82 + *
13.83 + * <p> There are two general types of decoding errors. If the input byte
13.84 + * sequence is not legal for this charset then the input is considered <i>malformed</i>. If
13.85 + * the input byte sequence is legal but cannot be mapped to a valid
13.86 + * Unicode character then an <i>unmappable character</i> has been encountered.
13.87 + *
13.88 + * <a name="cae">
13.89 + *
13.90 + * <p> How a decoding error is handled depends upon the action requested for
13.91 + * that type of error, which is described by an instance of the {@link
13.92 + * CodingErrorAction} class. The possible error actions are to {@link
13.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
13.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
13.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
13.96 + * </code>replace<code>} the erroneous input with the current value of the
13.97 + * replacement string. The replacement
13.98 + *
13.99 +
13.100 +
13.101 +
13.102 +
13.103 +
13.104 + * has the initial value <tt>"\uFFFD"</tt>;
13.105 +
13.106 + *
13.107 + * its value may be changed via the {@link #replaceWith(java.lang.String)
13.108 + * replaceWith} method.
13.109 + *
13.110 + * <p> The default action for malformed-input and unmappable-character errors
13.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
13.112 + * malformed-input error action may be changed via the {@link
13.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
13.114 + * unmappable-character action may be changed via the {@link
13.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
13.116 + *
13.117 + * <p> This class is designed to handle many of the details of the decoding
13.118 + * process, including the implementation of error actions. A decoder for a
13.119 + * specific charset, which is a concrete subclass of this class, need only
13.120 + * implement the abstract {@link #decodeLoop decodeLoop} method, which
13.121 + * encapsulates the basic decoding loop. A subclass that maintains internal
13.122 + * state should, additionally, override the {@link #implFlush implFlush} and
13.123 + * {@link #implReset implReset} methods.
13.124 + *
13.125 + * <p> Instances of this class are not safe for use by multiple concurrent
13.126 + * threads. </p>
13.127 + *
13.128 + *
13.129 + * @author Mark Reinhold
13.130 + * @author JSR-51 Expert Group
13.131 + * @since 1.4
13.132 + *
13.133 + * @see ByteBuffer
13.134 + * @see CharBuffer
13.135 + * @see Charset
13.136 + * @see CharsetEncoder
13.137 + */
13.138 +
13.139 +public abstract class CharsetDecoder {
13.140 +
13.141 + private final Charset charset;
13.142 + private final float averageCharsPerByte;
13.143 + private final float maxCharsPerByte;
13.144 +
13.145 + private String replacement;
13.146 + private CodingErrorAction malformedInputAction
13.147 + = CodingErrorAction.REPORT;
13.148 + private CodingErrorAction unmappableCharacterAction
13.149 + = CodingErrorAction.REPORT;
13.150 +
13.151 + // Internal states
13.152 + //
13.153 + private static final int ST_RESET = 0;
13.154 + private static final int ST_CODING = 1;
13.155 + private static final int ST_END = 2;
13.156 + private static final int ST_FLUSHED = 3;
13.157 +
13.158 + private int state = ST_RESET;
13.159 +
13.160 + private static String stateNames[]
13.161 + = { "RESET", "CODING", "CODING_END", "FLUSHED" };
13.162 +
13.163 +
13.164 + /**
13.165 + * Initializes a new decoder. The new decoder will have the given
13.166 + * chars-per-byte and replacement values. </p>
13.167 + *
13.168 + * @param averageCharsPerByte
13.169 + * A positive float value indicating the expected number of
13.170 + * characters that will be produced for each input byte
13.171 + *
13.172 + * @param maxCharsPerByte
13.173 + * A positive float value indicating the maximum number of
13.174 + * characters that will be produced for each input byte
13.175 + *
13.176 + * @param replacement
13.177 + * The initial replacement; must not be <tt>null</tt>, must have
13.178 + * non-zero length, must not be longer than maxCharsPerByte,
13.179 + * and must be {@link #isLegalReplacement </code>legal<code>}
13.180 + *
13.181 + * @throws IllegalArgumentException
13.182 + * If the preconditions on the parameters do not hold
13.183 + */
13.184 + private
13.185 + CharsetDecoder(Charset cs,
13.186 + float averageCharsPerByte,
13.187 + float maxCharsPerByte,
13.188 + String replacement)
13.189 + {
13.190 + this.charset = cs;
13.191 + if (averageCharsPerByte <= 0.0f)
13.192 + throw new IllegalArgumentException("Non-positive "
13.193 + + "averageCharsPerByte");
13.194 + if (maxCharsPerByte <= 0.0f)
13.195 + throw new IllegalArgumentException("Non-positive "
13.196 + + "maxCharsPerByte");
13.197 + if (!Charset.atBugLevel("1.4")) {
13.198 + if (averageCharsPerByte > maxCharsPerByte)
13.199 + throw new IllegalArgumentException("averageCharsPerByte"
13.200 + + " exceeds "
13.201 + + "maxCharsPerByte");
13.202 + }
13.203 + this.replacement = replacement;
13.204 + this.averageCharsPerByte = averageCharsPerByte;
13.205 + this.maxCharsPerByte = maxCharsPerByte;
13.206 + replaceWith(replacement);
13.207 + }
13.208 +
13.209 + /**
13.210 + * Initializes a new decoder. The new decoder will have the given
13.211 + * chars-per-byte values and its replacement will be the
13.212 + * string <tt>"\uFFFD"</tt>. </p>
13.213 + *
13.214 + * @param averageCharsPerByte
13.215 + * A positive float value indicating the expected number of
13.216 + * characters that will be produced for each input byte
13.217 + *
13.218 + * @param maxCharsPerByte
13.219 + * A positive float value indicating the maximum number of
13.220 + * characters that will be produced for each input byte
13.221 + *
13.222 + * @throws IllegalArgumentException
13.223 + * If the preconditions on the parameters do not hold
13.224 + */
13.225 + protected CharsetDecoder(Charset cs,
13.226 + float averageCharsPerByte,
13.227 + float maxCharsPerByte)
13.228 + {
13.229 + this(cs,
13.230 + averageCharsPerByte, maxCharsPerByte,
13.231 + "\uFFFD");
13.232 + }
13.233 +
13.234 + /**
13.235 + * Returns the charset that created this decoder. </p>
13.236 + *
13.237 + * @return This decoder's charset
13.238 + */
13.239 + public final Charset charset() {
13.240 + return charset;
13.241 + }
13.242 +
13.243 + /**
13.244 + * Returns this decoder's replacement value. </p>
13.245 + *
13.246 + * @return This decoder's current replacement,
13.247 + * which is never <tt>null</tt> and is never empty
13.248 + */
13.249 + public final String replacement() {
13.250 + return replacement;
13.251 + }
13.252 +
13.253 + /**
13.254 + * Changes this decoder's replacement value.
13.255 + *
13.256 + * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
13.257 + * method, passing the new replacement, after checking that the new
13.258 + * replacement is acceptable. </p>
13.259 + *
13.260 + * @param newReplacement
13.261 + *
13.262 +
13.263 + * The new replacement; must not be <tt>null</tt>
13.264 + * and must have non-zero length
13.265 +
13.266 +
13.267 +
13.268 +
13.269 +
13.270 +
13.271 +
13.272 + *
13.273 + * @return This decoder
13.274 + *
13.275 + * @throws IllegalArgumentException
13.276 + * If the preconditions on the parameter do not hold
13.277 + */
13.278 + public final CharsetDecoder replaceWith(String newReplacement) {
13.279 + if (newReplacement == null)
13.280 + throw new IllegalArgumentException("Null replacement");
13.281 + int len = newReplacement.length();
13.282 + if (len == 0)
13.283 + throw new IllegalArgumentException("Empty replacement");
13.284 + if (len > maxCharsPerByte)
13.285 + throw new IllegalArgumentException("Replacement too long");
13.286 +
13.287 +
13.288 +
13.289 +
13.290 + this.replacement = newReplacement;
13.291 + implReplaceWith(newReplacement);
13.292 + return this;
13.293 + }
13.294 +
13.295 + /**
13.296 + * Reports a change to this decoder's replacement value.
13.297 + *
13.298 + * <p> The default implementation of this method does nothing. This method
13.299 + * should be overridden by decoders that require notification of changes to
13.300 + * the replacement. </p>
13.301 + *
13.302 + * @param newReplacement
13.303 + */
13.304 + protected void implReplaceWith(String newReplacement) {
13.305 + }
13.306 +
13.307 +
13.308 +
13.309 +
13.310 +
13.311 +
13.312 +
13.313 +
13.314 +
13.315 +
13.316 +
13.317 +
13.318 +
13.319 +
13.320 +
13.321 +
13.322 +
13.323 +
13.324 +
13.325 +
13.326 +
13.327 +
13.328 +
13.329 +
13.330 +
13.331 +
13.332 +
13.333 +
13.334 +
13.335 +
13.336 +
13.337 +
13.338 +
13.339 +
13.340 +
13.341 +
13.342 +
13.343 +
13.344 +
13.345 +
13.346 +
13.347 + /**
13.348 + * Returns this decoder's current action for malformed-input errors. </p>
13.349 + *
13.350 + * @return The current malformed-input action, which is never <tt>null</tt>
13.351 + */
13.352 + public CodingErrorAction malformedInputAction() {
13.353 + return malformedInputAction;
13.354 + }
13.355 +
13.356 + /**
13.357 + * Changes this decoder's action for malformed-input errors. </p>
13.358 + *
13.359 + * <p> This method invokes the {@link #implOnMalformedInput
13.360 + * implOnMalformedInput} method, passing the new action. </p>
13.361 + *
13.362 + * @param newAction The new action; must not be <tt>null</tt>
13.363 + *
13.364 + * @return This decoder
13.365 + *
13.366 + * @throws IllegalArgumentException
13.367 + * If the precondition on the parameter does not hold
13.368 + */
13.369 + public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
13.370 + if (newAction == null)
13.371 + throw new IllegalArgumentException("Null action");
13.372 + malformedInputAction = newAction;
13.373 + implOnMalformedInput(newAction);
13.374 + return this;
13.375 + }
13.376 +
13.377 + /**
13.378 + * Reports a change to this decoder's malformed-input action.
13.379 + *
13.380 + * <p> The default implementation of this method does nothing. This method
13.381 + * should be overridden by decoders that require notification of changes to
13.382 + * the malformed-input action. </p>
13.383 + */
13.384 + protected void implOnMalformedInput(CodingErrorAction newAction) { }
13.385 +
13.386 + /**
13.387 + * Returns this decoder's current action for unmappable-character errors.
13.388 + * </p>
13.389 + *
13.390 + * @return The current unmappable-character action, which is never
13.391 + * <tt>null</tt>
13.392 + */
13.393 + public CodingErrorAction unmappableCharacterAction() {
13.394 + return unmappableCharacterAction;
13.395 + }
13.396 +
13.397 + /**
13.398 + * Changes this decoder's action for unmappable-character errors.
13.399 + *
13.400 + * <p> This method invokes the {@link #implOnUnmappableCharacter
13.401 + * implOnUnmappableCharacter} method, passing the new action. </p>
13.402 + *
13.403 + * @param newAction The new action; must not be <tt>null</tt>
13.404 + *
13.405 + * @return This decoder
13.406 + *
13.407 + * @throws IllegalArgumentException
13.408 + * If the precondition on the parameter does not hold
13.409 + */
13.410 + public final CharsetDecoder onUnmappableCharacter(CodingErrorAction
13.411 + newAction)
13.412 + {
13.413 + if (newAction == null)
13.414 + throw new IllegalArgumentException("Null action");
13.415 + unmappableCharacterAction = newAction;
13.416 + implOnUnmappableCharacter(newAction);
13.417 + return this;
13.418 + }
13.419 +
13.420 + /**
13.421 + * Reports a change to this decoder's unmappable-character action.
13.422 + *
13.423 + * <p> The default implementation of this method does nothing. This method
13.424 + * should be overridden by decoders that require notification of changes to
13.425 + * the unmappable-character action. </p>
13.426 + */
13.427 + protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
13.428 +
13.429 + /**
13.430 + * Returns the average number of characters that will be produced for each
13.431 + * byte of input. This heuristic value may be used to estimate the size
13.432 + * of the output buffer required for a given input sequence. </p>
13.433 + *
13.434 + * @return The average number of characters produced
13.435 + * per byte of input
13.436 + */
13.437 + public final float averageCharsPerByte() {
13.438 + return averageCharsPerByte;
13.439 + }
13.440 +
13.441 + /**
13.442 + * Returns the maximum number of characters that will be produced for each
13.443 + * byte of input. This value may be used to compute the worst-case size
13.444 + * of the output buffer required for a given input sequence. </p>
13.445 + *
13.446 + * @return The maximum number of characters that will be produced per
13.447 + * byte of input
13.448 + */
13.449 + public final float maxCharsPerByte() {
13.450 + return maxCharsPerByte;
13.451 + }
13.452 +
13.453 + /**
13.454 + * Decodes as many bytes as possible from the given input buffer,
13.455 + * writing the results to the given output buffer.
13.456 + *
13.457 + * <p> The buffers are read from, and written to, starting at their current
13.458 + * positions. At most {@link Buffer#remaining in.remaining()} bytes
13.459 + * will be read and at most {@link Buffer#remaining out.remaining()}
13.460 + * characters will be written. The buffers' positions will be advanced to
13.461 + * reflect the bytes read and the characters written, but their marks and
13.462 + * limits will not be modified.
13.463 + *
13.464 + * <p> In addition to reading bytes from the input buffer and writing
13.465 + * characters to the output buffer, this method returns a {@link CoderResult}
13.466 + * object to describe its reason for termination:
13.467 + *
13.468 + * <ul>
13.469 + *
13.470 + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
13.471 + * input buffer as possible has been decoded. If there is no further
13.472 + * input then the invoker can proceed to the next step of the
13.473 + * <a href="#steps">decoding operation</a>. Otherwise this method
13.474 + * should be invoked again with further input. </p></li>
13.475 + *
13.476 + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is
13.477 + * insufficient space in the output buffer to decode any more bytes.
13.478 + * This method should be invoked again with an output buffer that has
13.479 + * more {@linkplain Buffer#remaining remaining} characters. This is
13.480 + * typically done by draining any decoded characters from the output
13.481 + * buffer. </p></li>
13.482 + *
13.483 + * <li><p> A {@link CoderResult#malformedForLength
13.484 + * </code>malformed-input<code>} result indicates that a malformed-input
13.485 + * error has been detected. The malformed bytes begin at the input
13.486 + * buffer's (possibly incremented) position; the number of malformed
13.487 + * bytes may be determined by invoking the result object's {@link
13.488 + * CoderResult#length() length} method. This case applies only if the
13.489 + * {@link #onMalformedInput </code>malformed action<code>} of this decoder
13.490 + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
13.491 + * will be ignored or replaced, as requested. </p></li>
13.492 + *
13.493 + * <li><p> An {@link CoderResult#unmappableForLength
13.494 + * </code>unmappable-character<code>} result indicates that an
13.495 + * unmappable-character error has been detected. The bytes that
13.496 + * decode the unmappable character begin at the input buffer's (possibly
13.497 + * incremented) position; the number of such bytes may be determined
13.498 + * by invoking the result object's {@link CoderResult#length() length}
13.499 + * method. This case applies only if the {@link #onUnmappableCharacter
13.500 + * </code>unmappable action<code>} of this decoder is {@link
13.501 + * CodingErrorAction#REPORT}; otherwise the unmappable character will be
13.502 + * ignored or replaced, as requested. </p></li>
13.503 + *
13.504 + * </ul>
13.505 + *
13.506 + * In any case, if this method is to be reinvoked in the same decoding
13.507 + * operation then care should be taken to preserve any bytes remaining
13.508 + * in the input buffer so that they are available to the next invocation.
13.509 + *
13.510 + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
13.511 + * the invoker can provide further input beyond that contained in the given
13.512 + * input buffer. If there is a possibility of providing additional input
13.513 + * then the invoker should pass <tt>false</tt> for this parameter; if there
13.514 + * is no possibility of providing further input then the invoker should
13.515 + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
13.516 + * common, to pass <tt>false</tt> in one invocation and later discover that
13.517 + * no further input was actually available. It is critical, however, that
13.518 + * the final invocation of this method in a sequence of invocations always
13.519 + * pass <tt>true</tt> so that any remaining undecoded input will be treated
13.520 + * as being malformed.
13.521 + *
13.522 + * <p> This method works by invoking the {@link #decodeLoop decodeLoop}
13.523 + * method, interpreting its results, handling error conditions, and
13.524 + * reinvoking it as necessary. </p>
13.525 + *
13.526 + *
13.527 + * @param in
13.528 + * The input byte buffer
13.529 + *
13.530 + * @param out
13.531 + * The output character buffer
13.532 + *
13.533 + * @param endOfInput
13.534 + * <tt>true</tt> if, and only if, the invoker can provide no
13.535 + * additional input bytes beyond those in the given buffer
13.536 + *
13.537 + * @return A coder-result object describing the reason for termination
13.538 + *
13.539 + * @throws IllegalStateException
13.540 + * If a decoding operation is already in progress and the previous
13.541 + * step was an invocation neither of the {@link #reset reset}
13.542 + * method, nor of this method with a value of <tt>false</tt> for
13.543 + * the <tt>endOfInput</tt> parameter, nor of this method with a
13.544 + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
13.545 + * but a return value indicating an incomplete decoding operation
13.546 + *
13.547 + * @throws CoderMalfunctionError
13.548 + * If an invocation of the decodeLoop method threw
13.549 + * an unexpected exception
13.550 + */
13.551 + public final CoderResult decode(ByteBuffer in, CharBuffer out,
13.552 + boolean endOfInput)
13.553 + {
13.554 + int newState = endOfInput ? ST_END : ST_CODING;
13.555 + if ((state != ST_RESET) && (state != ST_CODING)
13.556 + && !(endOfInput && (state == ST_END)))
13.557 + throwIllegalStateException(state, newState);
13.558 + state = newState;
13.559 +
13.560 + for (;;) {
13.561 +
13.562 + CoderResult cr;
13.563 + try {
13.564 + cr = decodeLoop(in, out);
13.565 + } catch (BufferUnderflowException x) {
13.566 + throw new CoderMalfunctionError(x);
13.567 + } catch (BufferOverflowException x) {
13.568 + throw new CoderMalfunctionError(x);
13.569 + }
13.570 +
13.571 + if (cr.isOverflow())
13.572 + return cr;
13.573 +
13.574 + if (cr.isUnderflow()) {
13.575 + if (endOfInput && in.hasRemaining()) {
13.576 + cr = CoderResult.malformedForLength(in.remaining());
13.577 + // Fall through to malformed-input case
13.578 + } else {
13.579 + return cr;
13.580 + }
13.581 + }
13.582 +
13.583 + CodingErrorAction action = null;
13.584 + if (cr.isMalformed())
13.585 + action = malformedInputAction;
13.586 + else if (cr.isUnmappable())
13.587 + action = unmappableCharacterAction;
13.588 + else
13.589 + assert false : cr.toString();
13.590 +
13.591 + if (action == CodingErrorAction.REPORT)
13.592 + return cr;
13.593 +
13.594 + if (action == CodingErrorAction.REPLACE) {
13.595 + if (out.remaining() < replacement.length())
13.596 + return CoderResult.OVERFLOW;
13.597 + out.put(replacement);
13.598 + }
13.599 +
13.600 + if ((action == CodingErrorAction.IGNORE)
13.601 + || (action == CodingErrorAction.REPLACE)) {
13.602 + // Skip erroneous input either way
13.603 + in.position(in.position() + cr.length());
13.604 + continue;
13.605 + }
13.606 +
13.607 + assert false;
13.608 + }
13.609 +
13.610 + }
13.611 +
13.612 + /**
13.613 + * Flushes this decoder.
13.614 + *
13.615 + * <p> Some decoders maintain internal state and may need to write some
13.616 + * final characters to the output buffer once the overall input sequence has
13.617 + * been read.
13.618 + *
13.619 + * <p> Any additional output is written to the output buffer beginning at
13.620 + * its current position. At most {@link Buffer#remaining out.remaining()}
13.621 + * characters will be written. The buffer's position will be advanced
13.622 + * appropriately, but its mark and limit will not be modified.
13.623 + *
13.624 + * <p> If this method completes successfully then it returns {@link
13.625 + * CoderResult#UNDERFLOW}. If there is insufficient room in the output
13.626 + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
13.627 + * then this method must be invoked again, with an output buffer that has
13.628 + * more room, in order to complete the current <a href="#steps">decoding
13.629 + * operation</a>.
13.630 + *
13.631 + * <p> If this decoder has already been flushed then invoking this method
13.632 + * has no effect.
13.633 + *
13.634 + * <p> This method invokes the {@link #implFlush implFlush} method to
13.635 + * perform the actual flushing operation. </p>
13.636 + *
13.637 + * @param out
13.638 + * The output character buffer
13.639 + *
13.640 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
13.641 + * {@link CoderResult#OVERFLOW}
13.642 + *
13.643 + * @throws IllegalStateException
13.644 + * If the previous step of the current decoding operation was an
13.645 + * invocation neither of the {@link #flush flush} method nor of
13.646 + * the three-argument {@link
13.647 + * #decode(ByteBuffer,CharBuffer,boolean) decode} method
13.648 + * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
13.649 + * parameter
13.650 + */
13.651 + public final CoderResult flush(CharBuffer out) {
13.652 + if (state == ST_END) {
13.653 + CoderResult cr = implFlush(out);
13.654 + if (cr.isUnderflow())
13.655 + state = ST_FLUSHED;
13.656 + return cr;
13.657 + }
13.658 +
13.659 + if (state != ST_FLUSHED)
13.660 + throwIllegalStateException(state, ST_FLUSHED);
13.661 +
13.662 + return CoderResult.UNDERFLOW; // Already flushed
13.663 + }
13.664 +
13.665 + /**
13.666 + * Flushes this decoder.
13.667 + *
13.668 + * <p> The default implementation of this method does nothing, and always
13.669 + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
13.670 + * by decoders that may need to write final characters to the output buffer
13.671 + * once the entire input sequence has been read. </p>
13.672 + *
13.673 + * @param out
13.674 + * The output character buffer
13.675 + *
13.676 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
13.677 + * {@link CoderResult#OVERFLOW}
13.678 + */
13.679 + protected CoderResult implFlush(CharBuffer out) {
13.680 + return CoderResult.UNDERFLOW;
13.681 + }
13.682 +
13.683 + /**
13.684 + * Resets this decoder, clearing any internal state.
13.685 + *
13.686 + * <p> This method resets charset-independent state and also invokes the
13.687 + * {@link #implReset() implReset} method in order to perform any
13.688 + * charset-specific reset actions. </p>
13.689 + *
13.690 + * @return This decoder
13.691 + *
13.692 + */
13.693 + public final CharsetDecoder reset() {
13.694 + implReset();
13.695 + state = ST_RESET;
13.696 + return this;
13.697 + }
13.698 +
13.699 + /**
13.700 + * Resets this decoder, clearing any charset-specific internal state.
13.701 + *
13.702 + * <p> The default implementation of this method does nothing. This method
13.703 + * should be overridden by decoders that maintain internal state. </p>
13.704 + */
13.705 + protected void implReset() { }
13.706 +
13.707 + /**
13.708 + * Decodes one or more bytes into one or more characters.
13.709 + *
13.710 + * <p> This method encapsulates the basic decoding loop, decoding as many
13.711 + * bytes as possible until it either runs out of input, runs out of room
13.712 + * in the output buffer, or encounters a decoding error. This method is
13.713 + * invoked by the {@link #decode decode} method, which handles result
13.714 + * interpretation and error recovery.
13.715 + *
13.716 + * <p> The buffers are read from, and written to, starting at their current
13.717 + * positions. At most {@link Buffer#remaining in.remaining()} bytes
13.718 + * will be read, and at most {@link Buffer#remaining out.remaining()}
13.719 + * characters will be written. The buffers' positions will be advanced to
13.720 + * reflect the bytes read and the characters written, but their marks and
13.721 + * limits will not be modified.
13.722 + *
13.723 + * <p> This method returns a {@link CoderResult} object to describe its
13.724 + * reason for termination, in the same manner as the {@link #decode decode}
13.725 + * method. Most implementations of this method will handle decoding errors
13.726 + * by returning an appropriate result object for interpretation by the
13.727 + * {@link #decode decode} method. An optimized implementation may instead
13.728 + * examine the relevant error action and implement that action itself.
13.729 + *
13.730 + * <p> An implementation of this method may perform arbitrary lookahead by
13.731 + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
13.732 + * input. </p>
13.733 + *
13.734 + * @param in
13.735 + * The input byte buffer
13.736 + *
13.737 + * @param out
13.738 + * The output character buffer
13.739 + *
13.740 + * @return A coder-result object describing the reason for termination
13.741 + */
13.742 + protected abstract CoderResult decodeLoop(ByteBuffer in,
13.743 + CharBuffer out);
13.744 +
13.745 + /**
13.746 + * Convenience method that decodes the remaining content of a single input
13.747 + * byte buffer into a newly-allocated character buffer.
13.748 + *
13.749 + * <p> This method implements an entire <a href="#steps">decoding
13.750 + * operation</a>; that is, it resets this decoder, then it decodes the
13.751 + * bytes in the given byte buffer, and finally it flushes this
13.752 + * decoder. This method should therefore not be invoked if a decoding
13.753 + * operation is already in progress. </p>
13.754 + *
13.755 + * @param in
13.756 + * The input byte buffer
13.757 + *
13.758 + * @return A newly-allocated character buffer containing the result of the
13.759 + * decoding operation. The buffer's position will be zero and its
13.760 + * limit will follow the last character written.
13.761 + *
13.762 + * @throws IllegalStateException
13.763 + * If a decoding operation is already in progress
13.764 + *
13.765 + * @throws MalformedInputException
13.766 + * If the byte sequence starting at the input buffer's current
13.767 + * position is not legal for this charset and the current malformed-input action
13.768 + * is {@link CodingErrorAction#REPORT}
13.769 + *
13.770 + * @throws UnmappableCharacterException
13.771 + * If the byte sequence starting at the input buffer's current
13.772 + * position cannot be mapped to an equivalent character sequence and
13.773 + * the current unmappable-character action is {@link
13.774 + * CodingErrorAction#REPORT}
13.775 + */
13.776 + public final CharBuffer decode(ByteBuffer in)
13.777 + throws CharacterCodingException
13.778 + {
13.779 + int n = (int)(in.remaining() * averageCharsPerByte());
13.780 + CharBuffer out = CharBuffer.allocate(n);
13.781 +
13.782 + if ((n == 0) && (in.remaining() == 0))
13.783 + return out;
13.784 + reset();
13.785 + for (;;) {
13.786 + CoderResult cr = in.hasRemaining() ?
13.787 + decode(in, out, true) : CoderResult.UNDERFLOW;
13.788 + if (cr.isUnderflow())
13.789 + cr = flush(out);
13.790 +
13.791 + if (cr.isUnderflow())
13.792 + break;
13.793 + if (cr.isOverflow()) {
13.794 + n = 2*n + 1; // Ensure progress; n might be 0!
13.795 + CharBuffer o = CharBuffer.allocate(n);
13.796 + out.flip();
13.797 + o.put(out);
13.798 + out = o;
13.799 + continue;
13.800 + }
13.801 + cr.throwException();
13.802 + }
13.803 + out.flip();
13.804 + return out;
13.805 + }
13.806 +
13.807 +
13.808 +
13.809 + /**
13.810 + * Tells whether or not this decoder implements an auto-detecting charset.
13.811 + *
13.812 + * <p> The default implementation of this method always returns
13.813 + * <tt>false</tt>; it should be overridden by auto-detecting decoders to
13.814 + * return <tt>true</tt>. </p>
13.815 + *
13.816 + * @return <tt>true</tt> if, and only if, this decoder implements an
13.817 + * auto-detecting charset
13.818 + */
13.819 + public boolean isAutoDetecting() {
13.820 + return false;
13.821 + }
13.822 +
13.823 + /**
13.824 + * Tells whether or not this decoder has yet detected a
13.825 + * charset <i>(optional operation)</i>.
13.826 + *
13.827 + * <p> If this decoder implements an auto-detecting charset then at a
13.828 + * single point during a decoding operation this method may start returning
13.829 + * <tt>true</tt> to indicate that a specific charset has been detected in
13.830 + * the input byte sequence. Once this occurs, the {@link #detectedCharset
13.831 + * detectedCharset} method may be invoked to retrieve the detected charset.
13.832 + *
13.833 + * <p> That this method returns <tt>false</tt> does not imply that no bytes
13.834 + * have yet been decoded. Some auto-detecting decoders are capable of
13.835 + * decoding some, or even all, of an input byte sequence without fixing on
13.836 + * a particular charset.
13.837 + *
13.838 + * <p> The default implementation of this method always throws an {@link
13.839 + * UnsupportedOperationException}; it should be overridden by
13.840 + * auto-detecting decoders to return <tt>true</tt> once the input charset
13.841 + * has been determined. </p>
13.842 + *
13.843 + * @return <tt>true</tt> if, and only if, this decoder has detected a
13.844 + * specific charset
13.845 + *
13.846 + * @throws UnsupportedOperationException
13.847 + * If this decoder does not implement an auto-detecting charset
13.848 + */
13.849 + public boolean isCharsetDetected() {
13.850 + throw new UnsupportedOperationException();
13.851 + }
13.852 +
13.853 + /**
13.854 + * Retrieves the charset that was detected by this
13.855 + * decoder <i>(optional operation)</i>.
13.856 + *
13.857 + * <p> If this decoder implements an auto-detecting charset then this
13.858 + * method returns the actual charset once it has been detected. After that
13.859 + * point, this method returns the same value for the duration of the
13.860 + * current decoding operation. If not enough input bytes have yet been
13.861 + * read to determine the actual charset then this method throws an {@link
13.862 + * IllegalStateException}.
13.863 + *
13.864 + * <p> The default implementation of this method always throws an {@link
13.865 + * UnsupportedOperationException}; it should be overridden by
13.866 + * auto-detecting decoders to return the appropriate value. </p>
13.867 + *
13.868 + * @return The charset detected by this auto-detecting decoder,
13.869 + * or <tt>null</tt> if the charset has not yet been determined
13.870 + *
13.871 + * @throws IllegalStateException
13.872 + * If insufficient bytes have been read to determine a charset
13.873 + *
13.874 + * @throws UnsupportedOperationException
13.875 + * If this decoder does not implement an auto-detecting charset
13.876 + */
13.877 + public Charset detectedCharset() {
13.878 + throw new UnsupportedOperationException();
13.879 + }
13.880 +
13.881 +
13.882 +
13.883 +
13.884 +
13.885 +
13.886 +
13.887 +
13.888 +
13.889 +
13.890 +
13.891 +
13.892 +
13.893 +
13.894 +
13.895 +
13.896 +
13.897 +
13.898 +
13.899 +
13.900 +
13.901 +
13.902 +
13.903 +
13.904 +
13.905 +
13.906 +
13.907 +
13.908 +
13.909 +
13.910 +
13.911 +
13.912 +
13.913 +
13.914 +
13.915 +
13.916 +
13.917 +
13.918 +
13.919 +
13.920 +
13.921 +
13.922 +
13.923 +
13.924 +
13.925 +
13.926 +
13.927 +
13.928 +
13.929 +
13.930 +
13.931 +
13.932 +
13.933 +
13.934 +
13.935 +
13.936 +
13.937 +
13.938 +
13.939 +
13.940 +
13.941 +
13.942 +
13.943 +
13.944 +
13.945 +
13.946 +
13.947 +
13.948 +
13.949 +
13.950 +
13.951 +
13.952 +
13.953 +
13.954 +
13.955 +
13.956 +
13.957 +
13.958 +
13.959 +
13.960 +
13.961 +
13.962 +
13.963 +
13.964 +
13.965 +
13.966 +
13.967 +
13.968 +
13.969 +
13.970 + private void throwIllegalStateException(int from, int to) {
13.971 + throw new IllegalStateException("Current state = " + stateNames[from]
13.972 + + ", new state = " + stateNames[to]);
13.973 + }
13.974 +
13.975 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetEncoder.java Thu Oct 03 15:43:10 2013 +0200
14.3 @@ -0,0 +1,972 @@
14.4 +/*
14.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
14.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
14.7 + *
14.8 + *
14.9 + *
14.10 + *
14.11 + *
14.12 + *
14.13 + *
14.14 + *
14.15 + *
14.16 + *
14.17 + *
14.18 + *
14.19 + *
14.20 + *
14.21 + *
14.22 + *
14.23 + *
14.24 + *
14.25 + *
14.26 + *
14.27 + */
14.28 +
14.29 +// -- This file was mechanically generated: Do not edit! -- //
14.30 +
14.31 +package java.nio.charset;
14.32 +
14.33 +import java.nio.Buffer;
14.34 +import java.nio.ByteBuffer;
14.35 +import java.nio.CharBuffer;
14.36 +import java.nio.BufferOverflowException;
14.37 +import java.nio.BufferUnderflowException;
14.38 +import java.lang.ref.WeakReference;
14.39 +import java.nio.charset.CoderMalfunctionError; // javadoc
14.40 +
14.41 +
14.42 +/**
14.43 + * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
14.44 + * bytes in a specific charset.
14.45 + *
14.46 + * <a name="steps">
14.47 + *
14.48 + * <p> The input character sequence is provided in a character buffer or a series
14.49 + * of such buffers. The output byte sequence is written to a byte buffer
14.50 + * or a series of such buffers. An encoder should always be used by making
14.51 + * the following sequence of method invocations, hereinafter referred to as an
14.52 + * <i>encoding operation</i>:
14.53 + *
14.54 + * <ol>
14.55 + *
14.56 + * <li><p> Reset the encoder via the {@link #reset reset} method, unless it
14.57 + * has not been used before; </p></li>
14.58 + *
14.59 + * <li><p> Invoke the {@link #encode encode} method zero or more times, as
14.60 + * long as additional input may be available, passing <tt>false</tt> for the
14.61 + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
14.62 + * output buffer between invocations; </p></li>
14.63 + *
14.64 + * <li><p> Invoke the {@link #encode encode} method one final time, passing
14.65 + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
14.66 + *
14.67 + * <li><p> Invoke the {@link #flush flush} method so that the encoder can
14.68 + * flush any internal state to the output buffer. </p></li>
14.69 + *
14.70 + * </ol>
14.71 + *
14.72 + * Each invocation of the {@link #encode encode} method will encode as many
14.73 + * characters as possible from the input buffer, writing the resulting bytes
14.74 + * to the output buffer. The {@link #encode encode} method returns when more
14.75 + * input is required, when there is not enough room in the output buffer, or
14.76 + * when an encoding error has occurred. In each case a {@link CoderResult}
14.77 + * object is returned to describe the reason for termination. An invoker can
14.78 + * examine this object and fill the input buffer, flush the output buffer, or
14.79 + * attempt to recover from an encoding error, as appropriate, and try again.
14.80 + *
14.81 + * <a name="ce">
14.82 + *
14.83 + * <p> There are two general types of encoding errors. If the input character
14.84 + * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>. If
14.85 + * the input character sequence is legal but cannot be mapped to a valid
14.86 + * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
14.87 + *
14.88 + * <a name="cae">
14.89 + *
14.90 + * <p> How an encoding error is handled depends upon the action requested for
14.91 + * that type of error, which is described by an instance of the {@link
14.92 + * CodingErrorAction} class. The possible error actions are to {@link
14.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
14.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
14.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
14.96 + * </code>replace<code>} the erroneous input with the current value of the
14.97 + * replacement byte array. The replacement
14.98 + *
14.99 +
14.100 + * is initially set to the encoder's default replacement, which often
14.101 + * (but not always) has the initial value <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>;
14.102 +
14.103 +
14.104 +
14.105 +
14.106 + *
14.107 + * its value may be changed via the {@link #replaceWith(byte[])
14.108 + * replaceWith} method.
14.109 + *
14.110 + * <p> The default action for malformed-input and unmappable-character errors
14.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
14.112 + * malformed-input error action may be changed via the {@link
14.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
14.114 + * unmappable-character action may be changed via the {@link
14.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
14.116 + *
14.117 + * <p> This class is designed to handle many of the details of the encoding
14.118 + * process, including the implementation of error actions. An encoder for a
14.119 + * specific charset, which is a concrete subclass of this class, need only
14.120 + * implement the abstract {@link #encodeLoop encodeLoop} method, which
14.121 + * encapsulates the basic encoding loop. A subclass that maintains internal
14.122 + * state should, additionally, override the {@link #implFlush implFlush} and
14.123 + * {@link #implReset implReset} methods.
14.124 + *
14.125 + * <p> Instances of this class are not safe for use by multiple concurrent
14.126 + * threads. </p>
14.127 + *
14.128 + *
14.129 + * @author Mark Reinhold
14.130 + * @author JSR-51 Expert Group
14.131 + * @since 1.4
14.132 + *
14.133 + * @see ByteBuffer
14.134 + * @see CharBuffer
14.135 + * @see Charset
14.136 + * @see CharsetDecoder
14.137 + */
14.138 +
14.139 +public abstract class CharsetEncoder {
14.140 +
14.141 + private final Charset charset;
14.142 + private final float averageBytesPerChar;
14.143 + private final float maxBytesPerChar;
14.144 +
14.145 + private byte[] replacement;
14.146 + private CodingErrorAction malformedInputAction
14.147 + = CodingErrorAction.REPORT;
14.148 + private CodingErrorAction unmappableCharacterAction
14.149 + = CodingErrorAction.REPORT;
14.150 +
14.151 + // Internal states
14.152 + //
14.153 + private static final int ST_RESET = 0;
14.154 + private static final int ST_CODING = 1;
14.155 + private static final int ST_END = 2;
14.156 + private static final int ST_FLUSHED = 3;
14.157 +
14.158 + private int state = ST_RESET;
14.159 +
14.160 + private static String stateNames[]
14.161 + = { "RESET", "CODING", "CODING_END", "FLUSHED" };
14.162 +
14.163 +
14.164 + /**
14.165 + * Initializes a new encoder. The new encoder will have the given
14.166 + * bytes-per-char and replacement values. </p>
14.167 + *
14.168 + * @param averageBytesPerChar
14.169 + * A positive float value indicating the expected number of
14.170 + * bytes that will be produced for each input character
14.171 + *
14.172 + * @param maxBytesPerChar
14.173 + * A positive float value indicating the maximum number of
14.174 + * bytes that will be produced for each input character
14.175 + *
14.176 + * @param replacement
14.177 + * The initial replacement; must not be <tt>null</tt>, must have
14.178 + * non-zero length, must not be longer than maxBytesPerChar,
14.179 + * and must be {@link #isLegalReplacement </code>legal<code>}
14.180 + *
14.181 + * @throws IllegalArgumentException
14.182 + * If the preconditions on the parameters do not hold
14.183 + */
14.184 + protected
14.185 + CharsetEncoder(Charset cs,
14.186 + float averageBytesPerChar,
14.187 + float maxBytesPerChar,
14.188 + byte[] replacement)
14.189 + {
14.190 + this.charset = cs;
14.191 + if (averageBytesPerChar <= 0.0f)
14.192 + throw new IllegalArgumentException("Non-positive "
14.193 + + "averageBytesPerChar");
14.194 + if (maxBytesPerChar <= 0.0f)
14.195 + throw new IllegalArgumentException("Non-positive "
14.196 + + "maxBytesPerChar");
14.197 + if (!Charset.atBugLevel("1.4")) {
14.198 + if (averageBytesPerChar > maxBytesPerChar)
14.199 + throw new IllegalArgumentException("averageBytesPerChar"
14.200 + + " exceeds "
14.201 + + "maxBytesPerChar");
14.202 + }
14.203 + this.replacement = replacement;
14.204 + this.averageBytesPerChar = averageBytesPerChar;
14.205 + this.maxBytesPerChar = maxBytesPerChar;
14.206 + replaceWith(replacement);
14.207 + }
14.208 +
14.209 + /**
14.210 + * Initializes a new encoder. The new encoder will have the given
14.211 + * bytes-per-char values and its replacement will be the
14.212 + * byte array <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>. </p>
14.213 + *
14.214 + * @param averageBytesPerChar
14.215 + * A positive float value indicating the expected number of
14.216 + * bytes that will be produced for each input character
14.217 + *
14.218 + * @param maxBytesPerChar
14.219 + * A positive float value indicating the maximum number of
14.220 + * bytes that will be produced for each input character
14.221 + *
14.222 + * @throws IllegalArgumentException
14.223 + * If the preconditions on the parameters do not hold
14.224 + */
14.225 + protected CharsetEncoder(Charset cs,
14.226 + float averageBytesPerChar,
14.227 + float maxBytesPerChar)
14.228 + {
14.229 + this(cs,
14.230 + averageBytesPerChar, maxBytesPerChar,
14.231 + new byte[] { (byte)'?' });
14.232 + }
14.233 +
14.234 + /**
14.235 + * Returns the charset that created this encoder. </p>
14.236 + *
14.237 + * @return This encoder's charset
14.238 + */
14.239 + public final Charset charset() {
14.240 + return charset;
14.241 + }
14.242 +
14.243 + /**
14.244 + * Returns this encoder's replacement value. </p>
14.245 + *
14.246 + * @return This encoder's current replacement,
14.247 + * which is never <tt>null</tt> and is never empty
14.248 + */
14.249 + public final byte[] replacement() {
14.250 + return replacement;
14.251 + }
14.252 +
14.253 + /**
14.254 + * Changes this encoder's replacement value.
14.255 + *
14.256 + * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
14.257 + * method, passing the new replacement, after checking that the new
14.258 + * replacement is acceptable. </p>
14.259 + *
14.260 + * @param newReplacement
14.261 + *
14.262 +
14.263 +
14.264 +
14.265 +
14.266 +
14.267 + * The new replacement; must not be <tt>null</tt>, must have
14.268 + * non-zero length, must not be longer than the value returned by
14.269 + * the {@link #maxBytesPerChar() maxBytesPerChar} method, and
14.270 + * must be {@link #isLegalReplacement </code>legal<code>}
14.271 +
14.272 + *
14.273 + * @return This encoder
14.274 + *
14.275 + * @throws IllegalArgumentException
14.276 + * If the preconditions on the parameter do not hold
14.277 + */
14.278 + public final CharsetEncoder replaceWith(byte[] newReplacement) {
14.279 + if (newReplacement == null)
14.280 + throw new IllegalArgumentException("Null replacement");
14.281 + int len = newReplacement.length;
14.282 + if (len == 0)
14.283 + throw new IllegalArgumentException("Empty replacement");
14.284 + if (len > maxBytesPerChar)
14.285 + throw new IllegalArgumentException("Replacement too long");
14.286 +
14.287 + if (!isLegalReplacement(newReplacement))
14.288 + throw new IllegalArgumentException("Illegal replacement");
14.289 +
14.290 + this.replacement = newReplacement;
14.291 + implReplaceWith(newReplacement);
14.292 + return this;
14.293 + }
14.294 +
14.295 + /**
14.296 + * Reports a change to this encoder's replacement value.
14.297 + *
14.298 + * <p> The default implementation of this method does nothing. This method
14.299 + * should be overridden by encoders that require notification of changes to
14.300 + * the replacement. </p>
14.301 + *
14.302 + * @param newReplacement
14.303 + */
14.304 + protected void implReplaceWith(byte[] newReplacement) {
14.305 + }
14.306 +
14.307 +
14.308 +
14.309 + private WeakReference<CharsetDecoder> cachedDecoder = null;
14.310 +
14.311 + /**
14.312 + * Tells whether or not the given byte array is a legal replacement value
14.313 + * for this encoder.
14.314 + *
14.315 + * <p> A replacement is legal if, and only if, it is a legal sequence of
14.316 + * bytes in this encoder's charset; that is, it must be possible to decode
14.317 + * the replacement into one or more sixteen-bit Unicode characters.
14.318 + *
14.319 + * <p> The default implementation of this method is not very efficient; it
14.320 + * should generally be overridden to improve performance. </p>
14.321 + *
14.322 + * @param repl The byte array to be tested
14.323 + *
14.324 + * @return <tt>true</tt> if, and only if, the given byte array
14.325 + * is a legal replacement value for this encoder
14.326 + */
14.327 + public boolean isLegalReplacement(byte[] repl) {
14.328 + WeakReference<CharsetDecoder> wr = cachedDecoder;
14.329 + CharsetDecoder dec = null;
14.330 + if ((wr == null) || ((dec = wr.get()) == null)) {
14.331 + dec = charset().newDecoder();
14.332 + dec.onMalformedInput(CodingErrorAction.REPORT);
14.333 + dec.onUnmappableCharacter(CodingErrorAction.REPORT);
14.334 + cachedDecoder = new WeakReference<CharsetDecoder>(dec);
14.335 + } else {
14.336 + dec.reset();
14.337 + }
14.338 + ByteBuffer bb = ByteBuffer.wrap(repl);
14.339 + CharBuffer cb = CharBuffer.allocate((int)(bb.remaining()
14.340 + * dec.maxCharsPerByte()));
14.341 + CoderResult cr = dec.decode(bb, cb, true);
14.342 + return !cr.isError();
14.343 + }
14.344 +
14.345 +
14.346 +
14.347 + /**
14.348 + * Returns this encoder's current action for malformed-input errors. </p>
14.349 + *
14.350 + * @return The current malformed-input action, which is never <tt>null</tt>
14.351 + */
14.352 + public CodingErrorAction malformedInputAction() {
14.353 + return malformedInputAction;
14.354 + }
14.355 +
14.356 + /**
14.357 + * Changes this encoder's action for malformed-input errors. </p>
14.358 + *
14.359 + * <p> This method invokes the {@link #implOnMalformedInput
14.360 + * implOnMalformedInput} method, passing the new action. </p>
14.361 + *
14.362 + * @param newAction The new action; must not be <tt>null</tt>
14.363 + *
14.364 + * @return This encoder
14.365 + *
14.366 + * @throws IllegalArgumentException
14.367 + * If the precondition on the parameter does not hold
14.368 + */
14.369 + public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
14.370 + if (newAction == null)
14.371 + throw new IllegalArgumentException("Null action");
14.372 + malformedInputAction = newAction;
14.373 + implOnMalformedInput(newAction);
14.374 + return this;
14.375 + }
14.376 +
14.377 + /**
14.378 + * Reports a change to this encoder's malformed-input action.
14.379 + *
14.380 + * <p> The default implementation of this method does nothing. This method
14.381 + * should be overridden by encoders that require notification of changes to
14.382 + * the malformed-input action. </p>
14.383 + */
14.384 + protected void implOnMalformedInput(CodingErrorAction newAction) { }
14.385 +
14.386 + /**
14.387 + * Returns this encoder's current action for unmappable-character errors.
14.388 + * </p>
14.389 + *
14.390 + * @return The current unmappable-character action, which is never
14.391 + * <tt>null</tt>
14.392 + */
14.393 + public CodingErrorAction unmappableCharacterAction() {
14.394 + return unmappableCharacterAction;
14.395 + }
14.396 +
14.397 + /**
14.398 + * Changes this encoder's action for unmappable-character errors.
14.399 + *
14.400 + * <p> This method invokes the {@link #implOnUnmappableCharacter
14.401 + * implOnUnmappableCharacter} method, passing the new action. </p>
14.402 + *
14.403 + * @param newAction The new action; must not be <tt>null</tt>
14.404 + *
14.405 + * @return This encoder
14.406 + *
14.407 + * @throws IllegalArgumentException
14.408 + * If the precondition on the parameter does not hold
14.409 + */
14.410 + public final CharsetEncoder onUnmappableCharacter(CodingErrorAction
14.411 + newAction)
14.412 + {
14.413 + if (newAction == null)
14.414 + throw new IllegalArgumentException("Null action");
14.415 + unmappableCharacterAction = newAction;
14.416 + implOnUnmappableCharacter(newAction);
14.417 + return this;
14.418 + }
14.419 +
14.420 + /**
14.421 + * Reports a change to this encoder's unmappable-character action.
14.422 + *
14.423 + * <p> The default implementation of this method does nothing. This method
14.424 + * should be overridden by encoders that require notification of changes to
14.425 + * the unmappable-character action. </p>
14.426 + */
14.427 + protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
14.428 +
14.429 + /**
14.430 + * Returns the average number of bytes that will be produced for each
14.431 + * character of input. This heuristic value may be used to estimate the size
14.432 + * of the output buffer required for a given input sequence. </p>
14.433 + *
14.434 + * @return The average number of bytes produced
14.435 + * per character of input
14.436 + */
14.437 + public final float averageBytesPerChar() {
14.438 + return averageBytesPerChar;
14.439 + }
14.440 +
14.441 + /**
14.442 + * Returns the maximum number of bytes that will be produced for each
14.443 + * character of input. This value may be used to compute the worst-case size
14.444 + * of the output buffer required for a given input sequence. </p>
14.445 + *
14.446 + * @return The maximum number of bytes that will be produced per
14.447 + * character of input
14.448 + */
14.449 + public final float maxBytesPerChar() {
14.450 + return maxBytesPerChar;
14.451 + }
14.452 +
14.453 + /**
14.454 + * Encodes as many characters as possible from the given input buffer,
14.455 + * writing the results to the given output buffer.
14.456 + *
14.457 + * <p> The buffers are read from, and written to, starting at their current
14.458 + * positions. At most {@link Buffer#remaining in.remaining()} characters
14.459 + * will be read and at most {@link Buffer#remaining out.remaining()}
14.460 + * bytes will be written. The buffers' positions will be advanced to
14.461 + * reflect the characters read and the bytes written, but their marks and
14.462 + * limits will not be modified.
14.463 + *
14.464 + * <p> In addition to reading characters from the input buffer and writing
14.465 + * bytes to the output buffer, this method returns a {@link CoderResult}
14.466 + * object to describe its reason for termination:
14.467 + *
14.468 + * <ul>
14.469 + *
14.470 + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
14.471 + * input buffer as possible has been encoded. If there is no further
14.472 + * input then the invoker can proceed to the next step of the
14.473 + * <a href="#steps">encoding operation</a>. Otherwise this method
14.474 + * should be invoked again with further input. </p></li>
14.475 + *
14.476 + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is
14.477 + * insufficient space in the output buffer to encode any more characters.
14.478 + * This method should be invoked again with an output buffer that has
14.479 + * more {@linkplain Buffer#remaining remaining} bytes. This is
14.480 + * typically done by draining any encoded bytes from the output
14.481 + * buffer. </p></li>
14.482 + *
14.483 + * <li><p> A {@link CoderResult#malformedForLength
14.484 + * </code>malformed-input<code>} result indicates that a malformed-input
14.485 + * error has been detected. The malformed characters begin at the input
14.486 + * buffer's (possibly incremented) position; the number of malformed
14.487 + * characters may be determined by invoking the result object's {@link
14.488 + * CoderResult#length() length} method. This case applies only if the
14.489 + * {@link #onMalformedInput </code>malformed action<code>} of this encoder
14.490 + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
14.491 + * will be ignored or replaced, as requested. </p></li>
14.492 + *
14.493 + * <li><p> An {@link CoderResult#unmappableForLength
14.494 + * </code>unmappable-character<code>} result indicates that an
14.495 + * unmappable-character error has been detected. The characters that
14.496 + * encode the unmappable character begin at the input buffer's (possibly
14.497 + * incremented) position; the number of such characters may be determined
14.498 + * by invoking the result object's {@link CoderResult#length() length}
14.499 + * method. This case applies only if the {@link #onUnmappableCharacter
14.500 + * </code>unmappable action<code>} of this encoder is {@link
14.501 + * CodingErrorAction#REPORT}; otherwise the unmappable character will be
14.502 + * ignored or replaced, as requested. </p></li>
14.503 + *
14.504 + * </ul>
14.505 + *
14.506 + * In any case, if this method is to be reinvoked in the same encoding
14.507 + * operation then care should be taken to preserve any characters remaining
14.508 + * in the input buffer so that they are available to the next invocation.
14.509 + *
14.510 + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
14.511 + * the invoker can provide further input beyond that contained in the given
14.512 + * input buffer. If there is a possibility of providing additional input
14.513 + * then the invoker should pass <tt>false</tt> for this parameter; if there
14.514 + * is no possibility of providing further input then the invoker should
14.515 + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
14.516 + * common, to pass <tt>false</tt> in one invocation and later discover that
14.517 + * no further input was actually available. It is critical, however, that
14.518 + * the final invocation of this method in a sequence of invocations always
14.519 + * pass <tt>true</tt> so that any remaining unencoded input will be treated
14.520 + * as being malformed.
14.521 + *
14.522 + * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
14.523 + * method, interpreting its results, handling error conditions, and
14.524 + * reinvoking it as necessary. </p>
14.525 + *
14.526 + *
14.527 + * @param in
14.528 + * The input character buffer
14.529 + *
14.530 + * @param out
14.531 + * The output byte buffer
14.532 + *
14.533 + * @param endOfInput
14.534 + * <tt>true</tt> if, and only if, the invoker can provide no
14.535 + * additional input characters beyond those in the given buffer
14.536 + *
14.537 + * @return A coder-result object describing the reason for termination
14.538 + *
14.539 + * @throws IllegalStateException
14.540 + * If an encoding operation is already in progress and the previous
14.541 + * step was an invocation neither of the {@link #reset reset}
14.542 + * method, nor of this method with a value of <tt>false</tt> for
14.543 + * the <tt>endOfInput</tt> parameter, nor of this method with a
14.544 + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
14.545 + * but a return value indicating an incomplete encoding operation
14.546 + *
14.547 + * @throws CoderMalfunctionError
14.548 + * If an invocation of the encodeLoop method threw
14.549 + * an unexpected exception
14.550 + */
14.551 + public final CoderResult encode(CharBuffer in, ByteBuffer out,
14.552 + boolean endOfInput)
14.553 + {
14.554 + int newState = endOfInput ? ST_END : ST_CODING;
14.555 + if ((state != ST_RESET) && (state != ST_CODING)
14.556 + && !(endOfInput && (state == ST_END)))
14.557 + throwIllegalStateException(state, newState);
14.558 + state = newState;
14.559 +
14.560 + for (;;) {
14.561 +
14.562 + CoderResult cr;
14.563 + try {
14.564 + cr = encodeLoop(in, out);
14.565 + } catch (BufferUnderflowException x) {
14.566 + throw new CoderMalfunctionError(x);
14.567 + } catch (BufferOverflowException x) {
14.568 + throw new CoderMalfunctionError(x);
14.569 + }
14.570 +
14.571 + if (cr.isOverflow())
14.572 + return cr;
14.573 +
14.574 + if (cr.isUnderflow()) {
14.575 + if (endOfInput && in.hasRemaining()) {
14.576 + cr = CoderResult.malformedForLength(in.remaining());
14.577 + // Fall through to malformed-input case
14.578 + } else {
14.579 + return cr;
14.580 + }
14.581 + }
14.582 +
14.583 + CodingErrorAction action = null;
14.584 + if (cr.isMalformed())
14.585 + action = malformedInputAction;
14.586 + else if (cr.isUnmappable())
14.587 + action = unmappableCharacterAction;
14.588 + else
14.589 + assert false : cr.toString();
14.590 +
14.591 + if (action == CodingErrorAction.REPORT)
14.592 + return cr;
14.593 +
14.594 + if (action == CodingErrorAction.REPLACE) {
14.595 + if (out.remaining() < replacement.length)
14.596 + return CoderResult.OVERFLOW;
14.597 + out.put(replacement);
14.598 + }
14.599 +
14.600 + if ((action == CodingErrorAction.IGNORE)
14.601 + || (action == CodingErrorAction.REPLACE)) {
14.602 + // Skip erroneous input either way
14.603 + in.position(in.position() + cr.length());
14.604 + continue;
14.605 + }
14.606 +
14.607 + assert false;
14.608 + }
14.609 +
14.610 + }
14.611 +
14.612 + /**
14.613 + * Flushes this encoder.
14.614 + *
14.615 + * <p> Some encoders maintain internal state and may need to write some
14.616 + * final bytes to the output buffer once the overall input sequence has
14.617 + * been read.
14.618 + *
14.619 + * <p> Any additional output is written to the output buffer beginning at
14.620 + * its current position. At most {@link Buffer#remaining out.remaining()}
14.621 + * bytes will be written. The buffer's position will be advanced
14.622 + * appropriately, but its mark and limit will not be modified.
14.623 + *
14.624 + * <p> If this method completes successfully then it returns {@link
14.625 + * CoderResult#UNDERFLOW}. If there is insufficient room in the output
14.626 + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
14.627 + * then this method must be invoked again, with an output buffer that has
14.628 + * more room, in order to complete the current <a href="#steps">encoding
14.629 + * operation</a>.
14.630 + *
14.631 + * <p> If this encoder has already been flushed then invoking this method
14.632 + * has no effect.
14.633 + *
14.634 + * <p> This method invokes the {@link #implFlush implFlush} method to
14.635 + * perform the actual flushing operation. </p>
14.636 + *
14.637 + * @param out
14.638 + * The output byte buffer
14.639 + *
14.640 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
14.641 + * {@link CoderResult#OVERFLOW}
14.642 + *
14.643 + * @throws IllegalStateException
14.644 + * If the previous step of the current encoding operation was an
14.645 + * invocation neither of the {@link #flush flush} method nor of
14.646 + * the three-argument {@link
14.647 + * #encode(CharBuffer,ByteBuffer,boolean) encode} method
14.648 + * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
14.649 + * parameter
14.650 + */
14.651 + public final CoderResult flush(ByteBuffer out) {
14.652 + if (state == ST_END) {
14.653 + CoderResult cr = implFlush(out);
14.654 + if (cr.isUnderflow())
14.655 + state = ST_FLUSHED;
14.656 + return cr;
14.657 + }
14.658 +
14.659 + if (state != ST_FLUSHED)
14.660 + throwIllegalStateException(state, ST_FLUSHED);
14.661 +
14.662 + return CoderResult.UNDERFLOW; // Already flushed
14.663 + }
14.664 +
14.665 + /**
14.666 + * Flushes this encoder.
14.667 + *
14.668 + * <p> The default implementation of this method does nothing, and always
14.669 + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
14.670 + * by encoders that may need to write final bytes to the output buffer
14.671 + * once the entire input sequence has been read. </p>
14.672 + *
14.673 + * @param out
14.674 + * The output byte buffer
14.675 + *
14.676 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
14.677 + * {@link CoderResult#OVERFLOW}
14.678 + */
14.679 + protected CoderResult implFlush(ByteBuffer out) {
14.680 + return CoderResult.UNDERFLOW;
14.681 + }
14.682 +
14.683 + /**
14.684 + * Resets this encoder, clearing any internal state.
14.685 + *
14.686 + * <p> This method resets charset-independent state and also invokes the
14.687 + * {@link #implReset() implReset} method in order to perform any
14.688 + * charset-specific reset actions. </p>
14.689 + *
14.690 + * @return This encoder
14.691 + *
14.692 + */
14.693 + public final CharsetEncoder reset() {
14.694 + implReset();
14.695 + state = ST_RESET;
14.696 + return this;
14.697 + }
14.698 +
14.699 + /**
14.700 + * Resets this encoder, clearing any charset-specific internal state.
14.701 + *
14.702 + * <p> The default implementation of this method does nothing. This method
14.703 + * should be overridden by encoders that maintain internal state. </p>
14.704 + */
14.705 + protected void implReset() { }
14.706 +
14.707 + /**
14.708 + * Encodes one or more characters into one or more bytes.
14.709 + *
14.710 + * <p> This method encapsulates the basic encoding loop, encoding as many
14.711 + * characters as possible until it either runs out of input, runs out of room
14.712 + * in the output buffer, or encounters an encoding error. This method is
14.713 + * invoked by the {@link #encode encode} method, which handles result
14.714 + * interpretation and error recovery.
14.715 + *
14.716 + * <p> The buffers are read from, and written to, starting at their current
14.717 + * positions. At most {@link Buffer#remaining in.remaining()} characters
14.718 + * will be read, and at most {@link Buffer#remaining out.remaining()}
14.719 + * bytes will be written. The buffers' positions will be advanced to
14.720 + * reflect the characters read and the bytes written, but their marks and
14.721 + * limits will not be modified.
14.722 + *
14.723 + * <p> This method returns a {@link CoderResult} object to describe its
14.724 + * reason for termination, in the same manner as the {@link #encode encode}
14.725 + * method. Most implementations of this method will handle encoding errors
14.726 + * by returning an appropriate result object for interpretation by the
14.727 + * {@link #encode encode} method. An optimized implementation may instead
14.728 + * examine the relevant error action and implement that action itself.
14.729 + *
14.730 + * <p> An implementation of this method may perform arbitrary lookahead by
14.731 + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
14.732 + * input. </p>
14.733 + *
14.734 + * @param in
14.735 + * The input character buffer
14.736 + *
14.737 + * @param out
14.738 + * The output byte buffer
14.739 + *
14.740 + * @return A coder-result object describing the reason for termination
14.741 + */
14.742 + protected abstract CoderResult encodeLoop(CharBuffer in,
14.743 + ByteBuffer out);
14.744 +
14.745 + /**
14.746 + * Convenience method that encodes the remaining content of a single input
14.747 + * character buffer into a newly-allocated byte buffer.
14.748 + *
14.749 + * <p> This method implements an entire <a href="#steps">encoding
14.750 + * operation</a>; that is, it resets this encoder, then it encodes the
14.751 + * characters in the given character buffer, and finally it flushes this
14.752 + * encoder. This method should therefore not be invoked if an encoding
14.753 + * operation is already in progress. </p>
14.754 + *
14.755 + * @param in
14.756 + * The input character buffer
14.757 + *
14.758 + * @return A newly-allocated byte buffer containing the result of the
14.759 + * encoding operation. The buffer's position will be zero and its
14.760 + * limit will follow the last byte written.
14.761 + *
14.762 + * @throws IllegalStateException
14.763 + * If an encoding operation is already in progress
14.764 + *
14.765 + * @throws MalformedInputException
14.766 + * If the character sequence starting at the input buffer's current
14.767 + * position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
14.768 + * is {@link CodingErrorAction#REPORT}
14.769 + *
14.770 + * @throws UnmappableCharacterException
14.771 + * If the character sequence starting at the input buffer's current
14.772 + * position cannot be mapped to an equivalent byte sequence and
14.773 + * the current unmappable-character action is {@link
14.774 + * CodingErrorAction#REPORT}
14.775 + */
14.776 + public final ByteBuffer encode(CharBuffer in)
14.777 + throws CharacterCodingException
14.778 + {
14.779 + int n = (int)(in.remaining() * averageBytesPerChar());
14.780 + ByteBuffer out = ByteBuffer.allocate(n);
14.781 +
14.782 + if ((n == 0) && (in.remaining() == 0))
14.783 + return out;
14.784 + reset();
14.785 + for (;;) {
14.786 + CoderResult cr = in.hasRemaining() ?
14.787 + encode(in, out, true) : CoderResult.UNDERFLOW;
14.788 + if (cr.isUnderflow())
14.789 + cr = flush(out);
14.790 +
14.791 + if (cr.isUnderflow())
14.792 + break;
14.793 + if (cr.isOverflow()) {
14.794 + n = 2*n + 1; // Ensure progress; n might be 0!
14.795 + ByteBuffer o = ByteBuffer.allocate(n);
14.796 + out.flip();
14.797 + o.put(out);
14.798 + out = o;
14.799 + continue;
14.800 + }
14.801 + cr.throwException();
14.802 + }
14.803 + out.flip();
14.804 + return out;
14.805 + }
14.806 +
14.807 +
14.808 +
14.809 +
14.810 +
14.811 +
14.812 +
14.813 +
14.814 +
14.815 +
14.816 +
14.817 +
14.818 +
14.819 +
14.820 +
14.821 +
14.822 +
14.823 +
14.824 +
14.825 +
14.826 +
14.827 +
14.828 +
14.829 +
14.830 +
14.831 +
14.832 +
14.833 +
14.834 +
14.835 +
14.836 +
14.837 +
14.838 +
14.839 +
14.840 +
14.841 +
14.842 +
14.843 +
14.844 +
14.845 +
14.846 +
14.847 +
14.848 +
14.849 +
14.850 +
14.851 +
14.852 +
14.853 +
14.854 +
14.855 +
14.856 +
14.857 +
14.858 +
14.859 +
14.860 +
14.861 +
14.862 +
14.863 +
14.864 +
14.865 +
14.866 +
14.867 +
14.868 +
14.869 +
14.870 +
14.871 +
14.872 +
14.873 +
14.874 +
14.875 +
14.876 +
14.877 +
14.878 +
14.879 +
14.880 +
14.881 +
14.882 +
14.883 +
14.884 +
14.885 + private boolean canEncode(CharBuffer cb) {
14.886 + if (state == ST_FLUSHED)
14.887 + reset();
14.888 + else if (state != ST_RESET)
14.889 + throwIllegalStateException(state, ST_CODING);
14.890 + CodingErrorAction ma = malformedInputAction();
14.891 + CodingErrorAction ua = unmappableCharacterAction();
14.892 + try {
14.893 + onMalformedInput(CodingErrorAction.REPORT);
14.894 + onUnmappableCharacter(CodingErrorAction.REPORT);
14.895 + encode(cb);
14.896 + } catch (CharacterCodingException x) {
14.897 + return false;
14.898 + } finally {
14.899 + onMalformedInput(ma);
14.900 + onUnmappableCharacter(ua);
14.901 + reset();
14.902 + }
14.903 + return true;
14.904 + }
14.905 +
14.906 + /**
14.907 + * Tells whether or not this encoder can encode the given character.
14.908 + *
14.909 + * <p> This method returns <tt>false</tt> if the given character is a
14.910 + * surrogate character; such characters can be interpreted only when they
14.911 + * are members of a pair consisting of a high surrogate followed by a low
14.912 + * surrogate. The {@link #canEncode(java.lang.CharSequence)
14.913 + * canEncode(CharSequence)} method may be used to test whether or not a
14.914 + * character sequence can be encoded.
14.915 + *
14.916 + * <p> This method may modify this encoder's state; it should therefore not
14.917 + * be invoked if an <a href="#steps">encoding operation</a> is already in
14.918 + * progress.
14.919 + *
14.920 + * <p> The default implementation of this method is not very efficient; it
14.921 + * should generally be overridden to improve performance. </p>
14.922 + *
14.923 + * @return <tt>true</tt> if, and only if, this encoder can encode
14.924 + * the given character
14.925 + *
14.926 + * @throws IllegalStateException
14.927 + * If an encoding operation is already in progress
14.928 + */
14.929 + public boolean canEncode(char c) {
14.930 + CharBuffer cb = CharBuffer.allocate(1);
14.931 + cb.put(c);
14.932 + cb.flip();
14.933 + return canEncode(cb);
14.934 + }
14.935 +
14.936 + /**
14.937 + * Tells whether or not this encoder can encode the given character
14.938 + * sequence.
14.939 + *
14.940 + * <p> If this method returns <tt>false</tt> for a particular character
14.941 + * sequence then more information about why the sequence cannot be encoded
14.942 + * may be obtained by performing a full <a href="#steps">encoding
14.943 + * operation</a>.
14.944 + *
14.945 + * <p> This method may modify this encoder's state; it should therefore not
14.946 + * be invoked if an encoding operation is already in progress.
14.947 + *
14.948 + * <p> The default implementation of this method is not very efficient; it
14.949 + * should generally be overridden to improve performance. </p>
14.950 + *
14.951 + * @return <tt>true</tt> if, and only if, this encoder can encode
14.952 + * the given character without throwing any exceptions and without
14.953 + * performing any replacements
14.954 + *
14.955 + * @throws IllegalStateException
14.956 + * If an encoding operation is already in progress
14.957 + */
14.958 + public boolean canEncode(CharSequence cs) {
14.959 + CharBuffer cb;
14.960 + if (cs instanceof CharBuffer)
14.961 + cb = ((CharBuffer)cs).duplicate();
14.962 + else
14.963 + cb = CharBuffer.wrap(cs.toString());
14.964 + return canEncode(cb);
14.965 + }
14.966 +
14.967 +
14.968 +
14.969 +
14.970 + private void throwIllegalStateException(int from, int to) {
14.971 + throw new IllegalStateException("Current state = " + stateNames[from]
14.972 + + ", new state = " + stateNames[to]);
14.973 + }
14.974 +
14.975 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/IllegalCharsetNameException.java Thu Oct 03 15:43:10 2013 +0200
15.3 @@ -0,0 +1,68 @@
15.4 +/*
15.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
15.6 + *
15.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
15.8 + *
15.9 + *
15.10 + *
15.11 + *
15.12 + *
15.13 + *
15.14 + *
15.15 + *
15.16 + *
15.17 + *
15.18 + *
15.19 + *
15.20 + *
15.21 + *
15.22 + *
15.23 + *
15.24 + *
15.25 + *
15.26 + *
15.27 + *
15.28 + *
15.29 + */
15.30 +
15.31 +// -- This file was mechanically generated: Do not edit! -- //
15.32 +
15.33 +package java.nio.charset;
15.34 +
15.35 +
15.36 +/**
15.37 + * Unchecked exception thrown when a string that is not a
15.38 + * <a href=Charset.html#names>legal charset name</a> is used as such.
15.39 + *
15.40 + * @since 1.4
15.41 + */
15.42 +
15.43 +public class IllegalCharsetNameException
15.44 + extends IllegalArgumentException
15.45 +{
15.46 +
15.47 + private static final long serialVersionUID = 1457525358470002989L;
15.48 +
15.49 + private String charsetName;
15.50 +
15.51 + /**
15.52 + * Constructs an instance of this class. </p>
15.53 + *
15.54 + * @param charsetName
15.55 + * The illegal charset name
15.56 + */
15.57 + public IllegalCharsetNameException(String charsetName) {
15.58 + super(String.valueOf(charsetName));
15.59 + this.charsetName = charsetName;
15.60 + }
15.61 +
15.62 + /**
15.63 + * Retrieves the illegal charset name. </p>
15.64 + *
15.65 + * @return The illegal charset name
15.66 + */
15.67 + public String getCharsetName() {
15.68 + return charsetName;
15.69 + }
15.70 +
15.71 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/UnsupportedCharsetException.java Thu Oct 03 15:43:10 2013 +0200
16.3 @@ -0,0 +1,68 @@
16.4 +/*
16.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
16.6 + *
16.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
16.8 + *
16.9 + *
16.10 + *
16.11 + *
16.12 + *
16.13 + *
16.14 + *
16.15 + *
16.16 + *
16.17 + *
16.18 + *
16.19 + *
16.20 + *
16.21 + *
16.22 + *
16.23 + *
16.24 + *
16.25 + *
16.26 + *
16.27 + *
16.28 + *
16.29 + */
16.30 +
16.31 +// -- This file was mechanically generated: Do not edit! -- //
16.32 +
16.33 +package java.nio.charset;
16.34 +
16.35 +
16.36 +/**
16.37 + * Unchecked exception thrown when no support is available
16.38 + * for a requested charset.
16.39 + *
16.40 + * @since 1.4
16.41 + */
16.42 +
16.43 +public class UnsupportedCharsetException
16.44 + extends IllegalArgumentException
16.45 +{
16.46 +
16.47 + private static final long serialVersionUID = 1490765524727386367L;
16.48 +
16.49 + private String charsetName;
16.50 +
16.51 + /**
16.52 + * Constructs an instance of this class. </p>
16.53 + *
16.54 + * @param charsetName
16.55 + * The name of the unsupported charset
16.56 + */
16.57 + public UnsupportedCharsetException(String charsetName) {
16.58 + super(String.valueOf(charsetName));
16.59 + this.charsetName = charsetName;
16.60 + }
16.61 +
16.62 + /**
16.63 + * Retrieves the name of the unsupported charset. </p>
16.64 + *
16.65 + * @return The name of the unsupported charset
16.66 + */
16.67 + public String getCharsetName() {
16.68 + return charsetName;
16.69 + }
16.70 +
16.71 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/rt/emul/compact/src/main/java/java/security/AccessController.java Thu Oct 03 15:43:10 2013 +0200
17.3 @@ -0,0 +1,557 @@
17.4 +/*
17.5 + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
17.7 + *
17.8 + * This code is free software; you can redistribute it and/or modify it
17.9 + * under the terms of the GNU General Public License version 2 only, as
17.10 + * published by the Free Software Foundation. Oracle designates this
17.11 + * particular file as subject to the "Classpath" exception as provided
17.12 + * by Oracle in the LICENSE file that accompanied this code.
17.13 + *
17.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
17.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17.17 + * version 2 for more details (a copy is included in the LICENSE file that
17.18 + * accompanied this code).
17.19 + *
17.20 + * You should have received a copy of the GNU General Public License version
17.21 + * 2 along with this work; if not, write to the Free Software Foundation,
17.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17.23 + *
17.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
17.25 + * or visit www.oracle.com if you need additional information or have any
17.26 + * questions.
17.27 + */
17.28 +
17.29 +package java.security;
17.30 +
17.31 +import sun.security.util.Debug;
17.32 +
17.33 +/**
17.34 + * <p> The AccessController class is used for access control operations
17.35 + * and decisions.
17.36 + *
17.37 + * <p> More specifically, the AccessController class is used for
17.38 + * three purposes:
17.39 + *
17.40 + * <ul>
17.41 + * <li> to decide whether an access to a critical system
17.42 + * resource is to be allowed or denied, based on the security policy
17.43 + * currently in effect,<p>
17.44 + * <li>to mark code as being "privileged", thus affecting subsequent
17.45 + * access determinations, and<p>
17.46 + * <li>to obtain a "snapshot" of the current calling context so
17.47 + * access-control decisions from a different context can be made with
17.48 + * respect to the saved context. </ul>
17.49 + *
17.50 + * <p> The {@link #checkPermission(Permission) checkPermission} method
17.51 + * determines whether the access request indicated by a specified
17.52 + * permission should be granted or denied. A sample call appears
17.53 + * below. In this example, <code>checkPermission</code> will determine
17.54 + * whether or not to grant "read" access to the file named "testFile" in
17.55 + * the "/temp" directory.
17.56 + *
17.57 + * <pre>
17.58 + *
17.59 + * FilePermission perm = new FilePermission("/temp/testFile", "read");
17.60 + * AccessController.checkPermission(perm);
17.61 + *
17.62 + * </pre>
17.63 + *
17.64 + * <p> If a requested access is allowed,
17.65 + * <code>checkPermission</code> returns quietly. If denied, an
17.66 + * AccessControlException is
17.67 + * thrown. AccessControlException can also be thrown if the requested
17.68 + * permission is of an incorrect type or contains an invalid value.
17.69 + * Such information is given whenever possible.
17.70 + *
17.71 + * Suppose the current thread traversed m callers, in the order of caller 1
17.72 + * to caller 2 to caller m. Then caller m invoked the
17.73 + * <code>checkPermission</code> method.
17.74 + * The <code>checkPermission </code>method determines whether access
17.75 + * is granted or denied based on the following algorithm:
17.76 + *
17.77 + * <pre> {@code
17.78 + * for (int i = m; i > 0; i--) {
17.79 + *
17.80 + * if (caller i's domain does not have the permission)
17.81 + * throw AccessControlException
17.82 + *
17.83 + * else if (caller i is marked as privileged) {
17.84 + * if (a context was specified in the call to doPrivileged)
17.85 + * context.checkPermission(permission)
17.86 + * return;
17.87 + * }
17.88 + * };
17.89 + *
17.90 + * // Next, check the context inherited when the thread was created.
17.91 + * // Whenever a new thread is created, the AccessControlContext at
17.92 + * // that time is stored and associated with the new thread, as the
17.93 + * // "inherited" context.
17.94 + *
17.95 + * inheritedContext.checkPermission(permission);
17.96 + * }</pre>
17.97 + *
17.98 + * <p> A caller can be marked as being "privileged"
17.99 + * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
17.100 + * When making access control decisions, the <code>checkPermission</code>
17.101 + * method stops checking if it reaches a caller that
17.102 + * was marked as "privileged" via a <code>doPrivileged</code>
17.103 + * call without a context argument (see below for information about a
17.104 + * context argument). If that caller's domain has the
17.105 + * specified permission, no further checking is done and
17.106 + * <code>checkPermission</code>
17.107 + * returns quietly, indicating that the requested access is allowed.
17.108 + * If that domain does not have the specified permission, an exception
17.109 + * is thrown, as usual.
17.110 + *
17.111 + * <p> The normal use of the "privileged" feature is as follows. If you
17.112 + * don't need to return a value from within the "privileged" block, do
17.113 + * the following:
17.114 + *
17.115 + * <pre> {@code
17.116 + * somemethod() {
17.117 + * ...normal code here...
17.118 + * AccessController.doPrivileged(new PrivilegedAction<Void>() {
17.119 + * public Void run() {
17.120 + * // privileged code goes here, for example:
17.121 + * System.loadLibrary("awt");
17.122 + * return null; // nothing to return
17.123 + * }
17.124 + * });
17.125 + * ...normal code here...
17.126 + * }}</pre>
17.127 + *
17.128 + * <p>
17.129 + * PrivilegedAction is an interface with a single method, named
17.130 + * <code>run</code>.
17.131 + * The above example shows creation of an implementation
17.132 + * of that interface; a concrete implementation of the
17.133 + * <code>run</code> method is supplied.
17.134 + * When the call to <code>doPrivileged</code> is made, an
17.135 + * instance of the PrivilegedAction implementation is passed
17.136 + * to it. The <code>doPrivileged</code> method calls the
17.137 + * <code>run</code> method from the PrivilegedAction
17.138 + * implementation after enabling privileges, and returns the
17.139 + * <code>run</code> method's return value as the
17.140 + * <code>doPrivileged</code> return value (which is
17.141 + * ignored in this example).
17.142 + *
17.143 + * <p> If you need to return a value, you can do something like the following:
17.144 + *
17.145 + * <pre> {@code
17.146 + * somemethod() {
17.147 + * ...normal code here...
17.148 + * String user = AccessController.doPrivileged(
17.149 + * new PrivilegedAction<String>() {
17.150 + * public String run() {
17.151 + * return System.getProperty("user.name");
17.152 + * }
17.153 + * });
17.154 + * ...normal code here...
17.155 + * }}</pre>
17.156 + *
17.157 + * <p>If the action performed in your <code>run</code> method could
17.158 + * throw a "checked" exception (those listed in the <code>throws</code> clause
17.159 + * of a method), then you need to use the
17.160 + * <code>PrivilegedExceptionAction</code> interface instead of the
17.161 + * <code>PrivilegedAction</code> interface:
17.162 + *
17.163 + * <pre> {@code
17.164 + * somemethod() throws FileNotFoundException {
17.165 + * ...normal code here...
17.166 + * try {
17.167 + * FileInputStream fis = AccessController.doPrivileged(
17.168 + * new PrivilegedExceptionAction<FileInputStream>() {
17.169 + * public FileInputStream run() throws FileNotFoundException {
17.170 + * return new FileInputStream("someFile");
17.171 + * }
17.172 + * });
17.173 + * } catch (PrivilegedActionException e) {
17.174 + * // e.getException() should be an instance of FileNotFoundException,
17.175 + * // as only "checked" exceptions will be "wrapped" in a
17.176 + * // PrivilegedActionException.
17.177 + * throw (FileNotFoundException) e.getException();
17.178 + * }
17.179 + * ...normal code here...
17.180 + * }}</pre>
17.181 + *
17.182 + * <p> Be *very* careful in your use of the "privileged" construct, and
17.183 + * always remember to make the privileged code section as small as possible.
17.184 + *
17.185 + * <p> Note that <code>checkPermission</code> always performs security checks
17.186 + * within the context of the currently executing thread.
17.187 + * Sometimes a security check that should be made within a given context
17.188 + * will actually need to be done from within a
17.189 + * <i>different</i> context (for example, from within a worker thread).
17.190 + * The {@link #getContext() getContext} method and
17.191 + * AccessControlContext class are provided
17.192 + * for this situation. The <code>getContext</code> method takes a "snapshot"
17.193 + * of the current calling context, and places
17.194 + * it in an AccessControlContext object, which it returns. A sample call is
17.195 + * the following:
17.196 + *
17.197 + * <pre>
17.198 + *
17.199 + * AccessControlContext acc = AccessController.getContext()
17.200 + *
17.201 + * </pre>
17.202 + *
17.203 + * <p>
17.204 + * AccessControlContext itself has a <code>checkPermission</code> method
17.205 + * that makes access decisions based on the context <i>it</i> encapsulates,
17.206 + * rather than that of the current execution thread.
17.207 + * Code within a different context can thus call that method on the
17.208 + * previously-saved AccessControlContext object. A sample call is the
17.209 + * following:
17.210 + *
17.211 + * <pre>
17.212 + *
17.213 + * acc.checkPermission(permission)
17.214 + *
17.215 + * </pre>
17.216 + *
17.217 + * <p> There are also times where you don't know a priori which permissions
17.218 + * to check the context against. In these cases you can use the
17.219 + * doPrivileged method that takes a context:
17.220 + *
17.221 + * <pre> {@code
17.222 + * somemethod() {
17.223 + * AccessController.doPrivileged(new PrivilegedAction<Object>() {
17.224 + * public Object run() {
17.225 + * // Code goes here. Any permission checks within this
17.226 + * // run method will require that the intersection of the
17.227 + * // callers protection domain and the snapshot's
17.228 + * // context have the desired permission.
17.229 + * }
17.230 + * }, acc);
17.231 + * ...normal code here...
17.232 + * }}</pre>
17.233 + *
17.234 + * @see AccessControlContext
17.235 + *
17.236 + * @author Li Gong
17.237 + * @author Roland Schemers
17.238 + */
17.239 +
17.240 +public final class AccessController {
17.241 +
17.242 + /**
17.243 + * Don't allow anyone to instantiate an AccessController
17.244 + */
17.245 + private AccessController() { }
17.246 +
17.247 + /**
17.248 + * Performs the specified <code>PrivilegedAction</code> with privileges
17.249 + * enabled. The action is performed with <i>all</i> of the permissions
17.250 + * possessed by the caller's protection domain.
17.251 + *
17.252 + * <p> If the action's <code>run</code> method throws an (unchecked)
17.253 + * exception, it will propagate through this method.
17.254 + *
17.255 + * <p> Note that any DomainCombiner associated with the current
17.256 + * AccessControlContext will be ignored while the action is performed.
17.257 + *
17.258 + * @param action the action to be performed.
17.259 + *
17.260 + * @return the value returned by the action's <code>run</code> method.
17.261 + *
17.262 + * @exception NullPointerException if the action is <code>null</code>
17.263 + *
17.264 + * @see #doPrivileged(PrivilegedAction,AccessControlContext)
17.265 + * @see #doPrivileged(PrivilegedExceptionAction)
17.266 + * @see #doPrivilegedWithCombiner(PrivilegedAction)
17.267 + * @see java.security.DomainCombiner
17.268 + */
17.269 +
17.270 + public static native <T> T doPrivileged(PrivilegedAction<T> action);
17.271 +
17.272 + /**
17.273 + * Performs the specified <code>PrivilegedAction</code> with privileges
17.274 + * enabled. The action is performed with <i>all</i> of the permissions
17.275 + * possessed by the caller's protection domain.
17.276 + *
17.277 + * <p> If the action's <code>run</code> method throws an (unchecked)
17.278 + * exception, it will propagate through this method.
17.279 + *
17.280 + * <p> This method preserves the current AccessControlContext's
17.281 + * DomainCombiner (which may be null) while the action is performed.
17.282 + *
17.283 + * @param action the action to be performed.
17.284 + *
17.285 + * @return the value returned by the action's <code>run</code> method.
17.286 + *
17.287 + * @exception NullPointerException if the action is <code>null</code>
17.288 + *
17.289 + * @see #doPrivileged(PrivilegedAction)
17.290 + * @see java.security.DomainCombiner
17.291 + *
17.292 + * @since 1.6
17.293 + */
17.294 + public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
17.295 +
17.296 + DomainCombiner dc = null;
17.297 + AccessControlContext acc = getStackAccessControlContext();
17.298 + if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
17.299 + return AccessController.doPrivileged(action);
17.300 + }
17.301 + return AccessController.doPrivileged(action, preserveCombiner(dc));
17.302 + }
17.303 +
17.304 +
17.305 + /**
17.306 + * Performs the specified <code>PrivilegedAction</code> with privileges
17.307 + * enabled and restricted by the specified
17.308 + * <code>AccessControlContext</code>.
17.309 + * The action is performed with the intersection of the permissions
17.310 + * possessed by the caller's protection domain, and those possessed
17.311 + * by the domains represented by the specified
17.312 + * <code>AccessControlContext</code>.
17.313 + * <p>
17.314 + * If the action's <code>run</code> method throws an (unchecked) exception,
17.315 + * it will propagate through this method.
17.316 + *
17.317 + * @param action the action to be performed.
17.318 + * @param context an <i>access control context</i>
17.319 + * representing the restriction to be applied to the
17.320 + * caller's domain's privileges before performing
17.321 + * the specified action. If the context is
17.322 + * <code>null</code>,
17.323 + * then no additional restriction is applied.
17.324 + *
17.325 + * @return the value returned by the action's <code>run</code> method.
17.326 + *
17.327 + * @exception NullPointerException if the action is <code>null</code>
17.328 + *
17.329 + * @see #doPrivileged(PrivilegedAction)
17.330 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
17.331 + */
17.332 + public static native <T> T doPrivileged(PrivilegedAction<T> action,
17.333 + AccessControlContext context);
17.334 +
17.335 + /**
17.336 + * Performs the specified <code>PrivilegedExceptionAction</code> with
17.337 + * privileges enabled. The action is performed with <i>all</i> of the
17.338 + * permissions possessed by the caller's protection domain.
17.339 + *
17.340 + * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
17.341 + * exception, it will propagate through this method.
17.342 + *
17.343 + * <p> Note that any DomainCombiner associated with the current
17.344 + * AccessControlContext will be ignored while the action is performed.
17.345 + *
17.346 + * @param action the action to be performed
17.347 + *
17.348 + * @return the value returned by the action's <code>run</code> method
17.349 + *
17.350 + * @exception PrivilegedActionException if the specified action's
17.351 + * <code>run</code> method threw a <i>checked</i> exception
17.352 + * @exception NullPointerException if the action is <code>null</code>
17.353 + *
17.354 + * @see #doPrivileged(PrivilegedAction)
17.355 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
17.356 + * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
17.357 + * @see java.security.DomainCombiner
17.358 + */
17.359 + public static native <T> T
17.360 + doPrivileged(PrivilegedExceptionAction<T> action)
17.361 + throws PrivilegedActionException;
17.362 +
17.363 +
17.364 + /**
17.365 + * Performs the specified <code>PrivilegedExceptionAction</code> with
17.366 + * privileges enabled. The action is performed with <i>all</i> of the
17.367 + * permissions possessed by the caller's protection domain.
17.368 + *
17.369 + * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
17.370 + * exception, it will propagate through this method.
17.371 + *
17.372 + * <p> This method preserves the current AccessControlContext's
17.373 + * DomainCombiner (which may be null) while the action is performed.
17.374 + *
17.375 + * @param action the action to be performed.
17.376 + *
17.377 + * @return the value returned by the action's <code>run</code> method
17.378 + *
17.379 + * @exception PrivilegedActionException if the specified action's
17.380 + * <code>run</code> method threw a <i>checked</i> exception
17.381 + * @exception NullPointerException if the action is <code>null</code>
17.382 + *
17.383 + * @see #doPrivileged(PrivilegedAction)
17.384 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
17.385 + * @see java.security.DomainCombiner
17.386 + *
17.387 + * @since 1.6
17.388 + */
17.389 + public static <T> T doPrivilegedWithCombiner
17.390 + (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
17.391 +
17.392 + DomainCombiner dc = null;
17.393 + AccessControlContext acc = getStackAccessControlContext();
17.394 + if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
17.395 + return AccessController.doPrivileged(action);
17.396 + }
17.397 + return AccessController.doPrivileged(action, preserveCombiner(dc));
17.398 + }
17.399 +
17.400 + /**
17.401 + * preserve the combiner across the doPrivileged call
17.402 + */
17.403 + private static AccessControlContext preserveCombiner
17.404 + (DomainCombiner combiner) {
17.405 +
17.406 + /**
17.407 + * callerClass[0] = Reflection.getCallerClass
17.408 + * callerClass[1] = AccessController.preserveCombiner
17.409 + * callerClass[2] = AccessController.doPrivileged
17.410 + * callerClass[3] = caller
17.411 + */
17.412 + final Class callerClass = sun.reflect.Reflection.getCallerClass(3);
17.413 + ProtectionDomain callerPd = doPrivileged
17.414 + (new PrivilegedAction<ProtectionDomain>() {
17.415 + public ProtectionDomain run() {
17.416 + return callerClass.getProtectionDomain();
17.417 + }
17.418 + });
17.419 +
17.420 + // perform 'combine' on the caller of doPrivileged,
17.421 + // even if the caller is from the bootclasspath
17.422 + ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
17.423 + return new AccessControlContext(combiner.combine(pds, null), combiner);
17.424 + }
17.425 +
17.426 +
17.427 + /**
17.428 + * Performs the specified <code>PrivilegedExceptionAction</code> with
17.429 + * privileges enabled and restricted by the specified
17.430 + * <code>AccessControlContext</code>. The action is performed with the
17.431 + * intersection of the permissions possessed by the caller's
17.432 + * protection domain, and those possessed by the domains represented by the
17.433 + * specified <code>AccessControlContext</code>.
17.434 + * <p>
17.435 + * If the action's <code>run</code> method throws an <i>unchecked</i>
17.436 + * exception, it will propagate through this method.
17.437 + *
17.438 + * @param action the action to be performed
17.439 + * @param context an <i>access control context</i>
17.440 + * representing the restriction to be applied to the
17.441 + * caller's domain's privileges before performing
17.442 + * the specified action. If the context is
17.443 + * <code>null</code>,
17.444 + * then no additional restriction is applied.
17.445 + *
17.446 + * @return the value returned by the action's <code>run</code> method
17.447 + *
17.448 + * @exception PrivilegedActionException if the specified action's
17.449 + * <code>run</code> method
17.450 + * threw a <i>checked</i> exception
17.451 + * @exception NullPointerException if the action is <code>null</code>
17.452 + *
17.453 + * @see #doPrivileged(PrivilegedAction)
17.454 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
17.455 + */
17.456 + public static native <T> T
17.457 + doPrivileged(PrivilegedExceptionAction<T> action,
17.458 + AccessControlContext context)
17.459 + throws PrivilegedActionException;
17.460 +
17.461 + /**
17.462 + * Returns the AccessControl context. i.e., it gets
17.463 + * the protection domains of all the callers on the stack,
17.464 + * starting at the first class with a non-null
17.465 + * ProtectionDomain.
17.466 + *
17.467 + * @return the access control context based on the current stack or
17.468 + * null if there was only privileged system code.
17.469 + */
17.470 +
17.471 + private static native AccessControlContext getStackAccessControlContext();
17.472 +
17.473 + /**
17.474 + * Returns the "inherited" AccessControl context. This is the context
17.475 + * that existed when the thread was created. Package private so
17.476 + * AccessControlContext can use it.
17.477 + */
17.478 +
17.479 + static native AccessControlContext getInheritedAccessControlContext();
17.480 +
17.481 + /**
17.482 + * This method takes a "snapshot" of the current calling context, which
17.483 + * includes the current Thread's inherited AccessControlContext,
17.484 + * and places it in an AccessControlContext object. This context may then
17.485 + * be checked at a later point, possibly in another thread.
17.486 + *
17.487 + * @see AccessControlContext
17.488 + *
17.489 + * @return the AccessControlContext based on the current context.
17.490 + */
17.491 +
17.492 + public static AccessControlContext getContext()
17.493 + {
17.494 + AccessControlContext acc = getStackAccessControlContext();
17.495 + if (acc == null) {
17.496 + // all we had was privileged system code. We don't want
17.497 + // to return null though, so we construct a real ACC.
17.498 + return new AccessControlContext(null, true);
17.499 + } else {
17.500 + return acc.optimize();
17.501 + }
17.502 + }
17.503 +
17.504 + /**
17.505 + * Determines whether the access request indicated by the
17.506 + * specified permission should be allowed or denied, based on
17.507 + * the current AccessControlContext and security policy.
17.508 + * This method quietly returns if the access request
17.509 + * is permitted, or throws an AccessControlException otherwise. The
17.510 + * getPermission method of the AccessControlException returns the
17.511 + * <code>perm</code> Permission object instance.
17.512 + *
17.513 + * @param perm the requested permission.
17.514 + *
17.515 + * @exception AccessControlException if the specified permission
17.516 + * is not permitted, based on the current security policy.
17.517 + * @exception NullPointerException if the specified permission
17.518 + * is <code>null</code> and is checked based on the
17.519 + * security policy currently in effect.
17.520 + */
17.521 +
17.522 + public static void checkPermission(Permission perm)
17.523 + throws AccessControlException
17.524 + {
17.525 + //System.err.println("checkPermission "+perm);
17.526 + //Thread.currentThread().dumpStack();
17.527 +
17.528 + if (perm == null) {
17.529 + throw new NullPointerException("permission can't be null");
17.530 + }
17.531 +
17.532 + AccessControlContext stack = getStackAccessControlContext();
17.533 + // if context is null, we had privileged system code on the stack.
17.534 + if (stack == null) {
17.535 + Debug debug = AccessControlContext.getDebug();
17.536 + boolean dumpDebug = false;
17.537 + if (debug != null) {
17.538 + dumpDebug = !Debug.isOn("codebase=");
17.539 + dumpDebug &= !Debug.isOn("permission=") ||
17.540 + Debug.isOn("permission=" + perm.getClass().getCanonicalName());
17.541 + }
17.542 +
17.543 + if (dumpDebug && Debug.isOn("stack")) {
17.544 + Thread.currentThread().dumpStack();
17.545 + }
17.546 +
17.547 + if (dumpDebug && Debug.isOn("domain")) {
17.548 + debug.println("domain (context is null)");
17.549 + }
17.550 +
17.551 + if (dumpDebug) {
17.552 + debug.println("access allowed "+perm);
17.553 + }
17.554 + return;
17.555 + }
17.556 +
17.557 + AccessControlContext acc = stack.optimize();
17.558 + acc.checkPermission(perm);
17.559 + }
17.560 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedAction.java Thu Oct 03 15:43:10 2013 +0200
18.3 @@ -0,0 +1,56 @@
18.4 +/*
18.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
18.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
18.7 + *
18.8 + * This code is free software; you can redistribute it and/or modify it
18.9 + * under the terms of the GNU General Public License version 2 only, as
18.10 + * published by the Free Software Foundation. Oracle designates this
18.11 + * particular file as subject to the "Classpath" exception as provided
18.12 + * by Oracle in the LICENSE file that accompanied this code.
18.13 + *
18.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
18.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18.17 + * version 2 for more details (a copy is included in the LICENSE file that
18.18 + * accompanied this code).
18.19 + *
18.20 + * You should have received a copy of the GNU General Public License version
18.21 + * 2 along with this work; if not, write to the Free Software Foundation,
18.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18.23 + *
18.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
18.25 + * or visit www.oracle.com if you need additional information or have any
18.26 + * questions.
18.27 + */
18.28 +
18.29 +package java.security;
18.30 +
18.31 +
18.32 +/**
18.33 + * A computation to be performed with privileges enabled. The computation is
18.34 + * performed by invoking <code>AccessController.doPrivileged</code> on the
18.35 + * <code>PrivilegedAction</code> object. This interface is used only for
18.36 + * computations that do not throw checked exceptions; computations that
18.37 + * throw checked exceptions must use <code>PrivilegedExceptionAction</code>
18.38 + * instead.
18.39 + *
18.40 + * @see AccessController
18.41 + * @see AccessController#doPrivileged(PrivilegedAction)
18.42 + * @see PrivilegedExceptionAction
18.43 + */
18.44 +
18.45 +public interface PrivilegedAction<T> {
18.46 + /**
18.47 + * Performs the computation. This method will be called by
18.48 + * <code>AccessController.doPrivileged</code> after enabling privileges.
18.49 + *
18.50 + * @return a class-dependent value that may represent the results of the
18.51 + * computation. Each class that implements
18.52 + * <code>PrivilegedAction</code>
18.53 + * should document what (if anything) this value represents.
18.54 + * @see AccessController#doPrivileged(PrivilegedAction)
18.55 + * @see AccessController#doPrivileged(PrivilegedAction,
18.56 + * AccessControlContext)
18.57 + */
18.58 + T run();
18.59 +}
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedActionException.java Thu Oct 03 15:43:10 2013 +0200
19.3 @@ -0,0 +1,105 @@
19.4 +/*
19.5 + * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
19.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
19.7 + *
19.8 + * This code is free software; you can redistribute it and/or modify it
19.9 + * under the terms of the GNU General Public License version 2 only, as
19.10 + * published by the Free Software Foundation. Oracle designates this
19.11 + * particular file as subject to the "Classpath" exception as provided
19.12 + * by Oracle in the LICENSE file that accompanied this code.
19.13 + *
19.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
19.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19.17 + * version 2 for more details (a copy is included in the LICENSE file that
19.18 + * accompanied this code).
19.19 + *
19.20 + * You should have received a copy of the GNU General Public License version
19.21 + * 2 along with this work; if not, write to the Free Software Foundation,
19.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19.23 + *
19.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19.25 + * or visit www.oracle.com if you need additional information or have any
19.26 + * questions.
19.27 + */
19.28 +
19.29 +package java.security;
19.30 +
19.31 +/**
19.32 + * This exception is thrown by
19.33 + * <code>doPrivileged(PrivilegedExceptionAction)</code> and
19.34 + * <code>doPrivileged(PrivilegedExceptionAction,
19.35 + * AccessControlContext context)</code> to indicate
19.36 + * that the action being performed threw a checked exception. The exception
19.37 + * thrown by the action can be obtained by calling the
19.38 + * <code>getException</code> method. In effect, an
19.39 + * <code>PrivilegedActionException</code> is a "wrapper"
19.40 + * for an exception thrown by a privileged action.
19.41 + *
19.42 + * <p>As of release 1.4, this exception has been retrofitted to conform to
19.43 + * the general purpose exception-chaining mechanism. The "exception thrown
19.44 + * by the privileged computation" that is provided at construction time and
19.45 + * accessed via the {@link #getException()} method is now known as the
19.46 + * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
19.47 + * method, as well as the aforementioned "legacy method."
19.48 + *
19.49 + * @see PrivilegedExceptionAction
19.50 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
19.51 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
19.52 + */
19.53 +public class PrivilegedActionException extends Exception {
19.54 + // use serialVersionUID from JDK 1.2.2 for interoperability
19.55 + private static final long serialVersionUID = 4724086851538908602L;
19.56 +
19.57 + /**
19.58 + * @serial
19.59 + */
19.60 + private Exception exception;
19.61 +
19.62 + /**
19.63 + * Constructs a new PrivilegedActionException "wrapping"
19.64 + * the specific Exception.
19.65 + *
19.66 + * @param exception The exception thrown
19.67 + */
19.68 + public PrivilegedActionException(Exception exception) {
19.69 + super((Throwable)null); // Disallow initCause
19.70 + this.exception = exception;
19.71 + }
19.72 +
19.73 + /**
19.74 + * Returns the exception thrown by the privileged computation that
19.75 + * resulted in this <code>PrivilegedActionException</code>.
19.76 + *
19.77 + * <p>This method predates the general-purpose exception chaining facility.
19.78 + * The {@link Throwable#getCause()} method is now the preferred means of
19.79 + * obtaining this information.
19.80 + *
19.81 + * @return the exception thrown by the privileged computation that
19.82 + * resulted in this <code>PrivilegedActionException</code>.
19.83 + * @see PrivilegedExceptionAction
19.84 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
19.85 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
19.86 + * AccessControlContext)
19.87 + */
19.88 + public Exception getException() {
19.89 + return exception;
19.90 + }
19.91 +
19.92 + /**
19.93 + * Returns the cause of this exception (the exception thrown by
19.94 + * the privileged computation that resulted in this
19.95 + * <code>PrivilegedActionException</code>).
19.96 + *
19.97 + * @return the cause of this exception.
19.98 + * @since 1.4
19.99 + */
19.100 + public Throwable getCause() {
19.101 + return exception;
19.102 + }
19.103 +
19.104 + public String toString() {
19.105 + String s = getClass().getName();
19.106 + return (exception != null) ? (s + ": " + exception.toString()) : s;
19.107 + }
19.108 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedExceptionAction.java Thu Oct 03 15:43:10 2013 +0200
20.3 @@ -0,0 +1,62 @@
20.4 +/*
20.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
20.7 + *
20.8 + * This code is free software; you can redistribute it and/or modify it
20.9 + * under the terms of the GNU General Public License version 2 only, as
20.10 + * published by the Free Software Foundation. Oracle designates this
20.11 + * particular file as subject to the "Classpath" exception as provided
20.12 + * by Oracle in the LICENSE file that accompanied this code.
20.13 + *
20.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
20.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20.17 + * version 2 for more details (a copy is included in the LICENSE file that
20.18 + * accompanied this code).
20.19 + *
20.20 + * You should have received a copy of the GNU General Public License version
20.21 + * 2 along with this work; if not, write to the Free Software Foundation,
20.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20.23 + *
20.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20.25 + * or visit www.oracle.com if you need additional information or have any
20.26 + * questions.
20.27 + */
20.28 +
20.29 +package java.security;
20.30 +
20.31 +
20.32 +/**
20.33 + * A computation to be performed with privileges enabled, that throws one or
20.34 + * more checked exceptions. The computation is performed by invoking
20.35 + * <code>AccessController.doPrivileged</code> on the
20.36 + * <code>PrivilegedExceptionAction</code> object. This interface is
20.37 + * used only for computations that throw checked exceptions;
20.38 + * computations that do not throw
20.39 + * checked exceptions should use <code>PrivilegedAction</code> instead.
20.40 + *
20.41 + * @see AccessController
20.42 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
20.43 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
20.44 + * AccessControlContext)
20.45 + * @see PrivilegedAction
20.46 + */
20.47 +
20.48 +public interface PrivilegedExceptionAction<T> {
20.49 + /**
20.50 + * Performs the computation. This method will be called by
20.51 + * <code>AccessController.doPrivileged</code> after enabling privileges.
20.52 + *
20.53 + * @return a class-dependent value that may represent the results of the
20.54 + * computation. Each class that implements
20.55 + * <code>PrivilegedExceptionAction</code> should document what
20.56 + * (if anything) this value represents.
20.57 + * @throws Exception an exceptional condition has occurred. Each class
20.58 + * that implements <code>PrivilegedExceptionAction</code> should
20.59 + * document the exceptions that its run method can throw.
20.60 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
20.61 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
20.62 + */
20.63 +
20.64 + T run() throws Exception;
20.65 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/rt/emul/compact/src/main/java/java/text/Annotation.java Thu Oct 03 15:43:10 2013 +0200
21.3 @@ -0,0 +1,84 @@
21.4 +/*
21.5 + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
21.7 + *
21.8 + * This code is free software; you can redistribute it and/or modify it
21.9 + * under the terms of the GNU General Public License version 2 only, as
21.10 + * published by the Free Software Foundation. Oracle designates this
21.11 + * particular file as subject to the "Classpath" exception as provided
21.12 + * by Oracle in the LICENSE file that accompanied this code.
21.13 + *
21.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
21.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21.17 + * version 2 for more details (a copy is included in the LICENSE file that
21.18 + * accompanied this code).
21.19 + *
21.20 + * You should have received a copy of the GNU General Public License version
21.21 + * 2 along with this work; if not, write to the Free Software Foundation,
21.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21.23 + *
21.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21.25 + * or visit www.oracle.com if you need additional information or have any
21.26 + * questions.
21.27 + */
21.28 +
21.29 +package java.text;
21.30 +
21.31 +/**
21.32 +* An Annotation object is used as a wrapper for a text attribute value if
21.33 +* the attribute has annotation characteristics. These characteristics are:
21.34 +* <ul>
21.35 +* <li>The text range that the attribute is applied to is critical to the
21.36 +* semantics of the range. That means, the attribute cannot be applied to subranges
21.37 +* of the text range that it applies to, and, if two adjacent text ranges have
21.38 +* the same value for this attribute, the attribute still cannot be applied to
21.39 +* the combined range as a whole with this value.
21.40 +* <li>The attribute or its value usually do no longer apply if the underlying text is
21.41 +* changed.
21.42 +* </ul>
21.43 +*
21.44 +* An example is grammatical information attached to a sentence:
21.45 +* For the previous sentence, you can say that "an example"
21.46 +* is the subject, but you cannot say the same about "an", "example", or "exam".
21.47 +* When the text is changed, the grammatical information typically becomes invalid.
21.48 +* Another example is Japanese reading information (yomi).
21.49 +*
21.50 +* <p>
21.51 +* Wrapping the attribute value into an Annotation object guarantees that
21.52 +* adjacent text runs don't get merged even if the attribute values are equal,
21.53 +* and indicates to text containers that the attribute should be discarded if
21.54 +* the underlying text is modified.
21.55 +*
21.56 +* @see AttributedCharacterIterator
21.57 +* @since 1.2
21.58 +*/
21.59 +
21.60 +public class Annotation {
21.61 +
21.62 + /**
21.63 + * Constructs an annotation record with the given value, which
21.64 + * may be null.
21.65 + * @param value The value of the attribute
21.66 + */
21.67 + public Annotation(Object value) {
21.68 + this.value = value;
21.69 + }
21.70 +
21.71 + /**
21.72 + * Returns the value of the attribute, which may be null.
21.73 + */
21.74 + public Object getValue() {
21.75 + return value;
21.76 + }
21.77 +
21.78 + /**
21.79 + * Returns the String representation of this Annotation.
21.80 + */
21.81 + public String toString() {
21.82 + return getClass().getName() + "[value=" + value + "]";
21.83 + }
21.84 +
21.85 + private Object value;
21.86 +
21.87 +};
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedCharacterIterator.java Thu Oct 03 15:43:10 2013 +0200
22.3 @@ -0,0 +1,254 @@
22.4 +/*
22.5 + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
22.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
22.7 + *
22.8 + * This code is free software; you can redistribute it and/or modify it
22.9 + * under the terms of the GNU General Public License version 2 only, as
22.10 + * published by the Free Software Foundation. Oracle designates this
22.11 + * particular file as subject to the "Classpath" exception as provided
22.12 + * by Oracle in the LICENSE file that accompanied this code.
22.13 + *
22.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
22.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22.17 + * version 2 for more details (a copy is included in the LICENSE file that
22.18 + * accompanied this code).
22.19 + *
22.20 + * You should have received a copy of the GNU General Public License version
22.21 + * 2 along with this work; if not, write to the Free Software Foundation,
22.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22.23 + *
22.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22.25 + * or visit www.oracle.com if you need additional information or have any
22.26 + * questions.
22.27 + */
22.28 +
22.29 +package java.text;
22.30 +
22.31 +import java.io.InvalidObjectException;
22.32 +import java.io.Serializable;
22.33 +import java.util.HashMap;
22.34 +import java.util.Map;
22.35 +import java.util.Set;
22.36 +
22.37 +/**
22.38 + * An {@code AttributedCharacterIterator} allows iteration through both text and
22.39 + * related attribute information.
22.40 + *
22.41 + * <p>
22.42 + * An attribute is a key/value pair, identified by the key. No two
22.43 + * attributes on a given character can have the same key.
22.44 + *
22.45 + * <p>The values for an attribute are immutable, or must not be mutated
22.46 + * by clients or storage. They are always passed by reference, and not
22.47 + * cloned.
22.48 + *
22.49 + * <p>A <em>run with respect to an attribute</em> is a maximum text range for
22.50 + * which:
22.51 + * <ul>
22.52 + * <li>the attribute is undefined or {@code null} for the entire range, or
22.53 + * <li>the attribute value is defined and has the same non-{@code null} value for the
22.54 + * entire range.
22.55 + * </ul>
22.56 + *
22.57 + * <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
22.58 + * which this condition is met for each member attribute.
22.59 + *
22.60 + * <p>When getting a run with no explicit attributes specified (i.e.,
22.61 + * calling {@link #getRunStart()} and {@link #getRunLimit()}), any
22.62 + * contiguous text segments having the same attributes (the same set
22.63 + * of attribute/value pairs) are treated as separate runs if the
22.64 + * attributes have been given to those text segments separately.
22.65 + *
22.66 + * <p>The returned indexes are limited to the range of the iterator.
22.67 + *
22.68 + * <p>The returned attribute information is limited to runs that contain
22.69 + * the current character.
22.70 + *
22.71 + * <p>
22.72 + * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
22.73 + * subclasses, such as {@link java.awt.font.TextAttribute}.
22.74 + *
22.75 + * @see AttributedCharacterIterator.Attribute
22.76 + * @see java.awt.font.TextAttribute
22.77 + * @see AttributedString
22.78 + * @see Annotation
22.79 + * @since 1.2
22.80 + */
22.81 +
22.82 +public interface AttributedCharacterIterator extends CharacterIterator {
22.83 +
22.84 + /**
22.85 + * Defines attribute keys that are used to identify text attributes. These
22.86 + * keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
22.87 + * @see AttributedCharacterIterator
22.88 + * @see AttributedString
22.89 + * @since 1.2
22.90 + */
22.91 +
22.92 + public static class Attribute implements Serializable {
22.93 +
22.94 + /**
22.95 + * The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
22.96 + * to look up the corresponding predefined instance when deserializing
22.97 + * an instance.
22.98 + * @serial
22.99 + */
22.100 + private String name;
22.101 +
22.102 + // table of all instances in this class, used by readResolve
22.103 + private static final Map instanceMap = new HashMap(7);
22.104 +
22.105 + /**
22.106 + * Constructs an {@code Attribute} with the given name.
22.107 + */
22.108 + protected Attribute(String name) {
22.109 + this.name = name;
22.110 + if (this.getClass() == Attribute.class) {
22.111 + instanceMap.put(name, this);
22.112 + }
22.113 + }
22.114 +
22.115 + /**
22.116 + * Compares two objects for equality. This version only returns true
22.117 + * for <code>x.equals(y)</code> if <code>x</code> and <code>y</code> refer
22.118 + * to the same object, and guarantees this for all subclasses.
22.119 + */
22.120 + public final boolean equals(Object obj) {
22.121 + return super.equals(obj);
22.122 + }
22.123 +
22.124 + /**
22.125 + * Returns a hash code value for the object. This version is identical to
22.126 + * the one in {@code Object}, but is also final.
22.127 + */
22.128 + public final int hashCode() {
22.129 + return super.hashCode();
22.130 + }
22.131 +
22.132 + /**
22.133 + * Returns a string representation of the object. This version returns the
22.134 + * concatenation of class name, {@code "("}, a name identifying the attribute
22.135 + * and {@code ")"}.
22.136 + */
22.137 + public String toString() {
22.138 + return getClass().getName() + "(" + name + ")";
22.139 + }
22.140 +
22.141 + /**
22.142 + * Returns the name of the attribute.
22.143 + */
22.144 + protected String getName() {
22.145 + return name;
22.146 + }
22.147 +
22.148 + /**
22.149 + * Resolves instances being deserialized to the predefined constants.
22.150 + */
22.151 + protected Object readResolve() throws InvalidObjectException {
22.152 + if (this.getClass() != Attribute.class) {
22.153 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
22.154 + }
22.155 +
22.156 + Attribute instance = (Attribute) instanceMap.get(getName());
22.157 + if (instance != null) {
22.158 + return instance;
22.159 + } else {
22.160 + throw new InvalidObjectException("unknown attribute name");
22.161 + }
22.162 + }
22.163 +
22.164 + /**
22.165 + * Attribute key for the language of some text.
22.166 + * <p> Values are instances of {@link java.util.Locale Locale}.
22.167 + * @see java.util.Locale
22.168 + */
22.169 + public static final Attribute LANGUAGE = new Attribute("language");
22.170 +
22.171 + /**
22.172 + * Attribute key for the reading of some text. In languages where the written form
22.173 + * and the pronunciation of a word are only loosely related (such as Japanese),
22.174 + * it is often necessary to store the reading (pronunciation) along with the
22.175 + * written form.
22.176 + * <p>Values are instances of {@link Annotation} holding instances of {@link String}.
22.177 + * @see Annotation
22.178 + * @see java.lang.String
22.179 + */
22.180 + public static final Attribute READING = new Attribute("reading");
22.181 +
22.182 + /**
22.183 + * Attribute key for input method segments. Input methods often break
22.184 + * up text into segments, which usually correspond to words.
22.185 + * <p>Values are instances of {@link Annotation} holding a {@code null} reference.
22.186 + * @see Annotation
22.187 + */
22.188 + public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
22.189 +
22.190 + // make sure the serial version doesn't change between compiler versions
22.191 + private static final long serialVersionUID = -9142742483513960612L;
22.192 +
22.193 + };
22.194 +
22.195 + /**
22.196 + * Returns the index of the first character of the run
22.197 + * with respect to all attributes containing the current character.
22.198 + *
22.199 + * <p>Any contiguous text segments having the same attributes (the
22.200 + * same set of attribute/value pairs) are treated as separate runs
22.201 + * if the attributes have been given to those text segments separately.
22.202 + */
22.203 + public int getRunStart();
22.204 +
22.205 + /**
22.206 + * Returns the index of the first character of the run
22.207 + * with respect to the given {@code attribute} containing the current character.
22.208 + */
22.209 + public int getRunStart(Attribute attribute);
22.210 +
22.211 + /**
22.212 + * Returns the index of the first character of the run
22.213 + * with respect to the given {@code attributes} containing the current character.
22.214 + */
22.215 + public int getRunStart(Set<? extends Attribute> attributes);
22.216 +
22.217 + /**
22.218 + * Returns the index of the first character following the run
22.219 + * with respect to all attributes containing the current character.
22.220 + *
22.221 + * <p>Any contiguous text segments having the same attributes (the
22.222 + * same set of attribute/value pairs) are treated as separate runs
22.223 + * if the attributes have been given to those text segments separately.
22.224 + */
22.225 + public int getRunLimit();
22.226 +
22.227 + /**
22.228 + * Returns the index of the first character following the run
22.229 + * with respect to the given {@code attribute} containing the current character.
22.230 + */
22.231 + public int getRunLimit(Attribute attribute);
22.232 +
22.233 + /**
22.234 + * Returns the index of the first character following the run
22.235 + * with respect to the given {@code attributes} containing the current character.
22.236 + */
22.237 + public int getRunLimit(Set<? extends Attribute> attributes);
22.238 +
22.239 + /**
22.240 + * Returns a map with the attributes defined on the current
22.241 + * character.
22.242 + */
22.243 + public Map<Attribute,Object> getAttributes();
22.244 +
22.245 + /**
22.246 + * Returns the value of the named {@code attribute} for the current character.
22.247 + * Returns {@code null} if the {@code attribute} is not defined.
22.248 + */
22.249 + public Object getAttribute(Attribute attribute);
22.250 +
22.251 + /**
22.252 + * Returns the keys of all attributes defined on the
22.253 + * iterator's text range. The set is empty if no
22.254 + * attributes are defined.
22.255 + */
22.256 + public Set<Attribute> getAllAttributeKeys();
22.257 +};
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedString.java Thu Oct 03 15:43:10 2013 +0200
23.3 @@ -0,0 +1,1120 @@
23.4 +/*
23.5 + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
23.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
23.7 + *
23.8 + * This code is free software; you can redistribute it and/or modify it
23.9 + * under the terms of the GNU General Public License version 2 only, as
23.10 + * published by the Free Software Foundation. Oracle designates this
23.11 + * particular file as subject to the "Classpath" exception as provided
23.12 + * by Oracle in the LICENSE file that accompanied this code.
23.13 + *
23.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
23.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23.17 + * version 2 for more details (a copy is included in the LICENSE file that
23.18 + * accompanied this code).
23.19 + *
23.20 + * You should have received a copy of the GNU General Public License version
23.21 + * 2 along with this work; if not, write to the Free Software Foundation,
23.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23.23 + *
23.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23.25 + * or visit www.oracle.com if you need additional information or have any
23.26 + * questions.
23.27 + */
23.28 +
23.29 +package java.text;
23.30 +
23.31 +import java.util.*;
23.32 +import java.text.AttributedCharacterIterator.Attribute;
23.33 +
23.34 +/**
23.35 + * An AttributedString holds text and related attribute information. It
23.36 + * may be used as the actual data storage in some cases where a text
23.37 + * reader wants to access attributed text through the AttributedCharacterIterator
23.38 + * interface.
23.39 + *
23.40 + * <p>
23.41 + * An attribute is a key/value pair, identified by the key. No two
23.42 + * attributes on a given character can have the same key.
23.43 + *
23.44 + * <p>The values for an attribute are immutable, or must not be mutated
23.45 + * by clients or storage. They are always passed by reference, and not
23.46 + * cloned.
23.47 + *
23.48 + * @see AttributedCharacterIterator
23.49 + * @see Annotation
23.50 + * @since 1.2
23.51 + */
23.52 +
23.53 +public class AttributedString {
23.54 +
23.55 + // since there are no vectors of int, we have to use arrays.
23.56 + // We allocate them in chunks of 10 elements so we don't have to allocate all the time.
23.57 + private static final int ARRAY_SIZE_INCREMENT = 10;
23.58 +
23.59 + // field holding the text
23.60 + String text;
23.61 +
23.62 + // fields holding run attribute information
23.63 + // run attributes are organized by run
23.64 + int runArraySize; // current size of the arrays
23.65 + int runCount; // actual number of runs, <= runArraySize
23.66 + int runStarts[]; // start index for each run
23.67 + Vector runAttributes[]; // vector of attribute keys for each run
23.68 + Vector runAttributeValues[]; // parallel vector of attribute values for each run
23.69 +
23.70 + /**
23.71 + * Constructs an AttributedString instance with the given
23.72 + * AttributedCharacterIterators.
23.73 + *
23.74 + * @param iterators AttributedCharacterIterators to construct
23.75 + * AttributedString from.
23.76 + * @throws NullPointerException if iterators is null
23.77 + */
23.78 + AttributedString(AttributedCharacterIterator[] iterators) {
23.79 + if (iterators == null) {
23.80 + throw new NullPointerException("Iterators must not be null");
23.81 + }
23.82 + if (iterators.length == 0) {
23.83 + text = "";
23.84 + }
23.85 + else {
23.86 + // Build the String contents
23.87 + StringBuffer buffer = new StringBuffer();
23.88 + for (int counter = 0; counter < iterators.length; counter++) {
23.89 + appendContents(buffer, iterators[counter]);
23.90 + }
23.91 +
23.92 + text = buffer.toString();
23.93 +
23.94 + if (text.length() > 0) {
23.95 + // Determine the runs, creating a new run when the attributes
23.96 + // differ.
23.97 + int offset = 0;
23.98 + Map last = null;
23.99 +
23.100 + for (int counter = 0; counter < iterators.length; counter++) {
23.101 + AttributedCharacterIterator iterator = iterators[counter];
23.102 + int start = iterator.getBeginIndex();
23.103 + int end = iterator.getEndIndex();
23.104 + int index = start;
23.105 +
23.106 + while (index < end) {
23.107 + iterator.setIndex(index);
23.108 +
23.109 + Map attrs = iterator.getAttributes();
23.110 +
23.111 + if (mapsDiffer(last, attrs)) {
23.112 + setAttributes(attrs, index - start + offset);
23.113 + }
23.114 + last = attrs;
23.115 + index = iterator.getRunLimit();
23.116 + }
23.117 + offset += (end - start);
23.118 + }
23.119 + }
23.120 + }
23.121 + }
23.122 +
23.123 + /**
23.124 + * Constructs an AttributedString instance with the given text.
23.125 + * @param text The text for this attributed string.
23.126 + * @exception NullPointerException if <code>text</code> is null.
23.127 + */
23.128 + public AttributedString(String text) {
23.129 + if (text == null) {
23.130 + throw new NullPointerException();
23.131 + }
23.132 + this.text = text;
23.133 + }
23.134 +
23.135 + /**
23.136 + * Constructs an AttributedString instance with the given text and attributes.
23.137 + * @param text The text for this attributed string.
23.138 + * @param attributes The attributes that apply to the entire string.
23.139 + * @exception NullPointerException if <code>text</code> or
23.140 + * <code>attributes</code> is null.
23.141 + * @exception IllegalArgumentException if the text has length 0
23.142 + * and the attributes parameter is not an empty Map (attributes
23.143 + * cannot be applied to a 0-length range).
23.144 + */
23.145 + public AttributedString(String text,
23.146 + Map<? extends Attribute, ?> attributes)
23.147 + {
23.148 + if (text == null || attributes == null) {
23.149 + throw new NullPointerException();
23.150 + }
23.151 + this.text = text;
23.152 +
23.153 + if (text.length() == 0) {
23.154 + if (attributes.isEmpty())
23.155 + return;
23.156 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
23.157 + }
23.158 +
23.159 + int attributeCount = attributes.size();
23.160 + if (attributeCount > 0) {
23.161 + createRunAttributeDataVectors();
23.162 + Vector newRunAttributes = new Vector(attributeCount);
23.163 + Vector newRunAttributeValues = new Vector(attributeCount);
23.164 + runAttributes[0] = newRunAttributes;
23.165 + runAttributeValues[0] = newRunAttributeValues;
23.166 + Iterator iterator = attributes.entrySet().iterator();
23.167 + while (iterator.hasNext()) {
23.168 + Map.Entry entry = (Map.Entry) iterator.next();
23.169 + newRunAttributes.addElement(entry.getKey());
23.170 + newRunAttributeValues.addElement(entry.getValue());
23.171 + }
23.172 + }
23.173 + }
23.174 +
23.175 + /**
23.176 + * Constructs an AttributedString instance with the given attributed
23.177 + * text represented by AttributedCharacterIterator.
23.178 + * @param text The text for this attributed string.
23.179 + * @exception NullPointerException if <code>text</code> is null.
23.180 + */
23.181 + public AttributedString(AttributedCharacterIterator text) {
23.182 + // If performance is critical, this constructor should be
23.183 + // implemented here rather than invoking the constructor for a
23.184 + // subrange. We can avoid some range checking in the loops.
23.185 + this(text, text.getBeginIndex(), text.getEndIndex(), null);
23.186 + }
23.187 +
23.188 + /**
23.189 + * Constructs an AttributedString instance with the subrange of
23.190 + * the given attributed text represented by
23.191 + * AttributedCharacterIterator. If the given range produces an
23.192 + * empty text, all attributes will be discarded. Note that any
23.193 + * attributes wrapped by an Annotation object are discarded for a
23.194 + * subrange of the original attribute range.
23.195 + *
23.196 + * @param text The text for this attributed string.
23.197 + * @param beginIndex Index of the first character of the range.
23.198 + * @param endIndex Index of the character following the last character
23.199 + * of the range.
23.200 + * @exception NullPointerException if <code>text</code> is null.
23.201 + * @exception IllegalArgumentException if the subrange given by
23.202 + * beginIndex and endIndex is out of the text range.
23.203 + * @see java.text.Annotation
23.204 + */
23.205 + public AttributedString(AttributedCharacterIterator text,
23.206 + int beginIndex,
23.207 + int endIndex) {
23.208 + this(text, beginIndex, endIndex, null);
23.209 + }
23.210 +
23.211 + /**
23.212 + * Constructs an AttributedString instance with the subrange of
23.213 + * the given attributed text represented by
23.214 + * AttributedCharacterIterator. Only attributes that match the
23.215 + * given attributes will be incorporated into the instance. If the
23.216 + * given range produces an empty text, all attributes will be
23.217 + * discarded. Note that any attributes wrapped by an Annotation
23.218 + * object are discarded for a subrange of the original attribute
23.219 + * range.
23.220 + *
23.221 + * @param text The text for this attributed string.
23.222 + * @param beginIndex Index of the first character of the range.
23.223 + * @param endIndex Index of the character following the last character
23.224 + * of the range.
23.225 + * @param attributes Specifies attributes to be extracted
23.226 + * from the text. If null is specified, all available attributes will
23.227 + * be used.
23.228 + * @exception NullPointerException if <code>text</code> is null.
23.229 + * @exception IllegalArgumentException if the subrange given by
23.230 + * beginIndex and endIndex is out of the text range.
23.231 + * @see java.text.Annotation
23.232 + */
23.233 + public AttributedString(AttributedCharacterIterator text,
23.234 + int beginIndex,
23.235 + int endIndex,
23.236 + Attribute[] attributes) {
23.237 + if (text == null) {
23.238 + throw new NullPointerException();
23.239 + }
23.240 +
23.241 + // Validate the given subrange
23.242 + int textBeginIndex = text.getBeginIndex();
23.243 + int textEndIndex = text.getEndIndex();
23.244 + if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex)
23.245 + throw new IllegalArgumentException("Invalid substring range");
23.246 +
23.247 + // Copy the given string
23.248 + StringBuffer textBuffer = new StringBuffer();
23.249 + text.setIndex(beginIndex);
23.250 + for (char c = text.current(); text.getIndex() < endIndex; c = text.next())
23.251 + textBuffer.append(c);
23.252 + this.text = textBuffer.toString();
23.253 +
23.254 + if (beginIndex == endIndex)
23.255 + return;
23.256 +
23.257 + // Select attribute keys to be taken care of
23.258 + HashSet keys = new HashSet();
23.259 + if (attributes == null) {
23.260 + keys.addAll(text.getAllAttributeKeys());
23.261 + } else {
23.262 + for (int i = 0; i < attributes.length; i++)
23.263 + keys.add(attributes[i]);
23.264 + keys.retainAll(text.getAllAttributeKeys());
23.265 + }
23.266 + if (keys.isEmpty())
23.267 + return;
23.268 +
23.269 + // Get and set attribute runs for each attribute name. Need to
23.270 + // scan from the top of the text so that we can discard any
23.271 + // Annotation that is no longer applied to a subset text segment.
23.272 + Iterator itr = keys.iterator();
23.273 + while (itr.hasNext()) {
23.274 + Attribute attributeKey = (Attribute)itr.next();
23.275 + text.setIndex(textBeginIndex);
23.276 + while (text.getIndex() < endIndex) {
23.277 + int start = text.getRunStart(attributeKey);
23.278 + int limit = text.getRunLimit(attributeKey);
23.279 + Object value = text.getAttribute(attributeKey);
23.280 +
23.281 + if (value != null) {
23.282 + if (value instanceof Annotation) {
23.283 + if (start >= beginIndex && limit <= endIndex) {
23.284 + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
23.285 + } else {
23.286 + if (limit > endIndex)
23.287 + break;
23.288 + }
23.289 + } else {
23.290 + // if the run is beyond the given (subset) range, we
23.291 + // don't need to process further.
23.292 + if (start >= endIndex)
23.293 + break;
23.294 + if (limit > beginIndex) {
23.295 + // attribute is applied to any subrange
23.296 + if (start < beginIndex)
23.297 + start = beginIndex;
23.298 + if (limit > endIndex)
23.299 + limit = endIndex;
23.300 + if (start != limit) {
23.301 + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
23.302 + }
23.303 + }
23.304 + }
23.305 + }
23.306 + text.setIndex(limit);
23.307 + }
23.308 + }
23.309 + }
23.310 +
23.311 + /**
23.312 + * Adds an attribute to the entire string.
23.313 + * @param attribute the attribute key
23.314 + * @param value the value of the attribute; may be null
23.315 + * @exception NullPointerException if <code>attribute</code> is null.
23.316 + * @exception IllegalArgumentException if the AttributedString has length 0
23.317 + * (attributes cannot be applied to a 0-length range).
23.318 + */
23.319 + public void addAttribute(Attribute attribute, Object value) {
23.320 +
23.321 + if (attribute == null) {
23.322 + throw new NullPointerException();
23.323 + }
23.324 +
23.325 + int len = length();
23.326 + if (len == 0) {
23.327 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
23.328 + }
23.329 +
23.330 + addAttributeImpl(attribute, value, 0, len);
23.331 + }
23.332 +
23.333 + /**
23.334 + * Adds an attribute to a subrange of the string.
23.335 + * @param attribute the attribute key
23.336 + * @param value The value of the attribute. May be null.
23.337 + * @param beginIndex Index of the first character of the range.
23.338 + * @param endIndex Index of the character following the last character of the range.
23.339 + * @exception NullPointerException if <code>attribute</code> is null.
23.340 + * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
23.341 + * greater than the length of the string, or beginIndex and endIndex together don't
23.342 + * define a non-empty subrange of the string.
23.343 + */
23.344 + public void addAttribute(Attribute attribute, Object value,
23.345 + int beginIndex, int endIndex) {
23.346 +
23.347 + if (attribute == null) {
23.348 + throw new NullPointerException();
23.349 + }
23.350 +
23.351 + if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) {
23.352 + throw new IllegalArgumentException("Invalid substring range");
23.353 + }
23.354 +
23.355 + addAttributeImpl(attribute, value, beginIndex, endIndex);
23.356 + }
23.357 +
23.358 + /**
23.359 + * Adds a set of attributes to a subrange of the string.
23.360 + * @param attributes The attributes to be added to the string.
23.361 + * @param beginIndex Index of the first character of the range.
23.362 + * @param endIndex Index of the character following the last
23.363 + * character of the range.
23.364 + * @exception NullPointerException if <code>attributes</code> is null.
23.365 + * @exception IllegalArgumentException if beginIndex is less then
23.366 + * 0, endIndex is greater than the length of the string, or
23.367 + * beginIndex and endIndex together don't define a non-empty
23.368 + * subrange of the string and the attributes parameter is not an
23.369 + * empty Map.
23.370 + */
23.371 + public void addAttributes(Map<? extends Attribute, ?> attributes,
23.372 + int beginIndex, int endIndex)
23.373 + {
23.374 + if (attributes == null) {
23.375 + throw new NullPointerException();
23.376 + }
23.377 +
23.378 + if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
23.379 + throw new IllegalArgumentException("Invalid substring range");
23.380 + }
23.381 + if (beginIndex == endIndex) {
23.382 + if (attributes.isEmpty())
23.383 + return;
23.384 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
23.385 + }
23.386 +
23.387 + // make sure we have run attribute data vectors
23.388 + if (runCount == 0) {
23.389 + createRunAttributeDataVectors();
23.390 + }
23.391 +
23.392 + // break up runs if necessary
23.393 + int beginRunIndex = ensureRunBreak(beginIndex);
23.394 + int endRunIndex = ensureRunBreak(endIndex);
23.395 +
23.396 + Iterator iterator = attributes.entrySet().iterator();
23.397 + while (iterator.hasNext()) {
23.398 + Map.Entry entry = (Map.Entry) iterator.next();
23.399 + addAttributeRunData((Attribute) entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex);
23.400 + }
23.401 + }
23.402 +
23.403 + private synchronized void addAttributeImpl(Attribute attribute, Object value,
23.404 + int beginIndex, int endIndex) {
23.405 +
23.406 + // make sure we have run attribute data vectors
23.407 + if (runCount == 0) {
23.408 + createRunAttributeDataVectors();
23.409 + }
23.410 +
23.411 + // break up runs if necessary
23.412 + int beginRunIndex = ensureRunBreak(beginIndex);
23.413 + int endRunIndex = ensureRunBreak(endIndex);
23.414 +
23.415 + addAttributeRunData(attribute, value, beginRunIndex, endRunIndex);
23.416 + }
23.417 +
23.418 + private final void createRunAttributeDataVectors() {
23.419 + // use temporary variables so things remain consistent in case of an exception
23.420 + int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
23.421 + Vector newRunAttributes[] = new Vector[ARRAY_SIZE_INCREMENT];
23.422 + Vector newRunAttributeValues[] = new Vector[ARRAY_SIZE_INCREMENT];
23.423 + runStarts = newRunStarts;
23.424 + runAttributes = newRunAttributes;
23.425 + runAttributeValues = newRunAttributeValues;
23.426 + runArraySize = ARRAY_SIZE_INCREMENT;
23.427 + runCount = 1; // assume initial run starting at index 0
23.428 + }
23.429 +
23.430 + // ensure there's a run break at offset, return the index of the run
23.431 + private final int ensureRunBreak(int offset) {
23.432 + return ensureRunBreak(offset, true);
23.433 + }
23.434 +
23.435 + /**
23.436 + * Ensures there is a run break at offset, returning the index of
23.437 + * the run. If this results in splitting a run, two things can happen:
23.438 + * <ul>
23.439 + * <li>If copyAttrs is true, the attributes from the existing run
23.440 + * will be placed in both of the newly created runs.
23.441 + * <li>If copyAttrs is false, the attributes from the existing run
23.442 + * will NOT be copied to the run to the right (>= offset) of the break,
23.443 + * but will exist on the run to the left (< offset).
23.444 + * </ul>
23.445 + */
23.446 + private final int ensureRunBreak(int offset, boolean copyAttrs) {
23.447 + if (offset == length()) {
23.448 + return runCount;
23.449 + }
23.450 +
23.451 + // search for the run index where this offset should be
23.452 + int runIndex = 0;
23.453 + while (runIndex < runCount && runStarts[runIndex] < offset) {
23.454 + runIndex++;
23.455 + }
23.456 +
23.457 + // if the offset is at a run start already, we're done
23.458 + if (runIndex < runCount && runStarts[runIndex] == offset) {
23.459 + return runIndex;
23.460 + }
23.461 +
23.462 + // we'll have to break up a run
23.463 + // first, make sure we have enough space in our arrays
23.464 + if (runCount == runArraySize) {
23.465 + int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT;
23.466 + int newRunStarts[] = new int[newArraySize];
23.467 + Vector newRunAttributes[] = new Vector[newArraySize];
23.468 + Vector newRunAttributeValues[] = new Vector[newArraySize];
23.469 + for (int i = 0; i < runArraySize; i++) {
23.470 + newRunStarts[i] = runStarts[i];
23.471 + newRunAttributes[i] = runAttributes[i];
23.472 + newRunAttributeValues[i] = runAttributeValues[i];
23.473 + }
23.474 + runStarts = newRunStarts;
23.475 + runAttributes = newRunAttributes;
23.476 + runAttributeValues = newRunAttributeValues;
23.477 + runArraySize = newArraySize;
23.478 + }
23.479 +
23.480 + // make copies of the attribute information of the old run that the new one used to be part of
23.481 + // use temporary variables so things remain consistent in case of an exception
23.482 + Vector newRunAttributes = null;
23.483 + Vector newRunAttributeValues = null;
23.484 +
23.485 + if (copyAttrs) {
23.486 + Vector oldRunAttributes = runAttributes[runIndex - 1];
23.487 + Vector oldRunAttributeValues = runAttributeValues[runIndex - 1];
23.488 + if (oldRunAttributes != null) {
23.489 + newRunAttributes = (Vector) oldRunAttributes.clone();
23.490 + }
23.491 + if (oldRunAttributeValues != null) {
23.492 + newRunAttributeValues = (Vector) oldRunAttributeValues.clone();
23.493 + }
23.494 + }
23.495 +
23.496 + // now actually break up the run
23.497 + runCount++;
23.498 + for (int i = runCount - 1; i > runIndex; i--) {
23.499 + runStarts[i] = runStarts[i - 1];
23.500 + runAttributes[i] = runAttributes[i - 1];
23.501 + runAttributeValues[i] = runAttributeValues[i - 1];
23.502 + }
23.503 + runStarts[runIndex] = offset;
23.504 + runAttributes[runIndex] = newRunAttributes;
23.505 + runAttributeValues[runIndex] = newRunAttributeValues;
23.506 +
23.507 + return runIndex;
23.508 + }
23.509 +
23.510 + // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex
23.511 + private void addAttributeRunData(Attribute attribute, Object value,
23.512 + int beginRunIndex, int endRunIndex) {
23.513 +
23.514 + for (int i = beginRunIndex; i < endRunIndex; i++) {
23.515 + int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet
23.516 + if (runAttributes[i] == null) {
23.517 + Vector newRunAttributes = new Vector();
23.518 + Vector newRunAttributeValues = new Vector();
23.519 + runAttributes[i] = newRunAttributes;
23.520 + runAttributeValues[i] = newRunAttributeValues;
23.521 + } else {
23.522 + // check whether we have an entry already
23.523 + keyValueIndex = runAttributes[i].indexOf(attribute);
23.524 + }
23.525 +
23.526 + if (keyValueIndex == -1) {
23.527 + // create new entry
23.528 + int oldSize = runAttributes[i].size();
23.529 + runAttributes[i].addElement(attribute);
23.530 + try {
23.531 + runAttributeValues[i].addElement(value);
23.532 + }
23.533 + catch (Exception e) {
23.534 + runAttributes[i].setSize(oldSize);
23.535 + runAttributeValues[i].setSize(oldSize);
23.536 + }
23.537 + } else {
23.538 + // update existing entry
23.539 + runAttributeValues[i].set(keyValueIndex, value);
23.540 + }
23.541 + }
23.542 + }
23.543 +
23.544 + /**
23.545 + * Creates an AttributedCharacterIterator instance that provides access to the entire contents of
23.546 + * this string.
23.547 + *
23.548 + * @return An iterator providing access to the text and its attributes.
23.549 + */
23.550 + public AttributedCharacterIterator getIterator() {
23.551 + return getIterator(null, 0, length());
23.552 + }
23.553 +
23.554 + /**
23.555 + * Creates an AttributedCharacterIterator instance that provides access to
23.556 + * selected contents of this string.
23.557 + * Information about attributes not listed in attributes that the
23.558 + * implementor may have need not be made accessible through the iterator.
23.559 + * If the list is null, all available attribute information should be made
23.560 + * accessible.
23.561 + *
23.562 + * @param attributes a list of attributes that the client is interested in
23.563 + * @return an iterator providing access to the entire text and its selected attributes
23.564 + */
23.565 + public AttributedCharacterIterator getIterator(Attribute[] attributes) {
23.566 + return getIterator(attributes, 0, length());
23.567 + }
23.568 +
23.569 + /**
23.570 + * Creates an AttributedCharacterIterator instance that provides access to
23.571 + * selected contents of this string.
23.572 + * Information about attributes not listed in attributes that the
23.573 + * implementor may have need not be made accessible through the iterator.
23.574 + * If the list is null, all available attribute information should be made
23.575 + * accessible.
23.576 + *
23.577 + * @param attributes a list of attributes that the client is interested in
23.578 + * @param beginIndex the index of the first character
23.579 + * @param endIndex the index of the character following the last character
23.580 + * @return an iterator providing access to the text and its attributes
23.581 + * @exception IllegalArgumentException if beginIndex is less then 0,
23.582 + * endIndex is greater than the length of the string, or beginIndex is
23.583 + * greater than endIndex.
23.584 + */
23.585 + public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
23.586 + return new AttributedStringIterator(attributes, beginIndex, endIndex);
23.587 + }
23.588 +
23.589 + // all (with the exception of length) reading operations are private,
23.590 + // since AttributedString instances are accessed through iterators.
23.591 +
23.592 + // length is package private so that CharacterIteratorFieldDelegate can
23.593 + // access it without creating an AttributedCharacterIterator.
23.594 + int length() {
23.595 + return text.length();
23.596 + }
23.597 +
23.598 + private char charAt(int index) {
23.599 + return text.charAt(index);
23.600 + }
23.601 +
23.602 + private synchronized Object getAttribute(Attribute attribute, int runIndex) {
23.603 + Vector currentRunAttributes = runAttributes[runIndex];
23.604 + Vector currentRunAttributeValues = runAttributeValues[runIndex];
23.605 + if (currentRunAttributes == null) {
23.606 + return null;
23.607 + }
23.608 + int attributeIndex = currentRunAttributes.indexOf(attribute);
23.609 + if (attributeIndex != -1) {
23.610 + return currentRunAttributeValues.elementAt(attributeIndex);
23.611 + }
23.612 + else {
23.613 + return null;
23.614 + }
23.615 + }
23.616 +
23.617 + // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
23.618 + private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
23.619 + Object value = getAttribute(attribute, runIndex);
23.620 + if (value instanceof Annotation) {
23.621 + // need to check whether the annotation's range extends outside the iterator's range
23.622 + if (beginIndex > 0) {
23.623 + int currIndex = runIndex;
23.624 + int runStart = runStarts[currIndex];
23.625 + while (runStart >= beginIndex &&
23.626 + valuesMatch(value, getAttribute(attribute, currIndex - 1))) {
23.627 + currIndex--;
23.628 + runStart = runStarts[currIndex];
23.629 + }
23.630 + if (runStart < beginIndex) {
23.631 + // annotation's range starts before iterator's range
23.632 + return null;
23.633 + }
23.634 + }
23.635 + int textLength = length();
23.636 + if (endIndex < textLength) {
23.637 + int currIndex = runIndex;
23.638 + int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
23.639 + while (runLimit <= endIndex &&
23.640 + valuesMatch(value, getAttribute(attribute, currIndex + 1))) {
23.641 + currIndex++;
23.642 + runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
23.643 + }
23.644 + if (runLimit > endIndex) {
23.645 + // annotation's range ends after iterator's range
23.646 + return null;
23.647 + }
23.648 + }
23.649 + // annotation's range is subrange of iterator's range,
23.650 + // so we can return the value
23.651 + }
23.652 + return value;
23.653 + }
23.654 +
23.655 + // returns whether all specified attributes have equal values in the runs with the given indices
23.656 + private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) {
23.657 + Iterator iterator = attributes.iterator();
23.658 + while (iterator.hasNext()) {
23.659 + Attribute key = (Attribute) iterator.next();
23.660 + if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) {
23.661 + return false;
23.662 + }
23.663 + }
23.664 + return true;
23.665 + }
23.666 +
23.667 + // returns whether the two objects are either both null or equal
23.668 + private final static boolean valuesMatch(Object value1, Object value2) {
23.669 + if (value1 == null) {
23.670 + return value2 == null;
23.671 + } else {
23.672 + return value1.equals(value2);
23.673 + }
23.674 + }
23.675 +
23.676 + /**
23.677 + * Appends the contents of the CharacterIterator iterator into the
23.678 + * StringBuffer buf.
23.679 + */
23.680 + private final void appendContents(StringBuffer buf,
23.681 + CharacterIterator iterator) {
23.682 + int index = iterator.getBeginIndex();
23.683 + int end = iterator.getEndIndex();
23.684 +
23.685 + while (index < end) {
23.686 + iterator.setIndex(index++);
23.687 + buf.append(iterator.current());
23.688 + }
23.689 + }
23.690 +
23.691 + /**
23.692 + * Sets the attributes for the range from offset to the next run break
23.693 + * (typically the end of the text) to the ones specified in attrs.
23.694 + * This is only meant to be called from the constructor!
23.695 + */
23.696 + private void setAttributes(Map attrs, int offset) {
23.697 + if (runCount == 0) {
23.698 + createRunAttributeDataVectors();
23.699 + }
23.700 +
23.701 + int index = ensureRunBreak(offset, false);
23.702 + int size;
23.703 +
23.704 + if (attrs != null && (size = attrs.size()) > 0) {
23.705 + Vector runAttrs = new Vector(size);
23.706 + Vector runValues = new Vector(size);
23.707 + Iterator iterator = attrs.entrySet().iterator();
23.708 +
23.709 + while (iterator.hasNext()) {
23.710 + Map.Entry entry = (Map.Entry)iterator.next();
23.711 +
23.712 + runAttrs.add(entry.getKey());
23.713 + runValues.add(entry.getValue());
23.714 + }
23.715 + runAttributes[index] = runAttrs;
23.716 + runAttributeValues[index] = runValues;
23.717 + }
23.718 + }
23.719 +
23.720 + /**
23.721 + * Returns true if the attributes specified in last and attrs differ.
23.722 + */
23.723 + private static boolean mapsDiffer(Map last, Map attrs) {
23.724 + if (last == null) {
23.725 + return (attrs != null && attrs.size() > 0);
23.726 + }
23.727 + return (!last.equals(attrs));
23.728 + }
23.729 +
23.730 +
23.731 + // the iterator class associated with this string class
23.732 +
23.733 + final private class AttributedStringIterator implements AttributedCharacterIterator {
23.734 +
23.735 + // note on synchronization:
23.736 + // we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
23.737 + // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
23.738 +
23.739 + // start and end index for our iteration
23.740 + private int beginIndex;
23.741 + private int endIndex;
23.742 +
23.743 + // attributes that our client is interested in
23.744 + private Attribute[] relevantAttributes;
23.745 +
23.746 + // the current index for our iteration
23.747 + // invariant: beginIndex <= currentIndex <= endIndex
23.748 + private int currentIndex;
23.749 +
23.750 + // information about the run that includes currentIndex
23.751 + private int currentRunIndex;
23.752 + private int currentRunStart;
23.753 + private int currentRunLimit;
23.754 +
23.755 + // constructor
23.756 + AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) {
23.757 +
23.758 + if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
23.759 + throw new IllegalArgumentException("Invalid substring range");
23.760 + }
23.761 +
23.762 + this.beginIndex = beginIndex;
23.763 + this.endIndex = endIndex;
23.764 + this.currentIndex = beginIndex;
23.765 + updateRunInfo();
23.766 + if (attributes != null) {
23.767 + relevantAttributes = (Attribute[]) attributes.clone();
23.768 + }
23.769 + }
23.770 +
23.771 + // Object methods. See documentation in that class.
23.772 +
23.773 + public boolean equals(Object obj) {
23.774 + if (this == obj) {
23.775 + return true;
23.776 + }
23.777 + if (!(obj instanceof AttributedStringIterator)) {
23.778 + return false;
23.779 + }
23.780 +
23.781 + AttributedStringIterator that = (AttributedStringIterator) obj;
23.782 +
23.783 + if (AttributedString.this != that.getString())
23.784 + return false;
23.785 + if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
23.786 + return false;
23.787 + return true;
23.788 + }
23.789 +
23.790 + public int hashCode() {
23.791 + return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex;
23.792 + }
23.793 +
23.794 + public Object clone() {
23.795 + try {
23.796 + AttributedStringIterator other = (AttributedStringIterator) super.clone();
23.797 + return other;
23.798 + }
23.799 + catch (CloneNotSupportedException e) {
23.800 + throw new InternalError();
23.801 + }
23.802 + }
23.803 +
23.804 + // CharacterIterator methods. See documentation in that interface.
23.805 +
23.806 + public char first() {
23.807 + return internalSetIndex(beginIndex);
23.808 + }
23.809 +
23.810 + public char last() {
23.811 + if (endIndex == beginIndex) {
23.812 + return internalSetIndex(endIndex);
23.813 + } else {
23.814 + return internalSetIndex(endIndex - 1);
23.815 + }
23.816 + }
23.817 +
23.818 + public char current() {
23.819 + if (currentIndex == endIndex) {
23.820 + return DONE;
23.821 + } else {
23.822 + return charAt(currentIndex);
23.823 + }
23.824 + }
23.825 +
23.826 + public char next() {
23.827 + if (currentIndex < endIndex) {
23.828 + return internalSetIndex(currentIndex + 1);
23.829 + }
23.830 + else {
23.831 + return DONE;
23.832 + }
23.833 + }
23.834 +
23.835 + public char previous() {
23.836 + if (currentIndex > beginIndex) {
23.837 + return internalSetIndex(currentIndex - 1);
23.838 + }
23.839 + else {
23.840 + return DONE;
23.841 + }
23.842 + }
23.843 +
23.844 + public char setIndex(int position) {
23.845 + if (position < beginIndex || position > endIndex)
23.846 + throw new IllegalArgumentException("Invalid index");
23.847 + return internalSetIndex(position);
23.848 + }
23.849 +
23.850 + public int getBeginIndex() {
23.851 + return beginIndex;
23.852 + }
23.853 +
23.854 + public int getEndIndex() {
23.855 + return endIndex;
23.856 + }
23.857 +
23.858 + public int getIndex() {
23.859 + return currentIndex;
23.860 + }
23.861 +
23.862 + // AttributedCharacterIterator methods. See documentation in that interface.
23.863 +
23.864 + public int getRunStart() {
23.865 + return currentRunStart;
23.866 + }
23.867 +
23.868 + public int getRunStart(Attribute attribute) {
23.869 + if (currentRunStart == beginIndex || currentRunIndex == -1) {
23.870 + return currentRunStart;
23.871 + } else {
23.872 + Object value = getAttribute(attribute);
23.873 + int runStart = currentRunStart;
23.874 + int runIndex = currentRunIndex;
23.875 + while (runStart > beginIndex &&
23.876 + valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) {
23.877 + runIndex--;
23.878 + runStart = runStarts[runIndex];
23.879 + }
23.880 + if (runStart < beginIndex) {
23.881 + runStart = beginIndex;
23.882 + }
23.883 + return runStart;
23.884 + }
23.885 + }
23.886 +
23.887 + public int getRunStart(Set<? extends Attribute> attributes) {
23.888 + if (currentRunStart == beginIndex || currentRunIndex == -1) {
23.889 + return currentRunStart;
23.890 + } else {
23.891 + int runStart = currentRunStart;
23.892 + int runIndex = currentRunIndex;
23.893 + while (runStart > beginIndex &&
23.894 + AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) {
23.895 + runIndex--;
23.896 + runStart = runStarts[runIndex];
23.897 + }
23.898 + if (runStart < beginIndex) {
23.899 + runStart = beginIndex;
23.900 + }
23.901 + return runStart;
23.902 + }
23.903 + }
23.904 +
23.905 + public int getRunLimit() {
23.906 + return currentRunLimit;
23.907 + }
23.908 +
23.909 + public int getRunLimit(Attribute attribute) {
23.910 + if (currentRunLimit == endIndex || currentRunIndex == -1) {
23.911 + return currentRunLimit;
23.912 + } else {
23.913 + Object value = getAttribute(attribute);
23.914 + int runLimit = currentRunLimit;
23.915 + int runIndex = currentRunIndex;
23.916 + while (runLimit < endIndex &&
23.917 + valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) {
23.918 + runIndex++;
23.919 + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
23.920 + }
23.921 + if (runLimit > endIndex) {
23.922 + runLimit = endIndex;
23.923 + }
23.924 + return runLimit;
23.925 + }
23.926 + }
23.927 +
23.928 + public int getRunLimit(Set<? extends Attribute> attributes) {
23.929 + if (currentRunLimit == endIndex || currentRunIndex == -1) {
23.930 + return currentRunLimit;
23.931 + } else {
23.932 + int runLimit = currentRunLimit;
23.933 + int runIndex = currentRunIndex;
23.934 + while (runLimit < endIndex &&
23.935 + AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) {
23.936 + runIndex++;
23.937 + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
23.938 + }
23.939 + if (runLimit > endIndex) {
23.940 + runLimit = endIndex;
23.941 + }
23.942 + return runLimit;
23.943 + }
23.944 + }
23.945 +
23.946 + public Map<Attribute,Object> getAttributes() {
23.947 + if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) {
23.948 + // ??? would be nice to return null, but current spec doesn't allow it
23.949 + // returning Hashtable saves AttributeMap from dealing with emptiness
23.950 + return new Hashtable();
23.951 + }
23.952 + return new AttributeMap(currentRunIndex, beginIndex, endIndex);
23.953 + }
23.954 +
23.955 + public Set<Attribute> getAllAttributeKeys() {
23.956 + // ??? This should screen out attribute keys that aren't relevant to the client
23.957 + if (runAttributes == null) {
23.958 + // ??? would be nice to return null, but current spec doesn't allow it
23.959 + // returning HashSet saves us from dealing with emptiness
23.960 + return new HashSet();
23.961 + }
23.962 + synchronized (AttributedString.this) {
23.963 + // ??? should try to create this only once, then update if necessary,
23.964 + // and give callers read-only view
23.965 + Set keys = new HashSet();
23.966 + int i = 0;
23.967 + while (i < runCount) {
23.968 + if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) {
23.969 + Vector currentRunAttributes = runAttributes[i];
23.970 + if (currentRunAttributes != null) {
23.971 + int j = currentRunAttributes.size();
23.972 + while (j-- > 0) {
23.973 + keys.add(currentRunAttributes.get(j));
23.974 + }
23.975 + }
23.976 + }
23.977 + i++;
23.978 + }
23.979 + return keys;
23.980 + }
23.981 + }
23.982 +
23.983 + public Object getAttribute(Attribute attribute) {
23.984 + int runIndex = currentRunIndex;
23.985 + if (runIndex < 0) {
23.986 + return null;
23.987 + }
23.988 + return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex);
23.989 + }
23.990 +
23.991 + // internally used methods
23.992 +
23.993 + private AttributedString getString() {
23.994 + return AttributedString.this;
23.995 + }
23.996 +
23.997 + // set the current index, update information about the current run if necessary,
23.998 + // return the character at the current index
23.999 + private char internalSetIndex(int position) {
23.1000 + currentIndex = position;
23.1001 + if (position < currentRunStart || position >= currentRunLimit) {
23.1002 + updateRunInfo();
23.1003 + }
23.1004 + if (currentIndex == endIndex) {
23.1005 + return DONE;
23.1006 + } else {
23.1007 + return charAt(position);
23.1008 + }
23.1009 + }
23.1010 +
23.1011 + // update the information about the current run
23.1012 + private void updateRunInfo() {
23.1013 + if (currentIndex == endIndex) {
23.1014 + currentRunStart = currentRunLimit = endIndex;
23.1015 + currentRunIndex = -1;
23.1016 + } else {
23.1017 + synchronized (AttributedString.this) {
23.1018 + int runIndex = -1;
23.1019 + while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex)
23.1020 + runIndex++;
23.1021 + currentRunIndex = runIndex;
23.1022 + if (runIndex >= 0) {
23.1023 + currentRunStart = runStarts[runIndex];
23.1024 + if (currentRunStart < beginIndex)
23.1025 + currentRunStart = beginIndex;
23.1026 + }
23.1027 + else {
23.1028 + currentRunStart = beginIndex;
23.1029 + }
23.1030 + if (runIndex < runCount - 1) {
23.1031 + currentRunLimit = runStarts[runIndex + 1];
23.1032 + if (currentRunLimit > endIndex)
23.1033 + currentRunLimit = endIndex;
23.1034 + }
23.1035 + else {
23.1036 + currentRunLimit = endIndex;
23.1037 + }
23.1038 + }
23.1039 + }
23.1040 + }
23.1041 +
23.1042 + }
23.1043 +
23.1044 + // the map class associated with this string class, giving access to the attributes of one run
23.1045 +
23.1046 + final private class AttributeMap extends AbstractMap<Attribute,Object> {
23.1047 +
23.1048 + int runIndex;
23.1049 + int beginIndex;
23.1050 + int endIndex;
23.1051 +
23.1052 + AttributeMap(int runIndex, int beginIndex, int endIndex) {
23.1053 + this.runIndex = runIndex;
23.1054 + this.beginIndex = beginIndex;
23.1055 + this.endIndex = endIndex;
23.1056 + }
23.1057 +
23.1058 + public Set entrySet() {
23.1059 + HashSet set = new HashSet();
23.1060 + synchronized (AttributedString.this) {
23.1061 + int size = runAttributes[runIndex].size();
23.1062 + for (int i = 0; i < size; i++) {
23.1063 + Attribute key = (Attribute) runAttributes[runIndex].get(i);
23.1064 + Object value = runAttributeValues[runIndex].get(i);
23.1065 + if (value instanceof Annotation) {
23.1066 + value = AttributedString.this.getAttributeCheckRange(key,
23.1067 + runIndex, beginIndex, endIndex);
23.1068 + if (value == null) {
23.1069 + continue;
23.1070 + }
23.1071 + }
23.1072 + Map.Entry entry = new AttributeEntry(key, value);
23.1073 + set.add(entry);
23.1074 + }
23.1075 + }
23.1076 + return set;
23.1077 + }
23.1078 +
23.1079 + public Object get(Object key) {
23.1080 + return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
23.1081 + }
23.1082 + }
23.1083 +}
23.1084 +
23.1085 +class AttributeEntry implements Map.Entry {
23.1086 +
23.1087 + private Attribute key;
23.1088 + private Object value;
23.1089 +
23.1090 + AttributeEntry(Attribute key, Object value) {
23.1091 + this.key = key;
23.1092 + this.value = value;
23.1093 + }
23.1094 +
23.1095 + public boolean equals(Object o) {
23.1096 + if (!(o instanceof AttributeEntry)) {
23.1097 + return false;
23.1098 + }
23.1099 + AttributeEntry other = (AttributeEntry) o;
23.1100 + return other.key.equals(key) &&
23.1101 + (value == null ? other.value == null : other.value.equals(value));
23.1102 + }
23.1103 +
23.1104 + public Object getKey() {
23.1105 + return key;
23.1106 + }
23.1107 +
23.1108 + public Object getValue() {
23.1109 + return value;
23.1110 + }
23.1111 +
23.1112 + public Object setValue(Object newValue) {
23.1113 + throw new UnsupportedOperationException();
23.1114 + }
23.1115 +
23.1116 + public int hashCode() {
23.1117 + return key.hashCode() ^ (value==null ? 0 : value.hashCode());
23.1118 + }
23.1119 +
23.1120 + public String toString() {
23.1121 + return key.toString()+"="+value.toString();
23.1122 + }
23.1123 +}
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/rt/emul/compact/src/main/java/java/text/CalendarBuilder.java Thu Oct 03 15:43:10 2013 +0200
24.3 @@ -0,0 +1,170 @@
24.4 +/*
24.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
24.7 + *
24.8 + * This code is free software; you can redistribute it and/or modify it
24.9 + * under the terms of the GNU General Public License version 2 only, as
24.10 + * published by the Free Software Foundation. Oracle designates this
24.11 + * particular file as subject to the "Classpath" exception as provided
24.12 + * by Oracle in the LICENSE file that accompanied this code.
24.13 + *
24.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
24.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24.17 + * version 2 for more details (a copy is included in the LICENSE file that
24.18 + * accompanied this code).
24.19 + *
24.20 + * You should have received a copy of the GNU General Public License version
24.21 + * 2 along with this work; if not, write to the Free Software Foundation,
24.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24.23 + *
24.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
24.25 + * or visit www.oracle.com if you need additional information or have any
24.26 + * questions.
24.27 + */
24.28 +
24.29 +package java.text;
24.30 +
24.31 +import java.util.Calendar;
24.32 +import static java.util.GregorianCalendar.*;
24.33 +
24.34 +/**
24.35 + * {@code CalendarBuilder} keeps field-value pairs for setting
24.36 + * the calendar fields of the given {@code Calendar}. It has the
24.37 + * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
24.38 + * support. Also {@code ISO_DAY_OF_WEEK} is used to specify
24.39 + * {@code DAY_OF_WEEK} in the ISO day of week numbering.
24.40 + *
24.41 + * <p>{@code CalendarBuilder} retains the semantic of the pseudo
24.42 + * timestamp for fields. {@code CalendarBuilder} uses a single
24.43 + * int array combining fields[] and stamp[] of {@code Calendar}.
24.44 + *
24.45 + * @author Masayoshi Okutsu
24.46 + */
24.47 +class CalendarBuilder {
24.48 + /*
24.49 + * Pseudo time stamp constants used in java.util.Calendar
24.50 + */
24.51 + private static final int UNSET = 0;
24.52 + private static final int COMPUTED = 1;
24.53 + private static final int MINIMUM_USER_STAMP = 2;
24.54 +
24.55 + private static final int MAX_FIELD = FIELD_COUNT + 1;
24.56 +
24.57 + public static final int WEEK_YEAR = FIELD_COUNT;
24.58 + public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
24.59 +
24.60 + // stamp[] (lower half) and field[] (upper half) combined
24.61 + private final int[] field;
24.62 + private int nextStamp;
24.63 + private int maxFieldIndex;
24.64 +
24.65 + CalendarBuilder() {
24.66 + field = new int[MAX_FIELD * 2];
24.67 + nextStamp = MINIMUM_USER_STAMP;
24.68 + maxFieldIndex = -1;
24.69 + }
24.70 +
24.71 + CalendarBuilder set(int index, int value) {
24.72 + if (index == ISO_DAY_OF_WEEK) {
24.73 + index = DAY_OF_WEEK;
24.74 + value = toCalendarDayOfWeek(value);
24.75 + }
24.76 + field[index] = nextStamp++;
24.77 + field[MAX_FIELD + index] = value;
24.78 + if (index > maxFieldIndex && index < FIELD_COUNT) {
24.79 + maxFieldIndex = index;
24.80 + }
24.81 + return this;
24.82 + }
24.83 +
24.84 + CalendarBuilder addYear(int value) {
24.85 + field[MAX_FIELD + YEAR] += value;
24.86 + field[MAX_FIELD + WEEK_YEAR] += value;
24.87 + return this;
24.88 + }
24.89 +
24.90 + boolean isSet(int index) {
24.91 + if (index == ISO_DAY_OF_WEEK) {
24.92 + index = DAY_OF_WEEK;
24.93 + }
24.94 + return field[index] > UNSET;
24.95 + }
24.96 +
24.97 + Calendar establish(Calendar cal) {
24.98 + boolean weekDate = isSet(WEEK_YEAR)
24.99 + && field[WEEK_YEAR] > field[YEAR];
24.100 + if (weekDate && !cal.isWeekDateSupported()) {
24.101 + // Use YEAR instead
24.102 + if (!isSet(YEAR)) {
24.103 + set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
24.104 + }
24.105 + weekDate = false;
24.106 + }
24.107 +
24.108 + cal.clear();
24.109 + // Set the fields from the min stamp to the max stamp so that
24.110 + // the field resolution works in the Calendar.
24.111 + for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
24.112 + for (int index = 0; index <= maxFieldIndex; index++) {
24.113 + if (field[index] == stamp) {
24.114 + cal.set(index, field[MAX_FIELD + index]);
24.115 + break;
24.116 + }
24.117 + }
24.118 + }
24.119 +
24.120 + if (weekDate) {
24.121 + int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
24.122 + int dayOfWeek = isSet(DAY_OF_WEEK) ?
24.123 + field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
24.124 + if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
24.125 + if (dayOfWeek >= 8) {
24.126 + dayOfWeek--;
24.127 + weekOfYear += dayOfWeek / 7;
24.128 + dayOfWeek = (dayOfWeek % 7) + 1;
24.129 + } else {
24.130 + while (dayOfWeek <= 0) {
24.131 + dayOfWeek += 7;
24.132 + weekOfYear--;
24.133 + }
24.134 + }
24.135 + dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
24.136 + }
24.137 + cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
24.138 + }
24.139 + return cal;
24.140 + }
24.141 +
24.142 + public String toString() {
24.143 + StringBuilder sb = new StringBuilder();
24.144 + sb.append("CalendarBuilder:[");
24.145 + for (int i = 0; i < field.length; i++) {
24.146 + if (isSet(i)) {
24.147 + sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
24.148 + }
24.149 + }
24.150 + int lastIndex = sb.length() - 1;
24.151 + if (sb.charAt(lastIndex) == ',') {
24.152 + sb.setLength(lastIndex);
24.153 + }
24.154 + sb.append(']');
24.155 + return sb.toString();
24.156 + }
24.157 +
24.158 + static int toISODayOfWeek(int calendarDayOfWeek) {
24.159 + return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
24.160 + }
24.161 +
24.162 + static int toCalendarDayOfWeek(int isoDayOfWeek) {
24.163 + if (!isValidDayOfWeek(isoDayOfWeek)) {
24.164 + // adjust later for lenient mode
24.165 + return isoDayOfWeek;
24.166 + }
24.167 + return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
24.168 + }
24.169 +
24.170 + static boolean isValidDayOfWeek(int dayOfWeek) {
24.171 + return dayOfWeek > 0 && dayOfWeek <= 7;
24.172 + }
24.173 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIterator.java Thu Oct 03 15:43:10 2013 +0200
25.3 @@ -0,0 +1,193 @@
25.4 +/*
25.5 + * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
25.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
25.7 + *
25.8 + * This code is free software; you can redistribute it and/or modify it
25.9 + * under the terms of the GNU General Public License version 2 only, as
25.10 + * published by the Free Software Foundation. Oracle designates this
25.11 + * particular file as subject to the "Classpath" exception as provided
25.12 + * by Oracle in the LICENSE file that accompanied this code.
25.13 + *
25.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
25.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25.17 + * version 2 for more details (a copy is included in the LICENSE file that
25.18 + * accompanied this code).
25.19 + *
25.20 + * You should have received a copy of the GNU General Public License version
25.21 + * 2 along with this work; if not, write to the Free Software Foundation,
25.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25.23 + *
25.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
25.25 + * or visit www.oracle.com if you need additional information or have any
25.26 + * questions.
25.27 + */
25.28 +
25.29 +/*
25.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
25.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
25.32 + *
25.33 + * The original version of this source code and documentation
25.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
25.35 + * subsidiary of IBM. These materials are provided under terms
25.36 + * of a License Agreement between Taligent and Sun. This technology
25.37 + * is protected by multiple US and International patents.
25.38 + *
25.39 + * This notice and attribution to Taligent may not be removed.
25.40 + * Taligent is a registered trademark of Taligent, Inc.
25.41 + *
25.42 + */
25.43 +
25.44 +package java.text;
25.45 +
25.46 +
25.47 +/**
25.48 + * This interface defines a protocol for bidirectional iteration over text.
25.49 + * The iterator iterates over a bounded sequence of characters. Characters
25.50 + * are indexed with values beginning with the value returned by getBeginIndex() and
25.51 + * continuing through the value returned by getEndIndex()-1.
25.52 + * <p>
25.53 + * Iterators maintain a current character index, whose valid range is from
25.54 + * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
25.55 + * handling of zero-length text ranges and for historical reasons.
25.56 + * The current index can be retrieved by calling getIndex() and set directly
25.57 + * by calling setIndex(), first(), and last().
25.58 + * <p>
25.59 + * The methods previous() and next() are used for iteration. They return DONE if
25.60 + * they would move outside the range from getBeginIndex() to getEndIndex() -1,
25.61 + * signaling that the iterator has reached the end of the sequence. DONE is
25.62 + * also returned by other methods to indicate that the current index is
25.63 + * outside this range.
25.64 + *
25.65 + * <P>Examples:<P>
25.66 + *
25.67 + * Traverse the text from start to finish
25.68 + * <pre>
25.69 + * public void traverseForward(CharacterIterator iter) {
25.70 + * for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
25.71 + * processChar(c);
25.72 + * }
25.73 + * }
25.74 + * </pre>
25.75 + *
25.76 + * Traverse the text backwards, from end to start
25.77 + * <pre>
25.78 + * public void traverseBackward(CharacterIterator iter) {
25.79 + * for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
25.80 + * processChar(c);
25.81 + * }
25.82 + * }
25.83 + * </pre>
25.84 + *
25.85 + * Traverse both forward and backward from a given position in the text.
25.86 + * Calls to notBoundary() in this example represents some
25.87 + * additional stopping criteria.
25.88 + * <pre>
25.89 + * public void traverseOut(CharacterIterator iter, int pos) {
25.90 + * for (char c = iter.setIndex(pos);
25.91 + * c != CharacterIterator.DONE && notBoundary(c);
25.92 + * c = iter.next()) {
25.93 + * }
25.94 + * int end = iter.getIndex();
25.95 + * for (char c = iter.setIndex(pos);
25.96 + * c != CharacterIterator.DONE && notBoundary(c);
25.97 + * c = iter.previous()) {
25.98 + * }
25.99 + * int start = iter.getIndex();
25.100 + * processSection(start, end);
25.101 + * }
25.102 + * </pre>
25.103 + *
25.104 + * @see StringCharacterIterator
25.105 + * @see AttributedCharacterIterator
25.106 + */
25.107 +
25.108 +public interface CharacterIterator extends Cloneable
25.109 +{
25.110 +
25.111 + /**
25.112 + * Constant that is returned when the iterator has reached either the end
25.113 + * or the beginning of the text. The value is '\\uFFFF', the "not a
25.114 + * character" value which should not occur in any valid Unicode string.
25.115 + */
25.116 + public static final char DONE = '\uFFFF';
25.117 +
25.118 + /**
25.119 + * Sets the position to getBeginIndex() and returns the character at that
25.120 + * position.
25.121 + * @return the first character in the text, or DONE if the text is empty
25.122 + * @see #getBeginIndex()
25.123 + */
25.124 + public char first();
25.125 +
25.126 + /**
25.127 + * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
25.128 + * and returns the character at that position.
25.129 + * @return the last character in the text, or DONE if the text is empty
25.130 + * @see #getEndIndex()
25.131 + */
25.132 + public char last();
25.133 +
25.134 + /**
25.135 + * Gets the character at the current position (as returned by getIndex()).
25.136 + * @return the character at the current position or DONE if the current
25.137 + * position is off the end of the text.
25.138 + * @see #getIndex()
25.139 + */
25.140 + public char current();
25.141 +
25.142 + /**
25.143 + * Increments the iterator's index by one and returns the character
25.144 + * at the new index. If the resulting index is greater or equal
25.145 + * to getEndIndex(), the current index is reset to getEndIndex() and
25.146 + * a value of DONE is returned.
25.147 + * @return the character at the new position or DONE if the new
25.148 + * position is off the end of the text range.
25.149 + */
25.150 + public char next();
25.151 +
25.152 + /**
25.153 + * Decrements the iterator's index by one and returns the character
25.154 + * at the new index. If the current index is getBeginIndex(), the index
25.155 + * remains at getBeginIndex() and a value of DONE is returned.
25.156 + * @return the character at the new position or DONE if the current
25.157 + * position is equal to getBeginIndex().
25.158 + */
25.159 + public char previous();
25.160 +
25.161 + /**
25.162 + * Sets the position to the specified position in the text and returns that
25.163 + * character.
25.164 + * @param position the position within the text. Valid values range from
25.165 + * getBeginIndex() to getEndIndex(). An IllegalArgumentException is thrown
25.166 + * if an invalid value is supplied.
25.167 + * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
25.168 + */
25.169 + public char setIndex(int position);
25.170 +
25.171 + /**
25.172 + * Returns the start index of the text.
25.173 + * @return the index at which the text begins.
25.174 + */
25.175 + public int getBeginIndex();
25.176 +
25.177 + /**
25.178 + * Returns the end index of the text. This index is the index of the first
25.179 + * character following the end of the text.
25.180 + * @return the index after the last character in the text
25.181 + */
25.182 + public int getEndIndex();
25.183 +
25.184 + /**
25.185 + * Returns the current index.
25.186 + * @return the current index.
25.187 + */
25.188 + public int getIndex();
25.189 +
25.190 + /**
25.191 + * Create a copy of this iterator
25.192 + * @return A copy of this
25.193 + */
25.194 + public Object clone();
25.195 +
25.196 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIteratorFieldDelegate.java Thu Oct 03 15:43:10 2013 +0200
26.3 @@ -0,0 +1,124 @@
26.4 +/*
26.5 + * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
26.7 + *
26.8 + * This code is free software; you can redistribute it and/or modify it
26.9 + * under the terms of the GNU General Public License version 2 only, as
26.10 + * published by the Free Software Foundation. Oracle designates this
26.11 + * particular file as subject to the "Classpath" exception as provided
26.12 + * by Oracle in the LICENSE file that accompanied this code.
26.13 + *
26.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
26.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26.17 + * version 2 for more details (a copy is included in the LICENSE file that
26.18 + * accompanied this code).
26.19 + *
26.20 + * You should have received a copy of the GNU General Public License version
26.21 + * 2 along with this work; if not, write to the Free Software Foundation,
26.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26.23 + *
26.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
26.25 + * or visit www.oracle.com if you need additional information or have any
26.26 + * questions.
26.27 + */
26.28 +package java.text;
26.29 +
26.30 +import java.util.ArrayList;
26.31 +
26.32 +/**
26.33 + * CharacterIteratorFieldDelegate combines the notifications from a Format
26.34 + * into a resulting <code>AttributedCharacterIterator</code>. The resulting
26.35 + * <code>AttributedCharacterIterator</code> can be retrieved by way of
26.36 + * the <code>getIterator</code> method.
26.37 + *
26.38 + */
26.39 +class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
26.40 + /**
26.41 + * Array of AttributeStrings. Whenever <code>formatted</code> is invoked
26.42 + * for a region > size, a new instance of AttributedString is added to
26.43 + * attributedStrings. Subsequent invocations of <code>formatted</code>
26.44 + * for existing regions result in invoking addAttribute on the existing
26.45 + * AttributedStrings.
26.46 + */
26.47 + private ArrayList attributedStrings;
26.48 + /**
26.49 + * Running count of the number of characters that have
26.50 + * been encountered.
26.51 + */
26.52 + private int size;
26.53 +
26.54 +
26.55 + CharacterIteratorFieldDelegate() {
26.56 + attributedStrings = new ArrayList();
26.57 + }
26.58 +
26.59 + public void formatted(Format.Field attr, Object value, int start, int end,
26.60 + StringBuffer buffer) {
26.61 + if (start != end) {
26.62 + if (start < size) {
26.63 + // Adjust attributes of existing runs
26.64 + int index = size;
26.65 + int asIndex = attributedStrings.size() - 1;
26.66 +
26.67 + while (start < index) {
26.68 + AttributedString as = (AttributedString)attributedStrings.
26.69 + get(asIndex--);
26.70 + int newIndex = index - as.length();
26.71 + int aStart = Math.max(0, start - newIndex);
26.72 +
26.73 + as.addAttribute(attr, value, aStart, Math.min(
26.74 + end - start, as.length() - aStart) +
26.75 + aStart);
26.76 + index = newIndex;
26.77 + }
26.78 + }
26.79 + if (size < start) {
26.80 + // Pad attributes
26.81 + attributedStrings.add(new AttributedString(
26.82 + buffer.substring(size, start)));
26.83 + size = start;
26.84 + }
26.85 + if (size < end) {
26.86 + // Add new string
26.87 + int aStart = Math.max(start, size);
26.88 + AttributedString string = new AttributedString(
26.89 + buffer.substring(aStart, end));
26.90 +
26.91 + string.addAttribute(attr, value);
26.92 + attributedStrings.add(string);
26.93 + size = end;
26.94 + }
26.95 + }
26.96 + }
26.97 +
26.98 + public void formatted(int fieldID, Format.Field attr, Object value,
26.99 + int start, int end, StringBuffer buffer) {
26.100 + formatted(attr, value, start, end, buffer);
26.101 + }
26.102 +
26.103 + /**
26.104 + * Returns an <code>AttributedCharacterIterator</code> that can be used
26.105 + * to iterate over the resulting formatted String.
26.106 + *
26.107 + * @pararm string Result of formatting.
26.108 + */
26.109 + public AttributedCharacterIterator getIterator(String string) {
26.110 + // Add the last AttributedCharacterIterator if necessary
26.111 + // assert(size <= string.length());
26.112 + if (string.length() > size) {
26.113 + attributedStrings.add(new AttributedString(
26.114 + string.substring(size)));
26.115 + size = string.length();
26.116 + }
26.117 + int iCount = attributedStrings.size();
26.118 + AttributedCharacterIterator iterators[] = new
26.119 + AttributedCharacterIterator[iCount];
26.120 +
26.121 + for (int counter = 0; counter < iCount; counter++) {
26.122 + iterators[counter] = ((AttributedString)attributedStrings.
26.123 + get(counter)).getIterator();
26.124 + }
26.125 + return new AttributedString(iterators).getIterator();
26.126 + }
26.127 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/rt/emul/compact/src/main/java/java/text/ChoiceFormat.java Thu Oct 03 15:43:10 2013 +0200
27.3 @@ -0,0 +1,619 @@
27.4 +/*
27.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
27.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
27.7 + *
27.8 + * This code is free software; you can redistribute it and/or modify it
27.9 + * under the terms of the GNU General Public License version 2 only, as
27.10 + * published by the Free Software Foundation. Oracle designates this
27.11 + * particular file as subject to the "Classpath" exception as provided
27.12 + * by Oracle in the LICENSE file that accompanied this code.
27.13 + *
27.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
27.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
27.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27.17 + * version 2 for more details (a copy is included in the LICENSE file that
27.18 + * accompanied this code).
27.19 + *
27.20 + * You should have received a copy of the GNU General Public License version
27.21 + * 2 along with this work; if not, write to the Free Software Foundation,
27.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27.23 + *
27.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
27.25 + * or visit www.oracle.com if you need additional information or have any
27.26 + * questions.
27.27 + */
27.28 +
27.29 +/*
27.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
27.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
27.32 + *
27.33 + * The original version of this source code and documentation is copyrighted
27.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
27.35 + * materials are provided under terms of a License Agreement between Taligent
27.36 + * and Sun. This technology is protected by multiple US and International
27.37 + * patents. This notice and attribution to Taligent may not be removed.
27.38 + * Taligent is a registered trademark of Taligent, Inc.
27.39 + *
27.40 + */
27.41 +
27.42 +package java.text;
27.43 +
27.44 +import java.io.InvalidObjectException;
27.45 +import java.io.IOException;
27.46 +import java.io.ObjectInputStream;
27.47 +import java.util.Arrays;
27.48 +
27.49 +/**
27.50 + * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
27.51 + * It is generally used in a <code>MessageFormat</code> for handling plurals.
27.52 + * The choice is specified with an ascending list of doubles, where each item
27.53 + * specifies a half-open interval up to the next item:
27.54 + * <blockquote>
27.55 + * <pre>
27.56 + * X matches j if and only if limit[j] <= X < limit[j+1]
27.57 + * </pre>
27.58 + * </blockquote>
27.59 + * If there is no match, then either the first or last index is used, depending
27.60 + * on whether the number (X) is too low or too high. If the limit array is not
27.61 + * in ascending order, the results of formatting will be incorrect. ChoiceFormat
27.62 + * also accepts <code>\u221E</code> as equivalent to infinity(INF).
27.63 + *
27.64 + * <p>
27.65 + * <strong>Note:</strong>
27.66 + * <code>ChoiceFormat</code> differs from the other <code>Format</code>
27.67 + * classes in that you create a <code>ChoiceFormat</code> object with a
27.68 + * constructor (not with a <code>getInstance</code> style factory
27.69 + * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
27.70 + * doesn't require any complex setup for a given locale. In fact,
27.71 + * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
27.72 + *
27.73 + * <p>
27.74 + * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
27.75 + * and an array of limits. The length of these arrays must be the same.
27.76 + * For example,
27.77 + * <ul>
27.78 + * <li>
27.79 + * <em>limits</em> = {1,2,3,4,5,6,7}<br>
27.80 + * <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
27.81 + * <li>
27.82 + * <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
27.83 + * <em>formats</em> = {"no files", "one file", "many files"}<br>
27.84 + * (<code>nextDouble</code> can be used to get the next higher double, to
27.85 + * make the half-open interval.)
27.86 + * </ul>
27.87 + *
27.88 + * <p>
27.89 + * Here is a simple example that shows formatting and parsing:
27.90 + * <blockquote>
27.91 + * <pre>
27.92 + * double[] limits = {1,2,3,4,5,6,7};
27.93 + * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
27.94 + * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
27.95 + * ParsePosition status = new ParsePosition(0);
27.96 + * for (double i = 0.0; i <= 8.0; ++i) {
27.97 + * status.setIndex(0);
27.98 + * System.out.println(i + " -> " + form.format(i) + " -> "
27.99 + * + form.parse(form.format(i),status));
27.100 + * }
27.101 + * </pre>
27.102 + * </blockquote>
27.103 + * Here is a more complex example, with a pattern format:
27.104 + * <blockquote>
27.105 + * <pre>
27.106 + * double[] filelimits = {0,1,2};
27.107 + * String[] filepart = {"are no files","is one file","are {2} files"};
27.108 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
27.109 + * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
27.110 + * MessageFormat pattform = new MessageFormat("There {0} on {1}");
27.111 + * pattform.setFormats(testFormats);
27.112 + * Object[] testArgs = {null, "ADisk", null};
27.113 + * for (int i = 0; i < 4; ++i) {
27.114 + * testArgs[0] = new Integer(i);
27.115 + * testArgs[2] = testArgs[0];
27.116 + * System.out.println(pattform.format(testArgs));
27.117 + * }
27.118 + * </pre>
27.119 + * </blockquote>
27.120 + * <p>
27.121 + * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
27.122 + * For example:
27.123 + * <blockquote>
27.124 + * <pre>
27.125 + * ChoiceFormat fmt = new ChoiceFormat(
27.126 + * "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
27.127 + * System.out.println("Formatter Pattern : " + fmt.toPattern());
27.128 + *
27.129 + * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
27.130 + * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
27.131 + * System.out.println("Format with 0 : " + fmt.format(0));
27.132 + * System.out.println("Format with 0.9 : " + fmt.format(0.9));
27.133 + * System.out.println("Format with 1.0 : " + fmt.format(1));
27.134 + * System.out.println("Format with 1.5 : " + fmt.format(1.5));
27.135 + * System.out.println("Format with 2 : " + fmt.format(2));
27.136 + * System.out.println("Format with 2.1 : " + fmt.format(2.1));
27.137 + * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
27.138 + * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
27.139 + * </pre>
27.140 + * </blockquote>
27.141 + * And the output result would be like the following:
27.142 + * <blockquote>
27.143 + * <pre>
27.144 + * Format with -INF : is negative
27.145 + * Format with -1.0 : is negative
27.146 + * Format with 0 : is zero or fraction
27.147 + * Format with 0.9 : is zero or fraction
27.148 + * Format with 1.0 : is one
27.149 + * Format with 1.5 : is 1+
27.150 + * Format with 2 : is two
27.151 + * Format with 2.1 : is more than 2.
27.152 + * Format with NaN : is negative
27.153 + * Format with +INF : is more than 2.
27.154 + * </pre>
27.155 + * </blockquote>
27.156 + *
27.157 + * <h4><a name="synchronization">Synchronization</a></h4>
27.158 + *
27.159 + * <p>
27.160 + * Choice formats are not synchronized.
27.161 + * It is recommended to create separate format instances for each thread.
27.162 + * If multiple threads access a format concurrently, it must be synchronized
27.163 + * externally.
27.164 + *
27.165 + *
27.166 + * @see DecimalFormat
27.167 + * @see MessageFormat
27.168 + * @author Mark Davis
27.169 + */
27.170 +public class ChoiceFormat extends NumberFormat {
27.171 +
27.172 + // Proclaim serial compatibility with 1.1 FCS
27.173 + private static final long serialVersionUID = 1795184449645032964L;
27.174 +
27.175 + /**
27.176 + * Sets the pattern.
27.177 + * @param newPattern See the class description.
27.178 + */
27.179 + public void applyPattern(String newPattern) {
27.180 + StringBuffer[] segments = new StringBuffer[2];
27.181 + for (int i = 0; i < segments.length; ++i) {
27.182 + segments[i] = new StringBuffer();
27.183 + }
27.184 + double[] newChoiceLimits = new double[30];
27.185 + String[] newChoiceFormats = new String[30];
27.186 + int count = 0;
27.187 + int part = 0;
27.188 + double startValue = 0;
27.189 + double oldStartValue = Double.NaN;
27.190 + boolean inQuote = false;
27.191 + for (int i = 0; i < newPattern.length(); ++i) {
27.192 + char ch = newPattern.charAt(i);
27.193 + if (ch=='\'') {
27.194 + // Check for "''" indicating a literal quote
27.195 + if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
27.196 + segments[part].append(ch);
27.197 + ++i;
27.198 + } else {
27.199 + inQuote = !inQuote;
27.200 + }
27.201 + } else if (inQuote) {
27.202 + segments[part].append(ch);
27.203 + } else if (ch == '<' || ch == '#' || ch == '\u2264') {
27.204 + if (segments[0].length() == 0) {
27.205 + throw new IllegalArgumentException();
27.206 + }
27.207 + try {
27.208 + String tempBuffer = segments[0].toString();
27.209 + if (tempBuffer.equals("\u221E")) {
27.210 + startValue = Double.POSITIVE_INFINITY;
27.211 + } else if (tempBuffer.equals("-\u221E")) {
27.212 + startValue = Double.NEGATIVE_INFINITY;
27.213 + } else {
27.214 + startValue = Double.valueOf(segments[0].toString()).doubleValue();
27.215 + }
27.216 + } catch (Exception e) {
27.217 + throw new IllegalArgumentException();
27.218 + }
27.219 + if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
27.220 + startValue != Double.NEGATIVE_INFINITY) {
27.221 + startValue = nextDouble(startValue);
27.222 + }
27.223 + if (startValue <= oldStartValue) {
27.224 + throw new IllegalArgumentException();
27.225 + }
27.226 + segments[0].setLength(0);
27.227 + part = 1;
27.228 + } else if (ch == '|') {
27.229 + if (count == newChoiceLimits.length) {
27.230 + newChoiceLimits = doubleArraySize(newChoiceLimits);
27.231 + newChoiceFormats = doubleArraySize(newChoiceFormats);
27.232 + }
27.233 + newChoiceLimits[count] = startValue;
27.234 + newChoiceFormats[count] = segments[1].toString();
27.235 + ++count;
27.236 + oldStartValue = startValue;
27.237 + segments[1].setLength(0);
27.238 + part = 0;
27.239 + } else {
27.240 + segments[part].append(ch);
27.241 + }
27.242 + }
27.243 + // clean up last one
27.244 + if (part == 1) {
27.245 + if (count == newChoiceLimits.length) {
27.246 + newChoiceLimits = doubleArraySize(newChoiceLimits);
27.247 + newChoiceFormats = doubleArraySize(newChoiceFormats);
27.248 + }
27.249 + newChoiceLimits[count] = startValue;
27.250 + newChoiceFormats[count] = segments[1].toString();
27.251 + ++count;
27.252 + }
27.253 + choiceLimits = new double[count];
27.254 + System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
27.255 + choiceFormats = new String[count];
27.256 + System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
27.257 + }
27.258 +
27.259 + /**
27.260 + * Gets the pattern.
27.261 + */
27.262 + public String toPattern() {
27.263 + StringBuffer result = new StringBuffer();
27.264 + for (int i = 0; i < choiceLimits.length; ++i) {
27.265 + if (i != 0) {
27.266 + result.append('|');
27.267 + }
27.268 + // choose based upon which has less precision
27.269 + // approximate that by choosing the closest one to an integer.
27.270 + // could do better, but it's not worth it.
27.271 + double less = previousDouble(choiceLimits[i]);
27.272 + double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
27.273 + double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
27.274 +
27.275 + if (tryLessOrEqual < tryLess) {
27.276 + result.append(""+choiceLimits[i]);
27.277 + result.append('#');
27.278 + } else {
27.279 + if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
27.280 + result.append("\u221E");
27.281 + } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
27.282 + result.append("-\u221E");
27.283 + } else {
27.284 + result.append(""+less);
27.285 + }
27.286 + result.append('<');
27.287 + }
27.288 + // Append choiceFormats[i], using quotes if there are special characters.
27.289 + // Single quotes themselves must be escaped in either case.
27.290 + String text = choiceFormats[i];
27.291 + boolean needQuote = text.indexOf('<') >= 0
27.292 + || text.indexOf('#') >= 0
27.293 + || text.indexOf('\u2264') >= 0
27.294 + || text.indexOf('|') >= 0;
27.295 + if (needQuote) result.append('\'');
27.296 + if (text.indexOf('\'') < 0) result.append(text);
27.297 + else {
27.298 + for (int j=0; j<text.length(); ++j) {
27.299 + char c = text.charAt(j);
27.300 + result.append(c);
27.301 + if (c == '\'') result.append(c);
27.302 + }
27.303 + }
27.304 + if (needQuote) result.append('\'');
27.305 + }
27.306 + return result.toString();
27.307 + }
27.308 +
27.309 + /**
27.310 + * Constructs with limits and corresponding formats based on the pattern.
27.311 + * @see #applyPattern
27.312 + */
27.313 + public ChoiceFormat(String newPattern) {
27.314 + applyPattern(newPattern);
27.315 + }
27.316 +
27.317 + /**
27.318 + * Constructs with the limits and the corresponding formats.
27.319 + * @see #setChoices
27.320 + */
27.321 + public ChoiceFormat(double[] limits, String[] formats) {
27.322 + setChoices(limits, formats);
27.323 + }
27.324 +
27.325 + /**
27.326 + * Set the choices to be used in formatting.
27.327 + * @param limits contains the top value that you want
27.328 + * parsed with that format,and should be in ascending sorted order. When
27.329 + * formatting X, the choice will be the i, where
27.330 + * limit[i] <= X < limit[i+1].
27.331 + * If the limit array is not in ascending order, the results of formatting
27.332 + * will be incorrect.
27.333 + * @param formats are the formats you want to use for each limit.
27.334 + * They can be either Format objects or Strings.
27.335 + * When formatting with object Y,
27.336 + * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
27.337 + * is called. Otherwise Y.toString() is called.
27.338 + */
27.339 + public void setChoices(double[] limits, String formats[]) {
27.340 + if (limits.length != formats.length) {
27.341 + throw new IllegalArgumentException(
27.342 + "Array and limit arrays must be of the same length.");
27.343 + }
27.344 + choiceLimits = limits;
27.345 + choiceFormats = formats;
27.346 + }
27.347 +
27.348 + /**
27.349 + * Get the limits passed in the constructor.
27.350 + * @return the limits.
27.351 + */
27.352 + public double[] getLimits() {
27.353 + return choiceLimits;
27.354 + }
27.355 +
27.356 + /**
27.357 + * Get the formats passed in the constructor.
27.358 + * @return the formats.
27.359 + */
27.360 + public Object[] getFormats() {
27.361 + return choiceFormats;
27.362 + }
27.363 +
27.364 + // Overrides
27.365 +
27.366 + /**
27.367 + * Specialization of format. This method really calls
27.368 + * <code>format(double, StringBuffer, FieldPosition)</code>
27.369 + * thus the range of longs that are supported is only equal to
27.370 + * the range that can be stored by double. This will never be
27.371 + * a practical limitation.
27.372 + */
27.373 + public StringBuffer format(long number, StringBuffer toAppendTo,
27.374 + FieldPosition status) {
27.375 + return format((double)number, toAppendTo, status);
27.376 + }
27.377 +
27.378 + /**
27.379 + * Returns pattern with formatted double.
27.380 + * @param number number to be formatted & substituted.
27.381 + * @param toAppendTo where text is appended.
27.382 + * @param status ignore no useful status is returned.
27.383 + */
27.384 + public StringBuffer format(double number, StringBuffer toAppendTo,
27.385 + FieldPosition status) {
27.386 + // find the number
27.387 + int i;
27.388 + for (i = 0; i < choiceLimits.length; ++i) {
27.389 + if (!(number >= choiceLimits[i])) {
27.390 + // same as number < choiceLimits, except catchs NaN
27.391 + break;
27.392 + }
27.393 + }
27.394 + --i;
27.395 + if (i < 0) i = 0;
27.396 + // return either a formatted number, or a string
27.397 + return toAppendTo.append(choiceFormats[i]);
27.398 + }
27.399 +
27.400 + /**
27.401 + * Parses a Number from the input text.
27.402 + * @param text the source text.
27.403 + * @param status an input-output parameter. On input, the
27.404 + * status.index field indicates the first character of the
27.405 + * source text that should be parsed. On exit, if no error
27.406 + * occured, status.index is set to the first unparsed character
27.407 + * in the source text. On exit, if an error did occur,
27.408 + * status.index is unchanged and status.errorIndex is set to the
27.409 + * first index of the character that caused the parse to fail.
27.410 + * @return A Number representing the value of the number parsed.
27.411 + */
27.412 + public Number parse(String text, ParsePosition status) {
27.413 + // find the best number (defined as the one with the longest parse)
27.414 + int start = status.index;
27.415 + int furthest = start;
27.416 + double bestNumber = Double.NaN;
27.417 + double tempNumber = 0.0;
27.418 + for (int i = 0; i < choiceFormats.length; ++i) {
27.419 + String tempString = choiceFormats[i];
27.420 + if (text.regionMatches(start, tempString, 0, tempString.length())) {
27.421 + status.index = start + tempString.length();
27.422 + tempNumber = choiceLimits[i];
27.423 + if (status.index > furthest) {
27.424 + furthest = status.index;
27.425 + bestNumber = tempNumber;
27.426 + if (furthest == text.length()) break;
27.427 + }
27.428 + }
27.429 + }
27.430 + status.index = furthest;
27.431 + if (status.index == start) {
27.432 + status.errorIndex = furthest;
27.433 + }
27.434 + return new Double(bestNumber);
27.435 + }
27.436 +
27.437 + /**
27.438 + * Finds the least double greater than d.
27.439 + * If NaN, returns same value.
27.440 + * <p>Used to make half-open intervals.
27.441 + * @see #previousDouble
27.442 + */
27.443 + public static final double nextDouble (double d) {
27.444 + return nextDouble(d,true);
27.445 + }
27.446 +
27.447 + /**
27.448 + * Finds the greatest double less than d.
27.449 + * If NaN, returns same value.
27.450 + * @see #nextDouble
27.451 + */
27.452 + public static final double previousDouble (double d) {
27.453 + return nextDouble(d,false);
27.454 + }
27.455 +
27.456 + /**
27.457 + * Overrides Cloneable
27.458 + */
27.459 + public Object clone()
27.460 + {
27.461 + ChoiceFormat other = (ChoiceFormat) super.clone();
27.462 + // for primitives or immutables, shallow clone is enough
27.463 + other.choiceLimits = (double[]) choiceLimits.clone();
27.464 + other.choiceFormats = (String[]) choiceFormats.clone();
27.465 + return other;
27.466 + }
27.467 +
27.468 + /**
27.469 + * Generates a hash code for the message format object.
27.470 + */
27.471 + public int hashCode() {
27.472 + int result = choiceLimits.length;
27.473 + if (choiceFormats.length > 0) {
27.474 + // enough for reasonable distribution
27.475 + result ^= choiceFormats[choiceFormats.length-1].hashCode();
27.476 + }
27.477 + return result;
27.478 + }
27.479 +
27.480 + /**
27.481 + * Equality comparision between two
27.482 + */
27.483 + public boolean equals(Object obj) {
27.484 + if (obj == null) return false;
27.485 + if (this == obj) // quick check
27.486 + return true;
27.487 + if (getClass() != obj.getClass())
27.488 + return false;
27.489 + ChoiceFormat other = (ChoiceFormat) obj;
27.490 + return (Arrays.equals(choiceLimits, other.choiceLimits)
27.491 + && Arrays.equals(choiceFormats, other.choiceFormats));
27.492 + }
27.493 +
27.494 + /**
27.495 + * After reading an object from the input stream, do a simple verification
27.496 + * to maintain class invariants.
27.497 + * @throws InvalidObjectException if the objects read from the stream is invalid.
27.498 + */
27.499 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
27.500 + in.defaultReadObject();
27.501 + if (choiceLimits.length != choiceFormats.length) {
27.502 + throw new InvalidObjectException(
27.503 + "limits and format arrays of different length.");
27.504 + }
27.505 + }
27.506 +
27.507 + // ===============privates===========================
27.508 +
27.509 + /**
27.510 + * A list of lower bounds for the choices. The formatter will return
27.511 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
27.512 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
27.513 + * @serial
27.514 + */
27.515 + private double[] choiceLimits;
27.516 +
27.517 + /**
27.518 + * A list of choice strings. The formatter will return
27.519 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
27.520 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
27.521 + * @serial
27.522 + */
27.523 + private String[] choiceFormats;
27.524 +
27.525 + /*
27.526 + static final long SIGN = 0x8000000000000000L;
27.527 + static final long EXPONENT = 0x7FF0000000000000L;
27.528 + static final long SIGNIFICAND = 0x000FFFFFFFFFFFFFL;
27.529 +
27.530 + private static double nextDouble (double d, boolean positive) {
27.531 + if (Double.isNaN(d) || Double.isInfinite(d)) {
27.532 + return d;
27.533 + }
27.534 + long bits = Double.doubleToLongBits(d);
27.535 + long significand = bits & SIGNIFICAND;
27.536 + if (bits < 0) {
27.537 + significand |= (SIGN | EXPONENT);
27.538 + }
27.539 + long exponent = bits & EXPONENT;
27.540 + if (positive) {
27.541 + significand += 1;
27.542 + // FIXME fix overflow & underflow
27.543 + } else {
27.544 + significand -= 1;
27.545 + // FIXME fix overflow & underflow
27.546 + }
27.547 + bits = exponent | (significand & ~EXPONENT);
27.548 + return Double.longBitsToDouble(bits);
27.549 + }
27.550 + */
27.551 +
27.552 + static final long SIGN = 0x8000000000000000L;
27.553 + static final long EXPONENT = 0x7FF0000000000000L;
27.554 + static final long POSITIVEINFINITY = 0x7FF0000000000000L;
27.555 +
27.556 + /**
27.557 + * Finds the least double greater than d (if positive == true),
27.558 + * or the greatest double less than d (if positive == false).
27.559 + * If NaN, returns same value.
27.560 + *
27.561 + * Does not affect floating-point flags,
27.562 + * provided these member functions do not:
27.563 + * Double.longBitsToDouble(long)
27.564 + * Double.doubleToLongBits(double)
27.565 + * Double.isNaN(double)
27.566 + */
27.567 + public static double nextDouble (double d, boolean positive) {
27.568 +
27.569 + /* filter out NaN's */
27.570 + if (Double.isNaN(d)) {
27.571 + return d;
27.572 + }
27.573 +
27.574 + /* zero's are also a special case */
27.575 + if (d == 0.0) {
27.576 + double smallestPositiveDouble = Double.longBitsToDouble(1L);
27.577 + if (positive) {
27.578 + return smallestPositiveDouble;
27.579 + } else {
27.580 + return -smallestPositiveDouble;
27.581 + }
27.582 + }
27.583 +
27.584 + /* if entering here, d is a nonzero value */
27.585 +
27.586 + /* hold all bits in a long for later use */
27.587 + long bits = Double.doubleToLongBits(d);
27.588 +
27.589 + /* strip off the sign bit */
27.590 + long magnitude = bits & ~SIGN;
27.591 +
27.592 + /* if next double away from zero, increase magnitude */
27.593 + if ((bits > 0) == positive) {
27.594 + if (magnitude != POSITIVEINFINITY) {
27.595 + magnitude += 1;
27.596 + }
27.597 + }
27.598 + /* else decrease magnitude */
27.599 + else {
27.600 + magnitude -= 1;
27.601 + }
27.602 +
27.603 + /* restore sign bit and return */
27.604 + long signbit = bits & SIGN;
27.605 + return Double.longBitsToDouble (magnitude | signbit);
27.606 + }
27.607 +
27.608 + private static double[] doubleArraySize(double[] array) {
27.609 + int oldSize = array.length;
27.610 + double[] newArray = new double[oldSize * 2];
27.611 + System.arraycopy(array, 0, newArray, 0, oldSize);
27.612 + return newArray;
27.613 + }
27.614 +
27.615 + private String[] doubleArraySize(String[] array) {
27.616 + int oldSize = array.length;
27.617 + String[] newArray = new String[oldSize * 2];
27.618 + System.arraycopy(array, 0, newArray, 0, oldSize);
27.619 + return newArray;
27.620 + }
27.621 +
27.622 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormat.java Thu Oct 03 15:43:10 2013 +0200
28.3 @@ -0,0 +1,1030 @@
28.4 +/*
28.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
28.7 + *
28.8 + * This code is free software; you can redistribute it and/or modify it
28.9 + * under the terms of the GNU General Public License version 2 only, as
28.10 + * published by the Free Software Foundation. Oracle designates this
28.11 + * particular file as subject to the "Classpath" exception as provided
28.12 + * by Oracle in the LICENSE file that accompanied this code.
28.13 + *
28.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
28.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
28.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28.17 + * version 2 for more details (a copy is included in the LICENSE file that
28.18 + * accompanied this code).
28.19 + *
28.20 + * You should have received a copy of the GNU General Public License version
28.21 + * 2 along with this work; if not, write to the Free Software Foundation,
28.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28.23 + *
28.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28.25 + * or visit www.oracle.com if you need additional information or have any
28.26 + * questions.
28.27 + */
28.28 +
28.29 +/*
28.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
28.32 + *
28.33 + * The original version of this source code and documentation is copyrighted
28.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
28.35 + * materials are provided under terms of a License Agreement between Taligent
28.36 + * and Sun. This technology is protected by multiple US and International
28.37 + * patents. This notice and attribution to Taligent may not be removed.
28.38 + * Taligent is a registered trademark of Taligent, Inc.
28.39 + *
28.40 + */
28.41 +
28.42 +package java.text;
28.43 +
28.44 +import java.io.InvalidObjectException;
28.45 +import java.text.spi.DateFormatProvider;
28.46 +import java.util.Calendar;
28.47 +import java.util.Date;
28.48 +import java.util.GregorianCalendar;
28.49 +import java.util.HashMap;
28.50 +import java.util.Locale;
28.51 +import java.util.Map;
28.52 +import java.util.MissingResourceException;
28.53 +import java.util.ResourceBundle;
28.54 +import java.util.TimeZone;
28.55 +import java.util.spi.LocaleServiceProvider;
28.56 +import sun.util.LocaleServiceProviderPool;
28.57 +
28.58 +/**
28.59 + * {@code DateFormat} is an abstract class for date/time formatting subclasses which
28.60 + * formats and parses dates or time in a language-independent manner.
28.61 + * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
28.62 + * formatting (i.e., date -> text), parsing (text -> date), and
28.63 + * normalization. The date is represented as a <code>Date</code> object or
28.64 + * as the milliseconds since January 1, 1970, 00:00:00 GMT.
28.65 + *
28.66 + * <p>{@code DateFormat} provides many class methods for obtaining default date/time
28.67 + * formatters based on the default or a given locale and a number of formatting
28.68 + * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
28.69 + * detail and examples of using these styles are provided in the method
28.70 + * descriptions.
28.71 + *
28.72 + * <p>{@code DateFormat} helps you to format and parse dates for any locale.
28.73 + * Your code can be completely independent of the locale conventions for
28.74 + * months, days of the week, or even the calendar format: lunar vs. solar.
28.75 + *
28.76 + * <p>To format a date for the current Locale, use one of the
28.77 + * static factory methods:
28.78 + * <pre>
28.79 + * myString = DateFormat.getDateInstance().format(myDate);
28.80 + * </pre>
28.81 + * <p>If you are formatting multiple dates, it is
28.82 + * more efficient to get the format and use it multiple times so that
28.83 + * the system doesn't have to fetch the information about the local
28.84 + * language and country conventions multiple times.
28.85 + * <pre>
28.86 + * DateFormat df = DateFormat.getDateInstance();
28.87 + * for (int i = 0; i < myDate.length; ++i) {
28.88 + * output.println(df.format(myDate[i]) + "; ");
28.89 + * }
28.90 + * </pre>
28.91 + * <p>To format a date for a different Locale, specify it in the
28.92 + * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
28.93 + * <pre>
28.94 + * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
28.95 + * </pre>
28.96 + * <p>You can use a DateFormat to parse also.
28.97 + * <pre>
28.98 + * myDate = df.parse(myString);
28.99 + * </pre>
28.100 + * <p>Use {@code getDateInstance} to get the normal date format for that country.
28.101 + * There are other static factory methods available.
28.102 + * Use {@code getTimeInstance} to get the time format for that country.
28.103 + * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
28.104 + * different options to these factory methods to control the length of the
28.105 + * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
28.106 + * on the locale, but generally:
28.107 + * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
28.108 + * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
28.109 + * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
28.110 + * <li>{@link #FULL} is pretty completely specified, such as
28.111 + * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
28.112 + * </ul>
28.113 + *
28.114 + * <p>You can also set the time zone on the format if you wish.
28.115 + * If you want even more control over the format or parsing,
28.116 + * (or want to give your users more control),
28.117 + * you can try casting the {@code DateFormat} you get from the factory methods
28.118 + * to a {@link SimpleDateFormat}. This will work for the majority
28.119 + * of countries; just remember to put it in a {@code try} block in case you
28.120 + * encounter an unusual one.
28.121 + *
28.122 + * <p>You can also use forms of the parse and format methods with
28.123 + * {@link ParsePosition} and {@link FieldPosition} to
28.124 + * allow you to
28.125 + * <ul><li>progressively parse through pieces of a string.
28.126 + * <li>align any particular field, or find out where it is for selection
28.127 + * on the screen.
28.128 + * </ul>
28.129 + *
28.130 + * <h4><a name="synchronization">Synchronization</a></h4>
28.131 + *
28.132 + * <p>
28.133 + * Date formats are not synchronized.
28.134 + * It is recommended to create separate format instances for each thread.
28.135 + * If multiple threads access a format concurrently, it must be synchronized
28.136 + * externally.
28.137 + *
28.138 + * @see Format
28.139 + * @see NumberFormat
28.140 + * @see SimpleDateFormat
28.141 + * @see java.util.Calendar
28.142 + * @see java.util.GregorianCalendar
28.143 + * @see java.util.TimeZone
28.144 + * @author Mark Davis, Chen-Lieh Huang, Alan Liu
28.145 + */
28.146 +public abstract class DateFormat extends Format {
28.147 +
28.148 + /**
28.149 + * The {@link Calendar} instance used for calculating the date-time fields
28.150 + * and the instant of time. This field is used for both formatting and
28.151 + * parsing.
28.152 + *
28.153 + * <p>Subclasses should initialize this field to a {@link Calendar}
28.154 + * appropriate for the {@link Locale} associated with this
28.155 + * <code>DateFormat</code>.
28.156 + * @serial
28.157 + */
28.158 + protected Calendar calendar;
28.159 +
28.160 + /**
28.161 + * The number formatter that <code>DateFormat</code> uses to format numbers
28.162 + * in dates and times. Subclasses should initialize this to a number format
28.163 + * appropriate for the locale associated with this <code>DateFormat</code>.
28.164 + * @serial
28.165 + */
28.166 + protected NumberFormat numberFormat;
28.167 +
28.168 + /**
28.169 + * Useful constant for ERA field alignment.
28.170 + * Used in FieldPosition of date/time formatting.
28.171 + */
28.172 + public final static int ERA_FIELD = 0;
28.173 + /**
28.174 + * Useful constant for YEAR field alignment.
28.175 + * Used in FieldPosition of date/time formatting.
28.176 + */
28.177 + public final static int YEAR_FIELD = 1;
28.178 + /**
28.179 + * Useful constant for MONTH field alignment.
28.180 + * Used in FieldPosition of date/time formatting.
28.181 + */
28.182 + public final static int MONTH_FIELD = 2;
28.183 + /**
28.184 + * Useful constant for DATE field alignment.
28.185 + * Used in FieldPosition of date/time formatting.
28.186 + */
28.187 + public final static int DATE_FIELD = 3;
28.188 + /**
28.189 + * Useful constant for one-based HOUR_OF_DAY field alignment.
28.190 + * Used in FieldPosition of date/time formatting.
28.191 + * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
28.192 + * For example, 23:59 + 01:00 results in 24:59.
28.193 + */
28.194 + public final static int HOUR_OF_DAY1_FIELD = 4;
28.195 + /**
28.196 + * Useful constant for zero-based HOUR_OF_DAY field alignment.
28.197 + * Used in FieldPosition of date/time formatting.
28.198 + * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
28.199 + * For example, 23:59 + 01:00 results in 00:59.
28.200 + */
28.201 + public final static int HOUR_OF_DAY0_FIELD = 5;
28.202 + /**
28.203 + * Useful constant for MINUTE field alignment.
28.204 + * Used in FieldPosition of date/time formatting.
28.205 + */
28.206 + public final static int MINUTE_FIELD = 6;
28.207 + /**
28.208 + * Useful constant for SECOND field alignment.
28.209 + * Used in FieldPosition of date/time formatting.
28.210 + */
28.211 + public final static int SECOND_FIELD = 7;
28.212 + /**
28.213 + * Useful constant for MILLISECOND field alignment.
28.214 + * Used in FieldPosition of date/time formatting.
28.215 + */
28.216 + public final static int MILLISECOND_FIELD = 8;
28.217 + /**
28.218 + * Useful constant for DAY_OF_WEEK field alignment.
28.219 + * Used in FieldPosition of date/time formatting.
28.220 + */
28.221 + public final static int DAY_OF_WEEK_FIELD = 9;
28.222 + /**
28.223 + * Useful constant for DAY_OF_YEAR field alignment.
28.224 + * Used in FieldPosition of date/time formatting.
28.225 + */
28.226 + public final static int DAY_OF_YEAR_FIELD = 10;
28.227 + /**
28.228 + * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
28.229 + * Used in FieldPosition of date/time formatting.
28.230 + */
28.231 + public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
28.232 + /**
28.233 + * Useful constant for WEEK_OF_YEAR field alignment.
28.234 + * Used in FieldPosition of date/time formatting.
28.235 + */
28.236 + public final static int WEEK_OF_YEAR_FIELD = 12;
28.237 + /**
28.238 + * Useful constant for WEEK_OF_MONTH field alignment.
28.239 + * Used in FieldPosition of date/time formatting.
28.240 + */
28.241 + public final static int WEEK_OF_MONTH_FIELD = 13;
28.242 + /**
28.243 + * Useful constant for AM_PM field alignment.
28.244 + * Used in FieldPosition of date/time formatting.
28.245 + */
28.246 + public final static int AM_PM_FIELD = 14;
28.247 + /**
28.248 + * Useful constant for one-based HOUR field alignment.
28.249 + * Used in FieldPosition of date/time formatting.
28.250 + * HOUR1_FIELD is used for the one-based 12-hour clock.
28.251 + * For example, 11:30 PM + 1 hour results in 12:30 AM.
28.252 + */
28.253 + public final static int HOUR1_FIELD = 15;
28.254 + /**
28.255 + * Useful constant for zero-based HOUR field alignment.
28.256 + * Used in FieldPosition of date/time formatting.
28.257 + * HOUR0_FIELD is used for the zero-based 12-hour clock.
28.258 + * For example, 11:30 PM + 1 hour results in 00:30 AM.
28.259 + */
28.260 + public final static int HOUR0_FIELD = 16;
28.261 + /**
28.262 + * Useful constant for TIMEZONE field alignment.
28.263 + * Used in FieldPosition of date/time formatting.
28.264 + */
28.265 + public final static int TIMEZONE_FIELD = 17;
28.266 +
28.267 + // Proclaim serial compatibility with 1.1 FCS
28.268 + private static final long serialVersionUID = 7218322306649953788L;
28.269 +
28.270 + /**
28.271 + * Overrides Format.
28.272 + * Formats a time object into a time string. Examples of time objects
28.273 + * are a time value expressed in milliseconds and a Date object.
28.274 + * @param obj must be a Number or a Date.
28.275 + * @param toAppendTo the string buffer for the returning time string.
28.276 + * @return the string buffer passed in as toAppendTo, with formatted text appended.
28.277 + * @param fieldPosition keeps track of the position of the field
28.278 + * within the returned string.
28.279 + * On input: an alignment field,
28.280 + * if desired. On output: the offsets of the alignment field. For
28.281 + * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
28.282 + * if the given fieldPosition is DateFormat.YEAR_FIELD, the
28.283 + * begin index and end index of fieldPosition will be set to
28.284 + * 0 and 4, respectively.
28.285 + * Notice that if the same time field appears
28.286 + * more than once in a pattern, the fieldPosition will be set for the first
28.287 + * occurrence of that time field. For instance, formatting a Date to
28.288 + * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
28.289 + * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
28.290 + * the begin index and end index of fieldPosition will be set to
28.291 + * 5 and 8, respectively, for the first occurrence of the timezone
28.292 + * pattern character 'z'.
28.293 + * @see java.text.Format
28.294 + */
28.295 + public final StringBuffer format(Object obj, StringBuffer toAppendTo,
28.296 + FieldPosition fieldPosition)
28.297 + {
28.298 + if (obj instanceof Date)
28.299 + return format( (Date)obj, toAppendTo, fieldPosition );
28.300 + else if (obj instanceof Number)
28.301 + return format( new Date(((Number)obj).longValue()),
28.302 + toAppendTo, fieldPosition );
28.303 + else
28.304 + throw new IllegalArgumentException("Cannot format given Object as a Date");
28.305 + }
28.306 +
28.307 + /**
28.308 + * Formats a Date into a date/time string.
28.309 + * @param date a Date to be formatted into a date/time string.
28.310 + * @param toAppendTo the string buffer for the returning date/time string.
28.311 + * @param fieldPosition keeps track of the position of the field
28.312 + * within the returned string.
28.313 + * On input: an alignment field,
28.314 + * if desired. On output: the offsets of the alignment field. For
28.315 + * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
28.316 + * if the given fieldPosition is DateFormat.YEAR_FIELD, the
28.317 + * begin index and end index of fieldPosition will be set to
28.318 + * 0 and 4, respectively.
28.319 + * Notice that if the same time field appears
28.320 + * more than once in a pattern, the fieldPosition will be set for the first
28.321 + * occurrence of that time field. For instance, formatting a Date to
28.322 + * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
28.323 + * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
28.324 + * the begin index and end index of fieldPosition will be set to
28.325 + * 5 and 8, respectively, for the first occurrence of the timezone
28.326 + * pattern character 'z'.
28.327 + * @return the string buffer passed in as toAppendTo, with formatted text appended.
28.328 + */
28.329 + public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
28.330 + FieldPosition fieldPosition);
28.331 +
28.332 + /**
28.333 + * Formats a Date into a date/time string.
28.334 + * @param date the time value to be formatted into a time string.
28.335 + * @return the formatted time string.
28.336 + */
28.337 + public final String format(Date date)
28.338 + {
28.339 + return format(date, new StringBuffer(),
28.340 + DontCareFieldPosition.INSTANCE).toString();
28.341 + }
28.342 +
28.343 + /**
28.344 + * Parses text from the beginning of the given string to produce a date.
28.345 + * The method may not use the entire text of the given string.
28.346 + * <p>
28.347 + * See the {@link #parse(String, ParsePosition)} method for more information
28.348 + * on date parsing.
28.349 + *
28.350 + * @param source A <code>String</code> whose beginning should be parsed.
28.351 + * @return A <code>Date</code> parsed from the string.
28.352 + * @exception ParseException if the beginning of the specified string
28.353 + * cannot be parsed.
28.354 + */
28.355 + public Date parse(String source) throws ParseException
28.356 + {
28.357 + ParsePosition pos = new ParsePosition(0);
28.358 + Date result = parse(source, pos);
28.359 + if (pos.index == 0)
28.360 + throw new ParseException("Unparseable date: \"" + source + "\"" ,
28.361 + pos.errorIndex);
28.362 + return result;
28.363 + }
28.364 +
28.365 + /**
28.366 + * Parse a date/time string according to the given parse position. For
28.367 + * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
28.368 + * that is equivalent to {@code Date(837039900000L)}.
28.369 + *
28.370 + * <p> By default, parsing is lenient: If the input is not in the form used
28.371 + * by this object's format method but can still be parsed as a date, then
28.372 + * the parse succeeds. Clients may insist on strict adherence to the
28.373 + * format by calling {@link #setLenient(boolean) setLenient(false)}.
28.374 + *
28.375 + * <p>This parsing operation uses the {@link #calendar} to produce
28.376 + * a {@code Date}. As a result, the {@code calendar}'s date-time
28.377 + * fields and the {@code TimeZone} value may have been
28.378 + * overwritten, depending on subclass implementations. Any {@code
28.379 + * TimeZone} value that has previously been set by a call to
28.380 + * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
28.381 + * to be restored for further operations.
28.382 + *
28.383 + * @param source The date/time string to be parsed
28.384 + *
28.385 + * @param pos On input, the position at which to start parsing; on
28.386 + * output, the position at which parsing terminated, or the
28.387 + * start position if the parse failed.
28.388 + *
28.389 + * @return A {@code Date}, or {@code null} if the input could not be parsed
28.390 + */
28.391 + public abstract Date parse(String source, ParsePosition pos);
28.392 +
28.393 + /**
28.394 + * Parses text from a string to produce a <code>Date</code>.
28.395 + * <p>
28.396 + * The method attempts to parse text starting at the index given by
28.397 + * <code>pos</code>.
28.398 + * If parsing succeeds, then the index of <code>pos</code> is updated
28.399 + * to the index after the last character used (parsing does not necessarily
28.400 + * use all characters up to the end of the string), and the parsed
28.401 + * date is returned. The updated <code>pos</code> can be used to
28.402 + * indicate the starting point for the next call to this method.
28.403 + * If an error occurs, then the index of <code>pos</code> is not
28.404 + * changed, the error index of <code>pos</code> is set to the index of
28.405 + * the character where the error occurred, and null is returned.
28.406 + * <p>
28.407 + * See the {@link #parse(String, ParsePosition)} method for more information
28.408 + * on date parsing.
28.409 + *
28.410 + * @param source A <code>String</code>, part of which should be parsed.
28.411 + * @param pos A <code>ParsePosition</code> object with index and error
28.412 + * index information as described above.
28.413 + * @return A <code>Date</code> parsed from the string. In case of
28.414 + * error, returns null.
28.415 + * @exception NullPointerException if <code>pos</code> is null.
28.416 + */
28.417 + public Object parseObject(String source, ParsePosition pos) {
28.418 + return parse(source, pos);
28.419 + }
28.420 +
28.421 + /**
28.422 + * Constant for full style pattern.
28.423 + */
28.424 + public static final int FULL = 0;
28.425 + /**
28.426 + * Constant for long style pattern.
28.427 + */
28.428 + public static final int LONG = 1;
28.429 + /**
28.430 + * Constant for medium style pattern.
28.431 + */
28.432 + public static final int MEDIUM = 2;
28.433 + /**
28.434 + * Constant for short style pattern.
28.435 + */
28.436 + public static final int SHORT = 3;
28.437 + /**
28.438 + * Constant for default style pattern. Its value is MEDIUM.
28.439 + */
28.440 + public static final int DEFAULT = MEDIUM;
28.441 +
28.442 + /**
28.443 + * Gets the time formatter with the default formatting style
28.444 + * for the default locale.
28.445 + * @return a time formatter.
28.446 + */
28.447 + public final static DateFormat getTimeInstance()
28.448 + {
28.449 + return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
28.450 + }
28.451 +
28.452 + /**
28.453 + * Gets the time formatter with the given formatting style
28.454 + * for the default locale.
28.455 + * @param style the given formatting style. For example,
28.456 + * SHORT for "h:mm a" in the US locale.
28.457 + * @return a time formatter.
28.458 + */
28.459 + public final static DateFormat getTimeInstance(int style)
28.460 + {
28.461 + return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
28.462 + }
28.463 +
28.464 + /**
28.465 + * Gets the time formatter with the given formatting style
28.466 + * for the given locale.
28.467 + * @param style the given formatting style. For example,
28.468 + * SHORT for "h:mm a" in the US locale.
28.469 + * @param aLocale the given locale.
28.470 + * @return a time formatter.
28.471 + */
28.472 + public final static DateFormat getTimeInstance(int style,
28.473 + Locale aLocale)
28.474 + {
28.475 + return get(style, 0, 1, aLocale);
28.476 + }
28.477 +
28.478 + /**
28.479 + * Gets the date formatter with the default formatting style
28.480 + * for the default locale.
28.481 + * @return a date formatter.
28.482 + */
28.483 + public final static DateFormat getDateInstance()
28.484 + {
28.485 + return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
28.486 + }
28.487 +
28.488 + /**
28.489 + * Gets the date formatter with the given formatting style
28.490 + * for the default locale.
28.491 + * @param style the given formatting style. For example,
28.492 + * SHORT for "M/d/yy" in the US locale.
28.493 + * @return a date formatter.
28.494 + */
28.495 + public final static DateFormat getDateInstance(int style)
28.496 + {
28.497 + return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
28.498 + }
28.499 +
28.500 + /**
28.501 + * Gets the date formatter with the given formatting style
28.502 + * for the given locale.
28.503 + * @param style the given formatting style. For example,
28.504 + * SHORT for "M/d/yy" in the US locale.
28.505 + * @param aLocale the given locale.
28.506 + * @return a date formatter.
28.507 + */
28.508 + public final static DateFormat getDateInstance(int style,
28.509 + Locale aLocale)
28.510 + {
28.511 + return get(0, style, 2, aLocale);
28.512 + }
28.513 +
28.514 + /**
28.515 + * Gets the date/time formatter with the default formatting style
28.516 + * for the default locale.
28.517 + * @return a date/time formatter.
28.518 + */
28.519 + public final static DateFormat getDateTimeInstance()
28.520 + {
28.521 + return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
28.522 + }
28.523 +
28.524 + /**
28.525 + * Gets the date/time formatter with the given date and time
28.526 + * formatting styles for the default locale.
28.527 + * @param dateStyle the given date formatting style. For example,
28.528 + * SHORT for "M/d/yy" in the US locale.
28.529 + * @param timeStyle the given time formatting style. For example,
28.530 + * SHORT for "h:mm a" in the US locale.
28.531 + * @return a date/time formatter.
28.532 + */
28.533 + public final static DateFormat getDateTimeInstance(int dateStyle,
28.534 + int timeStyle)
28.535 + {
28.536 + return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
28.537 + }
28.538 +
28.539 + /**
28.540 + * Gets the date/time formatter with the given formatting styles
28.541 + * for the given locale.
28.542 + * @param dateStyle the given date formatting style.
28.543 + * @param timeStyle the given time formatting style.
28.544 + * @param aLocale the given locale.
28.545 + * @return a date/time formatter.
28.546 + */
28.547 + public final static DateFormat
28.548 + getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
28.549 + {
28.550 + return get(timeStyle, dateStyle, 3, aLocale);
28.551 + }
28.552 +
28.553 + /**
28.554 + * Get a default date/time formatter that uses the SHORT style for both the
28.555 + * date and the time.
28.556 + */
28.557 + public final static DateFormat getInstance() {
28.558 + return getDateTimeInstance(SHORT, SHORT);
28.559 + }
28.560 +
28.561 + /**
28.562 + * Returns an array of all locales for which the
28.563 + * <code>get*Instance</code> methods of this class can return
28.564 + * localized instances.
28.565 + * The returned array represents the union of locales supported by the Java
28.566 + * runtime and by installed
28.567 + * {@link java.text.spi.DateFormatProvider DateFormatProvider} implementations.
28.568 + * It must contain at least a <code>Locale</code> instance equal to
28.569 + * {@link java.util.Locale#US Locale.US}.
28.570 + *
28.571 + * @return An array of locales for which localized
28.572 + * <code>DateFormat</code> instances are available.
28.573 + */
28.574 + public static Locale[] getAvailableLocales()
28.575 + {
28.576 + LocaleServiceProviderPool pool =
28.577 + LocaleServiceProviderPool.getPool(DateFormatProvider.class);
28.578 + return pool.getAvailableLocales();
28.579 + }
28.580 +
28.581 + /**
28.582 + * Set the calendar to be used by this date format. Initially, the default
28.583 + * calendar for the specified or default locale is used.
28.584 + *
28.585 + * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
28.586 + * #isLenient() leniency} values that have previously been set are
28.587 + * overwritten by {@code newCalendar}'s values.
28.588 + *
28.589 + * @param newCalendar the new {@code Calendar} to be used by the date format
28.590 + */
28.591 + public void setCalendar(Calendar newCalendar)
28.592 + {
28.593 + this.calendar = newCalendar;
28.594 + }
28.595 +
28.596 + /**
28.597 + * Gets the calendar associated with this date/time formatter.
28.598 + *
28.599 + * @return the calendar associated with this date/time formatter.
28.600 + */
28.601 + public Calendar getCalendar()
28.602 + {
28.603 + return calendar;
28.604 + }
28.605 +
28.606 + /**
28.607 + * Allows you to set the number formatter.
28.608 + * @param newNumberFormat the given new NumberFormat.
28.609 + */
28.610 + public void setNumberFormat(NumberFormat newNumberFormat)
28.611 + {
28.612 + this.numberFormat = newNumberFormat;
28.613 + }
28.614 +
28.615 + /**
28.616 + * Gets the number formatter which this date/time formatter uses to
28.617 + * format and parse a time.
28.618 + * @return the number formatter which this date/time formatter uses.
28.619 + */
28.620 + public NumberFormat getNumberFormat()
28.621 + {
28.622 + return numberFormat;
28.623 + }
28.624 +
28.625 + /**
28.626 + * Sets the time zone for the calendar of this {@code DateFormat} object.
28.627 + * This method is equivalent to the following call.
28.628 + * <blockquote><pre>
28.629 + * getCalendar().setTimeZone(zone)
28.630 + * </pre></blockquote>
28.631 + *
28.632 + * <p>The {@code TimeZone} set by this method is overwritten by a
28.633 + * {@link #setCalendar(java.util.Calendar) setCalendar} call.
28.634 + *
28.635 + * <p>The {@code TimeZone} set by this method may be overwritten as
28.636 + * a result of a call to the parse method.
28.637 + *
28.638 + * @param zone the given new time zone.
28.639 + */
28.640 + public void setTimeZone(TimeZone zone)
28.641 + {
28.642 + calendar.setTimeZone(zone);
28.643 + }
28.644 +
28.645 + /**
28.646 + * Gets the time zone.
28.647 + * This method is equivalent to the following call.
28.648 + * <blockquote><pre>
28.649 + * getCalendar().getTimeZone()
28.650 + * </pre></blockquote>
28.651 + *
28.652 + * @return the time zone associated with the calendar of DateFormat.
28.653 + */
28.654 + public TimeZone getTimeZone()
28.655 + {
28.656 + return calendar.getTimeZone();
28.657 + }
28.658 +
28.659 + /**
28.660 + * Specify whether or not date/time parsing is to be lenient. With
28.661 + * lenient parsing, the parser may use heuristics to interpret inputs that
28.662 + * do not precisely match this object's format. With strict parsing,
28.663 + * inputs must match this object's format.
28.664 + *
28.665 + * <p>This method is equivalent to the following call.
28.666 + * <blockquote><pre>
28.667 + * getCalendar().setLenient(lenient)
28.668 + * </pre></blockquote>
28.669 + *
28.670 + * <p>This leniency value is overwritten by a call to {@link
28.671 + * #setCalendar(java.util.Calendar) setCalendar()}.
28.672 + *
28.673 + * @param lenient when {@code true}, parsing is lenient
28.674 + * @see java.util.Calendar#setLenient(boolean)
28.675 + */
28.676 + public void setLenient(boolean lenient)
28.677 + {
28.678 + calendar.setLenient(lenient);
28.679 + }
28.680 +
28.681 + /**
28.682 + * Tell whether date/time parsing is to be lenient.
28.683 + * This method is equivalent to the following call.
28.684 + * <blockquote><pre>
28.685 + * getCalendar().isLenient()
28.686 + * </pre></blockquote>
28.687 + *
28.688 + * @return {@code true} if the {@link #calendar} is lenient;
28.689 + * {@code false} otherwise.
28.690 + * @see java.util.Calendar#isLenient()
28.691 + */
28.692 + public boolean isLenient()
28.693 + {
28.694 + return calendar.isLenient();
28.695 + }
28.696 +
28.697 + /**
28.698 + * Overrides hashCode
28.699 + */
28.700 + public int hashCode() {
28.701 + return numberFormat.hashCode();
28.702 + // just enough fields for a reasonable distribution
28.703 + }
28.704 +
28.705 + /**
28.706 + * Overrides equals
28.707 + */
28.708 + public boolean equals(Object obj) {
28.709 + if (this == obj) return true;
28.710 + if (obj == null || getClass() != obj.getClass()) return false;
28.711 + DateFormat other = (DateFormat) obj;
28.712 + return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
28.713 + calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
28.714 + calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
28.715 + calendar.isLenient() == other.calendar.isLenient() &&
28.716 + calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
28.717 + numberFormat.equals(other.numberFormat));
28.718 + }
28.719 +
28.720 + /**
28.721 + * Overrides Cloneable
28.722 + */
28.723 + public Object clone()
28.724 + {
28.725 + DateFormat other = (DateFormat) super.clone();
28.726 + other.calendar = (Calendar) calendar.clone();
28.727 + other.numberFormat = (NumberFormat) numberFormat.clone();
28.728 + return other;
28.729 + }
28.730 +
28.731 + /**
28.732 + * Creates a DateFormat with the given time and/or date style in the given
28.733 + * locale.
28.734 + * @param timeStyle a value from 0 to 3 indicating the time format,
28.735 + * ignored if flags is 2
28.736 + * @param dateStyle a value from 0 to 3 indicating the time format,
28.737 + * ignored if flags is 1
28.738 + * @param flags either 1 for a time format, 2 for a date format,
28.739 + * or 3 for a date/time format
28.740 + * @param loc the locale for the format
28.741 + */
28.742 + private static DateFormat get(int timeStyle, int dateStyle,
28.743 + int flags, Locale loc) {
28.744 + if ((flags & 1) != 0) {
28.745 + if (timeStyle < 0 || timeStyle > 3) {
28.746 + throw new IllegalArgumentException("Illegal time style " + timeStyle);
28.747 + }
28.748 + } else {
28.749 + timeStyle = -1;
28.750 + }
28.751 + if ((flags & 2) != 0) {
28.752 + if (dateStyle < 0 || dateStyle > 3) {
28.753 + throw new IllegalArgumentException("Illegal date style " + dateStyle);
28.754 + }
28.755 + } else {
28.756 + dateStyle = -1;
28.757 + }
28.758 + try {
28.759 + // Check whether a provider can provide an implementation that's closer
28.760 + // to the requested locale than what the Java runtime itself can provide.
28.761 + LocaleServiceProviderPool pool =
28.762 + LocaleServiceProviderPool.getPool(DateFormatProvider.class);
28.763 + if (pool.hasProviders()) {
28.764 + DateFormat providersInstance = pool.getLocalizedObject(
28.765 + DateFormatGetter.INSTANCE,
28.766 + loc,
28.767 + timeStyle,
28.768 + dateStyle,
28.769 + flags);
28.770 + if (providersInstance != null) {
28.771 + return providersInstance;
28.772 + }
28.773 + }
28.774 +
28.775 + return new SimpleDateFormat(timeStyle, dateStyle, loc);
28.776 + } catch (MissingResourceException e) {
28.777 + return new SimpleDateFormat("M/d/yy h:mm a");
28.778 + }
28.779 + }
28.780 +
28.781 + /**
28.782 + * Create a new date format.
28.783 + */
28.784 + protected DateFormat() {}
28.785 +
28.786 + /**
28.787 + * Defines constants that are used as attribute keys in the
28.788 + * <code>AttributedCharacterIterator</code> returned
28.789 + * from <code>DateFormat.formatToCharacterIterator</code> and as
28.790 + * field identifiers in <code>FieldPosition</code>.
28.791 + * <p>
28.792 + * The class also provides two methods to map
28.793 + * between its constants and the corresponding Calendar constants.
28.794 + *
28.795 + * @since 1.4
28.796 + * @see java.util.Calendar
28.797 + */
28.798 + public static class Field extends Format.Field {
28.799 +
28.800 + // Proclaim serial compatibility with 1.4 FCS
28.801 + private static final long serialVersionUID = 7441350119349544720L;
28.802 +
28.803 + // table of all instances in this class, used by readResolve
28.804 + private static final Map instanceMap = new HashMap(18);
28.805 + // Maps from Calendar constant (such as Calendar.ERA) to Field
28.806 + // constant (such as Field.ERA).
28.807 + private static final Field[] calendarToFieldMapping =
28.808 + new Field[Calendar.FIELD_COUNT];
28.809 +
28.810 + /** Calendar field. */
28.811 + private int calendarField;
28.812 +
28.813 + /**
28.814 + * Returns the <code>Field</code> constant that corresponds to
28.815 + * the <code>Calendar</code> constant <code>calendarField</code>.
28.816 + * If there is no direct mapping between the <code>Calendar</code>
28.817 + * constant and a <code>Field</code>, null is returned.
28.818 + *
28.819 + * @throws IllegalArgumentException if <code>calendarField</code> is
28.820 + * not the value of a <code>Calendar</code> field constant.
28.821 + * @param calendarField Calendar field constant
28.822 + * @return Field instance representing calendarField.
28.823 + * @see java.util.Calendar
28.824 + */
28.825 + public static Field ofCalendarField(int calendarField) {
28.826 + if (calendarField < 0 || calendarField >=
28.827 + calendarToFieldMapping.length) {
28.828 + throw new IllegalArgumentException("Unknown Calendar constant "
28.829 + + calendarField);
28.830 + }
28.831 + return calendarToFieldMapping[calendarField];
28.832 + }
28.833 +
28.834 + /**
28.835 + * Creates a <code>Field</code>.
28.836 + *
28.837 + * @param name the name of the <code>Field</code>
28.838 + * @param calendarField the <code>Calendar</code> constant this
28.839 + * <code>Field</code> corresponds to; any value, even one
28.840 + * outside the range of legal <code>Calendar</code> values may
28.841 + * be used, but <code>-1</code> should be used for values
28.842 + * that don't correspond to legal <code>Calendar</code> values
28.843 + */
28.844 + protected Field(String name, int calendarField) {
28.845 + super(name);
28.846 + this.calendarField = calendarField;
28.847 + if (this.getClass() == DateFormat.Field.class) {
28.848 + instanceMap.put(name, this);
28.849 + if (calendarField >= 0) {
28.850 + // assert(calendarField < Calendar.FIELD_COUNT);
28.851 + calendarToFieldMapping[calendarField] = this;
28.852 + }
28.853 + }
28.854 + }
28.855 +
28.856 + /**
28.857 + * Returns the <code>Calendar</code> field associated with this
28.858 + * attribute. For example, if this represents the hours field of
28.859 + * a <code>Calendar</code>, this would return
28.860 + * <code>Calendar.HOUR</code>. If there is no corresponding
28.861 + * <code>Calendar</code> constant, this will return -1.
28.862 + *
28.863 + * @return Calendar constant for this field
28.864 + * @see java.util.Calendar
28.865 + */
28.866 + public int getCalendarField() {
28.867 + return calendarField;
28.868 + }
28.869 +
28.870 + /**
28.871 + * Resolves instances being deserialized to the predefined constants.
28.872 + *
28.873 + * @throws InvalidObjectException if the constant could not be
28.874 + * resolved.
28.875 + * @return resolved DateFormat.Field constant
28.876 + */
28.877 + protected Object readResolve() throws InvalidObjectException {
28.878 + if (this.getClass() != DateFormat.Field.class) {
28.879 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
28.880 + }
28.881 +
28.882 + Object instance = instanceMap.get(getName());
28.883 + if (instance != null) {
28.884 + return instance;
28.885 + } else {
28.886 + throw new InvalidObjectException("unknown attribute name");
28.887 + }
28.888 + }
28.889 +
28.890 + //
28.891 + // The constants
28.892 + //
28.893 +
28.894 + /**
28.895 + * Constant identifying the era field.
28.896 + */
28.897 + public final static Field ERA = new Field("era", Calendar.ERA);
28.898 +
28.899 + /**
28.900 + * Constant identifying the year field.
28.901 + */
28.902 + public final static Field YEAR = new Field("year", Calendar.YEAR);
28.903 +
28.904 + /**
28.905 + * Constant identifying the month field.
28.906 + */
28.907 + public final static Field MONTH = new Field("month", Calendar.MONTH);
28.908 +
28.909 + /**
28.910 + * Constant identifying the day of month field.
28.911 + */
28.912 + public final static Field DAY_OF_MONTH = new
28.913 + Field("day of month", Calendar.DAY_OF_MONTH);
28.914 +
28.915 + /**
28.916 + * Constant identifying the hour of day field, where the legal values
28.917 + * are 1 to 24.
28.918 + */
28.919 + public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
28.920 +
28.921 + /**
28.922 + * Constant identifying the hour of day field, where the legal values
28.923 + * are 0 to 23.
28.924 + */
28.925 + public final static Field HOUR_OF_DAY0 = new
28.926 + Field("hour of day", Calendar.HOUR_OF_DAY);
28.927 +
28.928 + /**
28.929 + * Constant identifying the minute field.
28.930 + */
28.931 + public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
28.932 +
28.933 + /**
28.934 + * Constant identifying the second field.
28.935 + */
28.936 + public final static Field SECOND =new Field("second", Calendar.SECOND);
28.937 +
28.938 + /**
28.939 + * Constant identifying the millisecond field.
28.940 + */
28.941 + public final static Field MILLISECOND = new
28.942 + Field("millisecond", Calendar.MILLISECOND);
28.943 +
28.944 + /**
28.945 + * Constant identifying the day of week field.
28.946 + */
28.947 + public final static Field DAY_OF_WEEK = new
28.948 + Field("day of week", Calendar.DAY_OF_WEEK);
28.949 +
28.950 + /**
28.951 + * Constant identifying the day of year field.
28.952 + */
28.953 + public final static Field DAY_OF_YEAR = new
28.954 + Field("day of year", Calendar.DAY_OF_YEAR);
28.955 +
28.956 + /**
28.957 + * Constant identifying the day of week field.
28.958 + */
28.959 + public final static Field DAY_OF_WEEK_IN_MONTH =
28.960 + new Field("day of week in month",
28.961 + Calendar.DAY_OF_WEEK_IN_MONTH);
28.962 +
28.963 + /**
28.964 + * Constant identifying the week of year field.
28.965 + */
28.966 + public final static Field WEEK_OF_YEAR = new
28.967 + Field("week of year", Calendar.WEEK_OF_YEAR);
28.968 +
28.969 + /**
28.970 + * Constant identifying the week of month field.
28.971 + */
28.972 + public final static Field WEEK_OF_MONTH = new
28.973 + Field("week of month", Calendar.WEEK_OF_MONTH);
28.974 +
28.975 + /**
28.976 + * Constant identifying the time of day indicator
28.977 + * (e.g. "a.m." or "p.m.") field.
28.978 + */
28.979 + public final static Field AM_PM = new
28.980 + Field("am pm", Calendar.AM_PM);
28.981 +
28.982 + /**
28.983 + * Constant identifying the hour field, where the legal values are
28.984 + * 1 to 12.
28.985 + */
28.986 + public final static Field HOUR1 = new Field("hour 1", -1);
28.987 +
28.988 + /**
28.989 + * Constant identifying the hour field, where the legal values are
28.990 + * 0 to 11.
28.991 + */
28.992 + public final static Field HOUR0 = new
28.993 + Field("hour", Calendar.HOUR);
28.994 +
28.995 + /**
28.996 + * Constant identifying the time zone field.
28.997 + */
28.998 + public final static Field TIME_ZONE = new Field("time zone", -1);
28.999 + }
28.1000 +
28.1001 + /**
28.1002 + * Obtains a DateFormat instance from a DateFormatProvider
28.1003 + * implementation.
28.1004 + */
28.1005 + private static class DateFormatGetter
28.1006 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatProvider, DateFormat> {
28.1007 + private static final DateFormatGetter INSTANCE = new DateFormatGetter();
28.1008 +
28.1009 + public DateFormat getObject(DateFormatProvider dateFormatProvider,
28.1010 + Locale locale,
28.1011 + String key,
28.1012 + Object... params) {
28.1013 + assert params.length == 3;
28.1014 +
28.1015 + int timeStyle = (Integer)params[0];
28.1016 + int dateStyle = (Integer)params[1];
28.1017 + int flags = (Integer)params[2];
28.1018 +
28.1019 + switch (flags) {
28.1020 + case 1:
28.1021 + return dateFormatProvider.getTimeInstance(timeStyle, locale);
28.1022 + case 2:
28.1023 + return dateFormatProvider.getDateInstance(dateStyle, locale);
28.1024 + case 3:
28.1025 + return dateFormatProvider.getDateTimeInstance(dateStyle, timeStyle, locale);
28.1026 + default:
28.1027 + assert false : "should not happen";
28.1028 + }
28.1029 +
28.1030 + return null;
28.1031 + }
28.1032 + }
28.1033 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormatSymbols.java Thu Oct 03 15:43:10 2013 +0200
29.3 @@ -0,0 +1,794 @@
29.4 +/*
29.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
29.7 + *
29.8 + * This code is free software; you can redistribute it and/or modify it
29.9 + * under the terms of the GNU General Public License version 2 only, as
29.10 + * published by the Free Software Foundation. Oracle designates this
29.11 + * particular file as subject to the "Classpath" exception as provided
29.12 + * by Oracle in the LICENSE file that accompanied this code.
29.13 + *
29.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
29.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
29.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29.17 + * version 2 for more details (a copy is included in the LICENSE file that
29.18 + * accompanied this code).
29.19 + *
29.20 + * You should have received a copy of the GNU General Public License version
29.21 + * 2 along with this work; if not, write to the Free Software Foundation,
29.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29.23 + *
29.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
29.25 + * or visit www.oracle.com if you need additional information or have any
29.26 + * questions.
29.27 + */
29.28 +
29.29 +/*
29.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
29.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29.32 + *
29.33 + * The original version of this source code and documentation is copyrighted
29.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
29.35 + * materials are provided under terms of a License Agreement between Taligent
29.36 + * and Sun. This technology is protected by multiple US and International
29.37 + * patents. This notice and attribution to Taligent may not be removed.
29.38 + * Taligent is a registered trademark of Taligent, Inc.
29.39 + *
29.40 + */
29.41 +
29.42 +package java.text;
29.43 +
29.44 +import java.io.IOException;
29.45 +import java.io.ObjectOutputStream;
29.46 +import java.io.Serializable;
29.47 +import java.lang.ref.SoftReference;
29.48 +import java.text.spi.DateFormatSymbolsProvider;
29.49 +import java.util.Arrays;
29.50 +import java.util.List;
29.51 +import java.util.Locale;
29.52 +import java.util.ResourceBundle;
29.53 +import java.util.TimeZone;
29.54 +import java.util.concurrent.ConcurrentHashMap;
29.55 +import java.util.concurrent.ConcurrentMap;
29.56 +import java.util.spi.LocaleServiceProvider;
29.57 +import sun.util.LocaleServiceProviderPool;
29.58 +import sun.util.TimeZoneNameUtility;
29.59 +import sun.util.calendar.ZoneInfo;
29.60 +import sun.util.resources.LocaleData;
29.61 +
29.62 +/**
29.63 + * <code>DateFormatSymbols</code> is a public class for encapsulating
29.64 + * localizable date-time formatting data, such as the names of the
29.65 + * months, the names of the days of the week, and the time zone data.
29.66 + * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
29.67 + * <code>DateFormatSymbols</code> to encapsulate this information.
29.68 + *
29.69 + * <p>
29.70 + * Typically you shouldn't use <code>DateFormatSymbols</code> directly.
29.71 + * Rather, you are encouraged to create a date-time formatter with the
29.72 + * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
29.73 + * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
29.74 + * These methods automatically create a <code>DateFormatSymbols</code> for
29.75 + * the formatter so that you don't have to. After the
29.76 + * formatter is created, you may modify its format pattern using the
29.77 + * <code>setPattern</code> method. For more information about
29.78 + * creating formatters using <code>DateFormat</code>'s factory methods,
29.79 + * see {@link DateFormat}.
29.80 + *
29.81 + * <p>
29.82 + * If you decide to create a date-time formatter with a specific
29.83 + * format pattern for a specific locale, you can do so with:
29.84 + * <blockquote>
29.85 + * <pre>
29.86 + * new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
29.87 + * </pre>
29.88 + * </blockquote>
29.89 + *
29.90 + * <p>
29.91 + * <code>DateFormatSymbols</code> objects are cloneable. When you obtain
29.92 + * a <code>DateFormatSymbols</code> object, feel free to modify the
29.93 + * date-time formatting data. For instance, you can replace the localized
29.94 + * date-time format pattern characters with the ones that you feel easy
29.95 + * to remember. Or you can change the representative cities
29.96 + * to your favorite ones.
29.97 + *
29.98 + * <p>
29.99 + * New <code>DateFormatSymbols</code> subclasses may be added to support
29.100 + * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
29.101 +
29.102 + * @see DateFormat
29.103 + * @see SimpleDateFormat
29.104 + * @see java.util.SimpleTimeZone
29.105 + * @author Chen-Lieh Huang
29.106 + */
29.107 +public class DateFormatSymbols implements Serializable, Cloneable {
29.108 +
29.109 + /**
29.110 + * Construct a DateFormatSymbols object by loading format data from
29.111 + * resources for the default locale. This constructor can only
29.112 + * construct instances for the locales supported by the Java
29.113 + * runtime environment, not for those supported by installed
29.114 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
29.115 + * implementations. For full locale coverage, use the
29.116 + * {@link #getInstance(Locale) getInstance} method.
29.117 + *
29.118 + * @see #getInstance()
29.119 + * @exception java.util.MissingResourceException
29.120 + * if the resources for the default locale cannot be
29.121 + * found or cannot be loaded.
29.122 + */
29.123 + public DateFormatSymbols()
29.124 + {
29.125 + initializeData(Locale.getDefault(Locale.Category.FORMAT));
29.126 + }
29.127 +
29.128 + /**
29.129 + * Construct a DateFormatSymbols object by loading format data from
29.130 + * resources for the given locale. This constructor can only
29.131 + * construct instances for the locales supported by the Java
29.132 + * runtime environment, not for those supported by installed
29.133 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
29.134 + * implementations. For full locale coverage, use the
29.135 + * {@link #getInstance(Locale) getInstance} method.
29.136 + *
29.137 + * @see #getInstance(Locale)
29.138 + * @exception java.util.MissingResourceException
29.139 + * if the resources for the specified locale cannot be
29.140 + * found or cannot be loaded.
29.141 + */
29.142 + public DateFormatSymbols(Locale locale)
29.143 + {
29.144 + initializeData(locale);
29.145 + }
29.146 +
29.147 + /**
29.148 + * Era strings. For example: "AD" and "BC". An array of 2 strings,
29.149 + * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
29.150 + * @serial
29.151 + */
29.152 + String eras[] = null;
29.153 +
29.154 + /**
29.155 + * Month strings. For example: "January", "February", etc. An array
29.156 + * of 13 strings (some calendars have 13 months), indexed by
29.157 + * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
29.158 + * @serial
29.159 + */
29.160 + String months[] = null;
29.161 +
29.162 + /**
29.163 + * Short month strings. For example: "Jan", "Feb", etc. An array of
29.164 + * 13 strings (some calendars have 13 months), indexed by
29.165 + * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
29.166 +
29.167 + * @serial
29.168 + */
29.169 + String shortMonths[] = null;
29.170 +
29.171 + /**
29.172 + * Weekday strings. For example: "Sunday", "Monday", etc. An array
29.173 + * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
29.174 + * <code>Calendar.MONDAY</code>, etc.
29.175 + * The element <code>weekdays[0]</code> is ignored.
29.176 + * @serial
29.177 + */
29.178 + String weekdays[] = null;
29.179 +
29.180 + /**
29.181 + * Short weekday strings. For example: "Sun", "Mon", etc. An array
29.182 + * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
29.183 + * <code>Calendar.MONDAY</code>, etc.
29.184 + * The element <code>shortWeekdays[0]</code> is ignored.
29.185 + * @serial
29.186 + */
29.187 + String shortWeekdays[] = null;
29.188 +
29.189 + /**
29.190 + * AM and PM strings. For example: "AM" and "PM". An array of
29.191 + * 2 strings, indexed by <code>Calendar.AM</code> and
29.192 + * <code>Calendar.PM</code>.
29.193 + * @serial
29.194 + */
29.195 + String ampms[] = null;
29.196 +
29.197 + /**
29.198 + * Localized names of time zones in this locale. This is a
29.199 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
29.200 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
29.201 + * entry containing the localized names for a single <code>TimeZone</code>.
29.202 + * Each such row contains (with <code>i</code> ranging from
29.203 + * 0..<em>n</em>-1):
29.204 + * <ul>
29.205 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
29.206 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
29.207 + * time</li>
29.208 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
29.209 + * standard time</li>
29.210 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
29.211 + * saving time</li>
29.212 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
29.213 + * saving time</li>
29.214 + * </ul>
29.215 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
29.216 + * the {@link java.util.TimeZone TimeZone} class that are not
29.217 + * <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
29.218 + * All other entries are localized names.
29.219 + * @see java.util.TimeZone
29.220 + * @serial
29.221 + */
29.222 + String zoneStrings[][] = null;
29.223 +
29.224 + /**
29.225 + * Indicates that zoneStrings is set externally with setZoneStrings() method.
29.226 + */
29.227 + transient boolean isZoneStringsSet = false;
29.228 +
29.229 + /**
29.230 + * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
29.231 + * All locales use the same these unlocalized pattern characters.
29.232 + */
29.233 + static final String patternChars = "GyMdkHmsSEDFwWahKzZYuX";
29.234 +
29.235 + static final int PATTERN_ERA = 0; // G
29.236 + static final int PATTERN_YEAR = 1; // y
29.237 + static final int PATTERN_MONTH = 2; // M
29.238 + static final int PATTERN_DAY_OF_MONTH = 3; // d
29.239 + static final int PATTERN_HOUR_OF_DAY1 = 4; // k
29.240 + static final int PATTERN_HOUR_OF_DAY0 = 5; // H
29.241 + static final int PATTERN_MINUTE = 6; // m
29.242 + static final int PATTERN_SECOND = 7; // s
29.243 + static final int PATTERN_MILLISECOND = 8; // S
29.244 + static final int PATTERN_DAY_OF_WEEK = 9; // E
29.245 + static final int PATTERN_DAY_OF_YEAR = 10; // D
29.246 + static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
29.247 + static final int PATTERN_WEEK_OF_YEAR = 12; // w
29.248 + static final int PATTERN_WEEK_OF_MONTH = 13; // W
29.249 + static final int PATTERN_AM_PM = 14; // a
29.250 + static final int PATTERN_HOUR1 = 15; // h
29.251 + static final int PATTERN_HOUR0 = 16; // K
29.252 + static final int PATTERN_ZONE_NAME = 17; // z
29.253 + static final int PATTERN_ZONE_VALUE = 18; // Z
29.254 + static final int PATTERN_WEEK_YEAR = 19; // Y
29.255 + static final int PATTERN_ISO_DAY_OF_WEEK = 20; // u
29.256 + static final int PATTERN_ISO_ZONE = 21; // X
29.257 +
29.258 + /**
29.259 + * Localized date-time pattern characters. For example, a locale may
29.260 + * wish to use 'u' rather than 'y' to represent years in its date format
29.261 + * pattern strings.
29.262 + * This string must be exactly 18 characters long, with the index of
29.263 + * the characters described by <code>DateFormat.ERA_FIELD</code>,
29.264 + * <code>DateFormat.YEAR_FIELD</code>, etc. Thus, if the string were
29.265 + * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
29.266 + * @serial
29.267 + */
29.268 + String localPatternChars = null;
29.269 +
29.270 + /**
29.271 + * The locale which is used for initializing this DateFormatSymbols object.
29.272 + *
29.273 + * @since 1.6
29.274 + * @serial
29.275 + */
29.276 + Locale locale = null;
29.277 +
29.278 + /* use serialVersionUID from JDK 1.1.4 for interoperability */
29.279 + static final long serialVersionUID = -5987973545549424702L;
29.280 +
29.281 + /**
29.282 + * Returns an array of all locales for which the
29.283 + * <code>getInstance</code> methods of this class can return
29.284 + * localized instances.
29.285 + * The returned array represents the union of locales supported by the
29.286 + * Java runtime and by installed
29.287 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
29.288 + * implementations. It must contain at least a <code>Locale</code>
29.289 + * instance equal to {@link java.util.Locale#US Locale.US}.
29.290 + *
29.291 + * @return An array of locales for which localized
29.292 + * <code>DateFormatSymbols</code> instances are available.
29.293 + * @since 1.6
29.294 + */
29.295 + public static Locale[] getAvailableLocales() {
29.296 + LocaleServiceProviderPool pool=
29.297 + LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
29.298 + return pool.getAvailableLocales();
29.299 + }
29.300 +
29.301 + /**
29.302 + * Gets the <code>DateFormatSymbols</code> instance for the default
29.303 + * locale. This method provides access to <code>DateFormatSymbols</code>
29.304 + * instances for locales supported by the Java runtime itself as well
29.305 + * as for those supported by installed
29.306 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
29.307 + * implementations.
29.308 + * @return a <code>DateFormatSymbols</code> instance.
29.309 + * @since 1.6
29.310 + */
29.311 + public static final DateFormatSymbols getInstance() {
29.312 + return getInstance(Locale.getDefault(Locale.Category.FORMAT));
29.313 + }
29.314 +
29.315 + /**
29.316 + * Gets the <code>DateFormatSymbols</code> instance for the specified
29.317 + * locale. This method provides access to <code>DateFormatSymbols</code>
29.318 + * instances for locales supported by the Java runtime itself as well
29.319 + * as for those supported by installed
29.320 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
29.321 + * implementations.
29.322 + * @param locale the given locale.
29.323 + * @return a <code>DateFormatSymbols</code> instance.
29.324 + * @exception NullPointerException if <code>locale</code> is null
29.325 + * @since 1.6
29.326 + */
29.327 + public static final DateFormatSymbols getInstance(Locale locale) {
29.328 + DateFormatSymbols dfs = getProviderInstance(locale);
29.329 + if (dfs != null) {
29.330 + return dfs;
29.331 + }
29.332 + return (DateFormatSymbols) getCachedInstance(locale).clone();
29.333 + }
29.334 +
29.335 + /**
29.336 + * Returns a DateFormatSymbols provided by a provider or found in
29.337 + * the cache. Note that this method returns a cached instance,
29.338 + * not its clone. Therefore, the instance should never be given to
29.339 + * an application.
29.340 + */
29.341 + static final DateFormatSymbols getInstanceRef(Locale locale) {
29.342 + DateFormatSymbols dfs = getProviderInstance(locale);
29.343 + if (dfs != null) {
29.344 + return dfs;
29.345 + }
29.346 + return getCachedInstance(locale);
29.347 + }
29.348 +
29.349 + private static DateFormatSymbols getProviderInstance(Locale locale) {
29.350 + DateFormatSymbols providersInstance = null;
29.351 +
29.352 + // Check whether a provider can provide an implementation that's closer
29.353 + // to the requested locale than what the Java runtime itself can provide.
29.354 + LocaleServiceProviderPool pool =
29.355 + LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
29.356 + if (pool.hasProviders()) {
29.357 + providersInstance = pool.getLocalizedObject(
29.358 + DateFormatSymbolsGetter.INSTANCE, locale);
29.359 + }
29.360 + return providersInstance;
29.361 + }
29.362 +
29.363 + /**
29.364 + * Returns a cached DateFormatSymbols if it's found in the
29.365 + * cache. Otherwise, this method returns a newly cached instance
29.366 + * for the given locale.
29.367 + */
29.368 + private static DateFormatSymbols getCachedInstance(Locale locale) {
29.369 + SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
29.370 + DateFormatSymbols dfs = null;
29.371 + if (ref == null || (dfs = ref.get()) == null) {
29.372 + dfs = new DateFormatSymbols(locale);
29.373 + ref = new SoftReference<DateFormatSymbols>(dfs);
29.374 + SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
29.375 + if (x != null) {
29.376 + DateFormatSymbols y = x.get();
29.377 + if (y != null) {
29.378 + dfs = y;
29.379 + } else {
29.380 + // Replace the empty SoftReference with ref.
29.381 + cachedInstances.put(locale, ref);
29.382 + }
29.383 + }
29.384 + }
29.385 + return dfs;
29.386 + }
29.387 +
29.388 + /**
29.389 + * Gets era strings. For example: "AD" and "BC".
29.390 + * @return the era strings.
29.391 + */
29.392 + public String[] getEras() {
29.393 + return Arrays.copyOf(eras, eras.length);
29.394 + }
29.395 +
29.396 + /**
29.397 + * Sets era strings. For example: "AD" and "BC".
29.398 + * @param newEras the new era strings.
29.399 + */
29.400 + public void setEras(String[] newEras) {
29.401 + eras = Arrays.copyOf(newEras, newEras.length);
29.402 + }
29.403 +
29.404 + /**
29.405 + * Gets month strings. For example: "January", "February", etc.
29.406 + * @return the month strings.
29.407 + */
29.408 + public String[] getMonths() {
29.409 + return Arrays.copyOf(months, months.length);
29.410 + }
29.411 +
29.412 + /**
29.413 + * Sets month strings. For example: "January", "February", etc.
29.414 + * @param newMonths the new month strings.
29.415 + */
29.416 + public void setMonths(String[] newMonths) {
29.417 + months = Arrays.copyOf(newMonths, newMonths.length);
29.418 + }
29.419 +
29.420 + /**
29.421 + * Gets short month strings. For example: "Jan", "Feb", etc.
29.422 + * @return the short month strings.
29.423 + */
29.424 + public String[] getShortMonths() {
29.425 + return Arrays.copyOf(shortMonths, shortMonths.length);
29.426 + }
29.427 +
29.428 + /**
29.429 + * Sets short month strings. For example: "Jan", "Feb", etc.
29.430 + * @param newShortMonths the new short month strings.
29.431 + */
29.432 + public void setShortMonths(String[] newShortMonths) {
29.433 + shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
29.434 + }
29.435 +
29.436 + /**
29.437 + * Gets weekday strings. For example: "Sunday", "Monday", etc.
29.438 + * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
29.439 + * <code>Calendar.MONDAY</code>, etc. to index the result array.
29.440 + */
29.441 + public String[] getWeekdays() {
29.442 + return Arrays.copyOf(weekdays, weekdays.length);
29.443 + }
29.444 +
29.445 + /**
29.446 + * Sets weekday strings. For example: "Sunday", "Monday", etc.
29.447 + * @param newWeekdays the new weekday strings. The array should
29.448 + * be indexed by <code>Calendar.SUNDAY</code>,
29.449 + * <code>Calendar.MONDAY</code>, etc.
29.450 + */
29.451 + public void setWeekdays(String[] newWeekdays) {
29.452 + weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
29.453 + }
29.454 +
29.455 + /**
29.456 + * Gets short weekday strings. For example: "Sun", "Mon", etc.
29.457 + * @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
29.458 + * <code>Calendar.MONDAY</code>, etc. to index the result array.
29.459 + */
29.460 + public String[] getShortWeekdays() {
29.461 + return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
29.462 + }
29.463 +
29.464 + /**
29.465 + * Sets short weekday strings. For example: "Sun", "Mon", etc.
29.466 + * @param newShortWeekdays the new short weekday strings. The array should
29.467 + * be indexed by <code>Calendar.SUNDAY</code>,
29.468 + * <code>Calendar.MONDAY</code>, etc.
29.469 + */
29.470 + public void setShortWeekdays(String[] newShortWeekdays) {
29.471 + shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
29.472 + }
29.473 +
29.474 + /**
29.475 + * Gets ampm strings. For example: "AM" and "PM".
29.476 + * @return the ampm strings.
29.477 + */
29.478 + public String[] getAmPmStrings() {
29.479 + return Arrays.copyOf(ampms, ampms.length);
29.480 + }
29.481 +
29.482 + /**
29.483 + * Sets ampm strings. For example: "AM" and "PM".
29.484 + * @param newAmpms the new ampm strings.
29.485 + */
29.486 + public void setAmPmStrings(String[] newAmpms) {
29.487 + ampms = Arrays.copyOf(newAmpms, newAmpms.length);
29.488 + }
29.489 +
29.490 + /**
29.491 + * Gets time zone strings. Use of this method is discouraged; use
29.492 + * {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
29.493 + * instead.
29.494 + * <p>
29.495 + * The value returned is a
29.496 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
29.497 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
29.498 + * entry containing the localized names for a single <code>TimeZone</code>.
29.499 + * Each such row contains (with <code>i</code> ranging from
29.500 + * 0..<em>n</em>-1):
29.501 + * <ul>
29.502 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
29.503 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
29.504 + * time</li>
29.505 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
29.506 + * standard time</li>
29.507 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
29.508 + * saving time</li>
29.509 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
29.510 + * saving time</li>
29.511 + * </ul>
29.512 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
29.513 + * the {@link java.util.TimeZone TimeZone} class that are not
29.514 + * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
29.515 + * All other entries are localized names. If a zone does not implement
29.516 + * daylight saving time, the daylight saving time names should not be used.
29.517 + * <p>
29.518 + * If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
29.519 + * on this <code>DateFormatSymbols</code> instance, then the strings
29.520 + * provided by that call are returned. Otherwise, the returned array
29.521 + * contains names provided by the Java runtime and by installed
29.522 + * {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider}
29.523 + * implementations.
29.524 + *
29.525 + * @return the time zone strings.
29.526 + * @see #setZoneStrings(String[][])
29.527 + */
29.528 + public String[][] getZoneStrings() {
29.529 + return getZoneStringsImpl(true);
29.530 + }
29.531 +
29.532 + /**
29.533 + * Sets time zone strings. The argument must be a
29.534 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
29.535 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
29.536 + * entry containing the localized names for a single <code>TimeZone</code>.
29.537 + * Each such row contains (with <code>i</code> ranging from
29.538 + * 0..<em>n</em>-1):
29.539 + * <ul>
29.540 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
29.541 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
29.542 + * time</li>
29.543 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
29.544 + * standard time</li>
29.545 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
29.546 + * saving time</li>
29.547 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
29.548 + * saving time</li>
29.549 + * </ul>
29.550 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
29.551 + * the {@link java.util.TimeZone TimeZone} class that are not
29.552 + * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
29.553 + * All other entries are localized names.
29.554 + *
29.555 + * @param newZoneStrings the new time zone strings.
29.556 + * @exception IllegalArgumentException if the length of any row in
29.557 + * <code>newZoneStrings</code> is less than 5
29.558 + * @exception NullPointerException if <code>newZoneStrings</code> is null
29.559 + * @see #getZoneStrings()
29.560 + */
29.561 + public void setZoneStrings(String[][] newZoneStrings) {
29.562 + String[][] aCopy = new String[newZoneStrings.length][];
29.563 + for (int i = 0; i < newZoneStrings.length; ++i) {
29.564 + int len = newZoneStrings[i].length;
29.565 + if (len < 5) {
29.566 + throw new IllegalArgumentException();
29.567 + }
29.568 + aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
29.569 + }
29.570 + zoneStrings = aCopy;
29.571 + isZoneStringsSet = true;
29.572 + }
29.573 +
29.574 + /**
29.575 + * Gets localized date-time pattern characters. For example: 'u', 't', etc.
29.576 + * @return the localized date-time pattern characters.
29.577 + */
29.578 + public String getLocalPatternChars() {
29.579 + return localPatternChars;
29.580 + }
29.581 +
29.582 + /**
29.583 + * Sets localized date-time pattern characters. For example: 'u', 't', etc.
29.584 + * @param newLocalPatternChars the new localized date-time
29.585 + * pattern characters.
29.586 + */
29.587 + public void setLocalPatternChars(String newLocalPatternChars) {
29.588 + // Call toString() to throw an NPE in case the argument is null
29.589 + localPatternChars = newLocalPatternChars.toString();
29.590 + }
29.591 +
29.592 + /**
29.593 + * Overrides Cloneable
29.594 + */
29.595 + public Object clone()
29.596 + {
29.597 + try
29.598 + {
29.599 + DateFormatSymbols other = (DateFormatSymbols)super.clone();
29.600 + copyMembers(this, other);
29.601 + return other;
29.602 + } catch (CloneNotSupportedException e) {
29.603 + throw new InternalError();
29.604 + }
29.605 + }
29.606 +
29.607 + /**
29.608 + * Override hashCode.
29.609 + * Generates a hash code for the DateFormatSymbols object.
29.610 + */
29.611 + public int hashCode() {
29.612 + int hashcode = 0;
29.613 + String[][] zoneStrings = getZoneStringsWrapper();
29.614 + for (int index = 0; index < zoneStrings[0].length; ++index)
29.615 + hashcode ^= zoneStrings[0][index].hashCode();
29.616 + return hashcode;
29.617 + }
29.618 +
29.619 + /**
29.620 + * Override equals
29.621 + */
29.622 + public boolean equals(Object obj)
29.623 + {
29.624 + if (this == obj) return true;
29.625 + if (obj == null || getClass() != obj.getClass()) return false;
29.626 + DateFormatSymbols that = (DateFormatSymbols) obj;
29.627 + return (Arrays.equals(eras, that.eras)
29.628 + && Arrays.equals(months, that.months)
29.629 + && Arrays.equals(shortMonths, that.shortMonths)
29.630 + && Arrays.equals(weekdays, that.weekdays)
29.631 + && Arrays.equals(shortWeekdays, that.shortWeekdays)
29.632 + && Arrays.equals(ampms, that.ampms)
29.633 + && Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper())
29.634 + && ((localPatternChars != null
29.635 + && localPatternChars.equals(that.localPatternChars))
29.636 + || (localPatternChars == null
29.637 + && that.localPatternChars == null)));
29.638 + }
29.639 +
29.640 + // =======================privates===============================
29.641 +
29.642 + /**
29.643 + * Useful constant for defining time zone offsets.
29.644 + */
29.645 + static final int millisPerHour = 60*60*1000;
29.646 +
29.647 + /**
29.648 + * Cache to hold DateFormatSymbols instances per Locale.
29.649 + */
29.650 + private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
29.651 + = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
29.652 +
29.653 + private void initializeData(Locale desiredLocale) {
29.654 + locale = desiredLocale;
29.655 +
29.656 + // Copy values of a cached instance if any.
29.657 + SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
29.658 + DateFormatSymbols dfs;
29.659 + if (ref != null && (dfs = ref.get()) != null) {
29.660 + copyMembers(dfs, this);
29.661 + return;
29.662 + }
29.663 +
29.664 + // Initialize the fields from the ResourceBundle for locale.
29.665 + ResourceBundle resource = LocaleData.getDateFormatData(locale);
29.666 +
29.667 + eras = resource.getStringArray("Eras");
29.668 + months = resource.getStringArray("MonthNames");
29.669 + shortMonths = resource.getStringArray("MonthAbbreviations");
29.670 + ampms = resource.getStringArray("AmPmMarkers");
29.671 + localPatternChars = resource.getString("DateTimePatternChars");
29.672 +
29.673 + // Day of week names are stored in a 1-based array.
29.674 + weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
29.675 + shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
29.676 + }
29.677 +
29.678 + private static String[] toOneBasedArray(String[] src) {
29.679 + int len = src.length;
29.680 + String[] dst = new String[len + 1];
29.681 + dst[0] = "";
29.682 + for (int i = 0; i < len; i++) {
29.683 + dst[i + 1] = src[i];
29.684 + }
29.685 + return dst;
29.686 + }
29.687 +
29.688 + /**
29.689 + * Package private: used by SimpleDateFormat
29.690 + * Gets the index for the given time zone ID to obtain the time zone
29.691 + * strings for formatting. The time zone ID is just for programmatic
29.692 + * lookup. NOT LOCALIZED!!!
29.693 + * @param ID the given time zone ID.
29.694 + * @return the index of the given time zone ID. Returns -1 if
29.695 + * the given time zone ID can't be located in the DateFormatSymbols object.
29.696 + * @see java.util.SimpleTimeZone
29.697 + */
29.698 + final int getZoneIndex(String ID)
29.699 + {
29.700 + String[][] zoneStrings = getZoneStringsWrapper();
29.701 + for (int index=0; index<zoneStrings.length; index++)
29.702 + {
29.703 + if (ID.equals(zoneStrings[index][0])) return index;
29.704 + }
29.705 +
29.706 + return -1;
29.707 + }
29.708 +
29.709 + /**
29.710 + * Wrapper method to the getZoneStrings(), which is called from inside
29.711 + * the java.text package and not to mutate the returned arrays, so that
29.712 + * it does not need to create a defensive copy.
29.713 + */
29.714 + final String[][] getZoneStringsWrapper() {
29.715 + if (isSubclassObject()) {
29.716 + return getZoneStrings();
29.717 + } else {
29.718 + return getZoneStringsImpl(false);
29.719 + }
29.720 + }
29.721 +
29.722 + private final String[][] getZoneStringsImpl(boolean needsCopy) {
29.723 + if (zoneStrings == null) {
29.724 + zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
29.725 + }
29.726 +
29.727 + if (!needsCopy) {
29.728 + return zoneStrings;
29.729 + }
29.730 +
29.731 + int len = zoneStrings.length;
29.732 + String[][] aCopy = new String[len][];
29.733 + for (int i = 0; i < len; i++) {
29.734 + aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
29.735 + }
29.736 + return aCopy;
29.737 + }
29.738 +
29.739 + private final boolean isSubclassObject() {
29.740 + return !getClass().getName().equals("java.text.DateFormatSymbols");
29.741 + }
29.742 +
29.743 + /**
29.744 + * Clones all the data members from the source DateFormatSymbols to
29.745 + * the target DateFormatSymbols. This is only for subclasses.
29.746 + * @param src the source DateFormatSymbols.
29.747 + * @param dst the target DateFormatSymbols.
29.748 + */
29.749 + private final void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
29.750 + {
29.751 + dst.eras = Arrays.copyOf(src.eras, src.eras.length);
29.752 + dst.months = Arrays.copyOf(src.months, src.months.length);
29.753 + dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
29.754 + dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
29.755 + dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
29.756 + dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
29.757 + if (src.zoneStrings != null) {
29.758 + dst.zoneStrings = src.getZoneStringsImpl(true);
29.759 + } else {
29.760 + dst.zoneStrings = null;
29.761 + }
29.762 + dst.localPatternChars = src.localPatternChars;
29.763 + }
29.764 +
29.765 + /**
29.766 + * Write out the default serializable data, after ensuring the
29.767 + * <code>zoneStrings</code> field is initialized in order to make
29.768 + * sure the backward compatibility.
29.769 + *
29.770 + * @since 1.6
29.771 + */
29.772 + private void writeObject(ObjectOutputStream stream) throws IOException {
29.773 + if (zoneStrings == null) {
29.774 + zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
29.775 + }
29.776 + stream.defaultWriteObject();
29.777 + }
29.778 +
29.779 + /**
29.780 + * Obtains a DateFormatSymbols instance from a DateFormatSymbolsProvider
29.781 + * implementation.
29.782 + */
29.783 + private static class DateFormatSymbolsGetter
29.784 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatSymbolsProvider,
29.785 + DateFormatSymbols> {
29.786 + private static final DateFormatSymbolsGetter INSTANCE =
29.787 + new DateFormatSymbolsGetter();
29.788 +
29.789 + public DateFormatSymbols getObject(DateFormatSymbolsProvider dateFormatSymbolsProvider,
29.790 + Locale locale,
29.791 + String key,
29.792 + Object... params) {
29.793 + assert params.length == 0;
29.794 + return dateFormatSymbolsProvider.getInstance(locale);
29.795 + }
29.796 + }
29.797 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormat.java Thu Oct 03 15:43:10 2013 +0200
30.3 @@ -0,0 +1,3278 @@
30.4 +/*
30.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
30.7 + *
30.8 + * This code is free software; you can redistribute it and/or modify it
30.9 + * under the terms of the GNU General Public License version 2 only, as
30.10 + * published by the Free Software Foundation. Oracle designates this
30.11 + * particular file as subject to the "Classpath" exception as provided
30.12 + * by Oracle in the LICENSE file that accompanied this code.
30.13 + *
30.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
30.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
30.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30.17 + * version 2 for more details (a copy is included in the LICENSE file that
30.18 + * accompanied this code).
30.19 + *
30.20 + * You should have received a copy of the GNU General Public License version
30.21 + * 2 along with this work; if not, write to the Free Software Foundation,
30.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
30.23 + *
30.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
30.25 + * or visit www.oracle.com if you need additional information or have any
30.26 + * questions.
30.27 + */
30.28 +
30.29 +/*
30.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
30.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
30.32 + *
30.33 + * The original version of this source code and documentation is copyrighted
30.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
30.35 + * materials are provided under terms of a License Agreement between Taligent
30.36 + * and Sun. This technology is protected by multiple US and International
30.37 + * patents. This notice and attribution to Taligent may not be removed.
30.38 + * Taligent is a registered trademark of Taligent, Inc.
30.39 + *
30.40 + */
30.41 +
30.42 +package java.text;
30.43 +
30.44 +import java.io.InvalidObjectException;
30.45 +import java.io.IOException;
30.46 +import java.io.ObjectInputStream;
30.47 +import java.math.BigDecimal;
30.48 +import java.math.BigInteger;
30.49 +import java.math.RoundingMode;
30.50 +import java.util.ArrayList;
30.51 +import java.util.Currency;
30.52 +import java.util.Locale;
30.53 +import java.util.ResourceBundle;
30.54 +import java.util.concurrent.ConcurrentHashMap;
30.55 +import java.util.concurrent.ConcurrentMap;
30.56 +import java.util.concurrent.atomic.AtomicInteger;
30.57 +import java.util.concurrent.atomic.AtomicLong;
30.58 +import sun.util.resources.LocaleData;
30.59 +
30.60 +/**
30.61 + * <code>DecimalFormat</code> is a concrete subclass of
30.62 + * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
30.63 + * features designed to make it possible to parse and format numbers in any
30.64 + * locale, including support for Western, Arabic, and Indic digits. It also
30.65 + * supports different kinds of numbers, including integers (123), fixed-point
30.66 + * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
30.67 + * currency amounts ($123). All of these can be localized.
30.68 + *
30.69 + * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
30.70 + * default locale, call one of <code>NumberFormat</code>'s factory methods, such
30.71 + * as <code>getInstance()</code>. In general, do not call the
30.72 + * <code>DecimalFormat</code> constructors directly, since the
30.73 + * <code>NumberFormat</code> factory methods may return subclasses other than
30.74 + * <code>DecimalFormat</code>. If you need to customize the format object, do
30.75 + * something like this:
30.76 + *
30.77 + * <blockquote><pre>
30.78 + * NumberFormat f = NumberFormat.getInstance(loc);
30.79 + * if (f instanceof DecimalFormat) {
30.80 + * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
30.81 + * }
30.82 + * </pre></blockquote>
30.83 + *
30.84 + * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
30.85 + * <em>symbols</em>. The pattern may be set directly using
30.86 + * <code>applyPattern()</code>, or indirectly using the API methods. The
30.87 + * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using
30.88 + * the <code>NumberFormat</code> factory methods, the pattern and symbols are
30.89 + * read from localized <code>ResourceBundle</code>s.
30.90 + *
30.91 + * <h4>Patterns</h4>
30.92 + *
30.93 + * <code>DecimalFormat</code> patterns have the following syntax:
30.94 + * <blockquote><pre>
30.95 + * <i>Pattern:</i>
30.96 + * <i>PositivePattern</i>
30.97 + * <i>PositivePattern</i> ; <i>NegativePattern</i>
30.98 + * <i>PositivePattern:</i>
30.99 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
30.100 + * <i>NegativePattern:</i>
30.101 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
30.102 + * <i>Prefix:</i>
30.103 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
30.104 + * <i>Suffix:</i>
30.105 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
30.106 + * <i>Number:</i>
30.107 + * <i>Integer</i> <i>Exponent<sub>opt</sub></i>
30.108 + * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
30.109 + * <i>Integer:</i>
30.110 + * <i>MinimumInteger</i>
30.111 + * #
30.112 + * # <i>Integer</i>
30.113 + * # , <i>Integer</i>
30.114 + * <i>MinimumInteger:</i>
30.115 + * 0
30.116 + * 0 <i>MinimumInteger</i>
30.117 + * 0 , <i>MinimumInteger</i>
30.118 + * <i>Fraction:</i>
30.119 + * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
30.120 + * <i>MinimumFraction:</i>
30.121 + * 0 <i>MinimumFraction<sub>opt</sub></i>
30.122 + * <i>OptionalFraction:</i>
30.123 + * # <i>OptionalFraction<sub>opt</sub></i>
30.124 + * <i>Exponent:</i>
30.125 + * E <i>MinimumExponent</i>
30.126 + * <i>MinimumExponent:</i>
30.127 + * 0 <i>MinimumExponent<sub>opt</sub></i>
30.128 + * </pre></blockquote>
30.129 + *
30.130 + * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
30.131 + * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each
30.132 + * subpattern has a prefix, numeric part, and suffix. The negative subpattern
30.133 + * is optional; if absent, then the positive subpattern prefixed with the
30.134 + * localized minus sign (<code>'-'</code> in most locales) is used as the
30.135 + * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
30.136 + * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it
30.137 + * serves only to specify the negative prefix and suffix; the number of digits,
30.138 + * minimal digits, and other characteristics are all the same as the positive
30.139 + * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
30.140 + * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
30.141 + *
30.142 + * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
30.143 + * thousands separators, decimal separators, etc. may be set to arbitrary
30.144 + * values, and they will appear properly during formatting. However, care must
30.145 + * be taken that the symbols and strings do not conflict, or parsing will be
30.146 + * unreliable. For example, either the positive and negative prefixes or the
30.147 + * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
30.148 + * to distinguish positive from negative values. (If they are identical, then
30.149 + * <code>DecimalFormat</code> will behave as if no negative subpattern was
30.150 + * specified.) Another example is that the decimal separator and thousands
30.151 + * separator should be distinct characters, or parsing will be impossible.
30.152 + *
30.153 + * <p>The grouping separator is commonly used for thousands, but in some
30.154 + * countries it separates ten-thousands. The grouping size is a constant number
30.155 + * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
30.156 + * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
30.157 + * interval between the last one and the end of the integer is the one that is
30.158 + * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
30.159 + * <code>"##,####,####"</code>.
30.160 + *
30.161 + * <h4>Special Pattern Characters</h4>
30.162 + *
30.163 + * <p>Many characters in a pattern are taken literally; they are matched during
30.164 + * parsing and output unchanged during formatting. Special characters, on the
30.165 + * other hand, stand for other characters, strings, or classes of characters.
30.166 + * They must be quoted, unless noted otherwise, if they are to appear in the
30.167 + * prefix or suffix as literals.
30.168 + *
30.169 + * <p>The characters listed here are used in non-localized patterns. Localized
30.170 + * patterns use the corresponding characters taken from this formatter's
30.171 + * <code>DecimalFormatSymbols</code> object instead, and these characters lose
30.172 + * their special status. Two exceptions are the currency sign and quote, which
30.173 + * are not localized.
30.174 + *
30.175 + * <blockquote>
30.176 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
30.177 + * location, localized, and meaning.">
30.178 + * <tr bgcolor="#ccccff">
30.179 + * <th align=left>Symbol
30.180 + * <th align=left>Location
30.181 + * <th align=left>Localized?
30.182 + * <th align=left>Meaning
30.183 + * <tr valign=top>
30.184 + * <td><code>0</code>
30.185 + * <td>Number
30.186 + * <td>Yes
30.187 + * <td>Digit
30.188 + * <tr valign=top bgcolor="#eeeeff">
30.189 + * <td><code>#</code>
30.190 + * <td>Number
30.191 + * <td>Yes
30.192 + * <td>Digit, zero shows as absent
30.193 + * <tr valign=top>
30.194 + * <td><code>.</code>
30.195 + * <td>Number
30.196 + * <td>Yes
30.197 + * <td>Decimal separator or monetary decimal separator
30.198 + * <tr valign=top bgcolor="#eeeeff">
30.199 + * <td><code>-</code>
30.200 + * <td>Number
30.201 + * <td>Yes
30.202 + * <td>Minus sign
30.203 + * <tr valign=top>
30.204 + * <td><code>,</code>
30.205 + * <td>Number
30.206 + * <td>Yes
30.207 + * <td>Grouping separator
30.208 + * <tr valign=top bgcolor="#eeeeff">
30.209 + * <td><code>E</code>
30.210 + * <td>Number
30.211 + * <td>Yes
30.212 + * <td>Separates mantissa and exponent in scientific notation.
30.213 + * <em>Need not be quoted in prefix or suffix.</em>
30.214 + * <tr valign=top>
30.215 + * <td><code>;</code>
30.216 + * <td>Subpattern boundary
30.217 + * <td>Yes
30.218 + * <td>Separates positive and negative subpatterns
30.219 + * <tr valign=top bgcolor="#eeeeff">
30.220 + * <td><code>%</code>
30.221 + * <td>Prefix or suffix
30.222 + * <td>Yes
30.223 + * <td>Multiply by 100 and show as percentage
30.224 + * <tr valign=top>
30.225 + * <td><code>\u2030</code>
30.226 + * <td>Prefix or suffix
30.227 + * <td>Yes
30.228 + * <td>Multiply by 1000 and show as per mille value
30.229 + * <tr valign=top bgcolor="#eeeeff">
30.230 + * <td><code>¤</code> (<code>\u00A4</code>)
30.231 + * <td>Prefix or suffix
30.232 + * <td>No
30.233 + * <td>Currency sign, replaced by currency symbol. If
30.234 + * doubled, replaced by international currency symbol.
30.235 + * If present in a pattern, the monetary decimal separator
30.236 + * is used instead of the decimal separator.
30.237 + * <tr valign=top>
30.238 + * <td><code>'</code>
30.239 + * <td>Prefix or suffix
30.240 + * <td>No
30.241 + * <td>Used to quote special characters in a prefix or suffix,
30.242 + * for example, <code>"'#'#"</code> formats 123 to
30.243 + * <code>"#123"</code>. To create a single quote
30.244 + * itself, use two in a row: <code>"# o''clock"</code>.
30.245 + * </table>
30.246 + * </blockquote>
30.247 + *
30.248 + * <h4>Scientific Notation</h4>
30.249 + *
30.250 + * <p>Numbers in scientific notation are expressed as the product of a mantissa
30.251 + * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The
30.252 + * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
30.253 + * <code>DecimalFormat</code> can be instructed to format and parse scientific
30.254 + * notation <em>only via a pattern</em>; there is currently no factory method
30.255 + * that creates a scientific notation format. In a pattern, the exponent
30.256 + * character immediately followed by one or more digit characters indicates
30.257 + * scientific notation. Example: <code>"0.###E0"</code> formats the number
30.258 + * 1234 as <code>"1.234E3"</code>.
30.259 + *
30.260 + * <ul>
30.261 + * <li>The number of digit characters after the exponent character gives the
30.262 + * minimum exponent digit count. There is no maximum. Negative exponents are
30.263 + * formatted using the localized minus sign, <em>not</em> the prefix and suffix
30.264 + * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>.
30.265 + *
30.266 + * <li>The minimum and maximum number of integer digits are interpreted
30.267 + * together:
30.268 + *
30.269 + * <ul>
30.270 + * <li>If the maximum number of integer digits is greater than their minimum number
30.271 + * and greater than 1, it forces the exponent to be a multiple of the maximum
30.272 + * number of integer digits, and the minimum number of integer digits to be
30.273 + * interpreted as 1. The most common use of this is to generate
30.274 + * <em>engineering notation</em>, in which the exponent is a multiple of three,
30.275 + * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
30.276 + * formats to <code>"12.345E3"</code>, and 123456 formats to
30.277 + * <code>"123.456E3"</code>.
30.278 + *
30.279 + * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
30.280 + * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields
30.281 + * <code>"12.3E-4"</code>.
30.282 + * </ul>
30.283 + *
30.284 + * <li>The number of significant digits in the mantissa is the sum of the
30.285 + * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
30.286 + * unaffected by the maximum integer digits. For example, 12345 formatted with
30.287 + * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
30.288 + * the significant digits count to zero. The number of significant digits
30.289 + * does not affect parsing.
30.290 + *
30.291 + * <li>Exponential patterns may not contain grouping separators.
30.292 + * </ul>
30.293 + *
30.294 + * <h4>Rounding</h4>
30.295 + *
30.296 + * <code>DecimalFormat</code> provides rounding modes defined in
30.297 + * {@link java.math.RoundingMode} for formatting. By default, it uses
30.298 + * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
30.299 + *
30.300 + * <h4>Digits</h4>
30.301 + *
30.302 + * For formatting, <code>DecimalFormat</code> uses the ten consecutive
30.303 + * characters starting with the localized zero digit defined in the
30.304 + * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
30.305 + * digits as well as all Unicode decimal digits, as defined by
30.306 + * {@link Character#digit Character.digit}, are recognized.
30.307 + *
30.308 + * <h4>Special Values</h4>
30.309 + *
30.310 + * <p><code>NaN</code> is formatted as a string, which typically has a single character
30.311 + * <code>\uFFFD</code>. This string is determined by the
30.312 + * <code>DecimalFormatSymbols</code> object. This is the only value for which
30.313 + * the prefixes and suffixes are not used.
30.314 + *
30.315 + * <p>Infinity is formatted as a string, which typically has a single character
30.316 + * <code>\u221E</code>, with the positive or negative prefixes and suffixes
30.317 + * applied. The infinity string is determined by the
30.318 + * <code>DecimalFormatSymbols</code> object.
30.319 + *
30.320 + * <p>Negative zero (<code>"-0"</code>) parses to
30.321 + * <ul>
30.322 + * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
30.323 + * true,
30.324 + * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
30.325 + * and <code>isParseIntegerOnly()</code> is true,
30.326 + * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
30.327 + * and <code>isParseIntegerOnly()</code> are false.
30.328 + * </ul>
30.329 + *
30.330 + * <h4><a name="synchronization">Synchronization</a></h4>
30.331 + *
30.332 + * <p>
30.333 + * Decimal formats are generally not synchronized.
30.334 + * It is recommended to create separate format instances for each thread.
30.335 + * If multiple threads access a format concurrently, it must be synchronized
30.336 + * externally.
30.337 + *
30.338 + * <h4>Example</h4>
30.339 + *
30.340 + * <blockquote><pre>
30.341 + * <strong>// Print out a number using the localized number, integer, currency,
30.342 + * // and percent format for each locale</strong>
30.343 + * Locale[] locales = NumberFormat.getAvailableLocales();
30.344 + * double myNumber = -1234.56;
30.345 + * NumberFormat form;
30.346 + * for (int j=0; j<4; ++j) {
30.347 + * System.out.println("FORMAT");
30.348 + * for (int i = 0; i < locales.length; ++i) {
30.349 + * if (locales[i].getCountry().length() == 0) {
30.350 + * continue; // Skip language-only locales
30.351 + * }
30.352 + * System.out.print(locales[i].getDisplayName());
30.353 + * switch (j) {
30.354 + * case 0:
30.355 + * form = NumberFormat.getInstance(locales[i]); break;
30.356 + * case 1:
30.357 + * form = NumberFormat.getIntegerInstance(locales[i]); break;
30.358 + * case 2:
30.359 + * form = NumberFormat.getCurrencyInstance(locales[i]); break;
30.360 + * default:
30.361 + * form = NumberFormat.getPercentInstance(locales[i]); break;
30.362 + * }
30.363 + * if (form instanceof DecimalFormat) {
30.364 + * System.out.print(": " + ((DecimalFormat) form).toPattern());
30.365 + * }
30.366 + * System.out.print(" -> " + form.format(myNumber));
30.367 + * try {
30.368 + * System.out.println(" -> " + form.parse(form.format(myNumber)));
30.369 + * } catch (ParseException e) {}
30.370 + * }
30.371 + * }
30.372 + * </pre></blockquote>
30.373 + *
30.374 + * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
30.375 + * @see NumberFormat
30.376 + * @see DecimalFormatSymbols
30.377 + * @see ParsePosition
30.378 + * @author Mark Davis
30.379 + * @author Alan Liu
30.380 + */
30.381 +public class DecimalFormat extends NumberFormat {
30.382 +
30.383 + /**
30.384 + * Creates a DecimalFormat using the default pattern and symbols
30.385 + * for the default locale. This is a convenient way to obtain a
30.386 + * DecimalFormat when internationalization is not the main concern.
30.387 + * <p>
30.388 + * To obtain standard formats for a given locale, use the factory methods
30.389 + * on NumberFormat such as getNumberInstance. These factories will
30.390 + * return the most appropriate sub-class of NumberFormat for a given
30.391 + * locale.
30.392 + *
30.393 + * @see java.text.NumberFormat#getInstance
30.394 + * @see java.text.NumberFormat#getNumberInstance
30.395 + * @see java.text.NumberFormat#getCurrencyInstance
30.396 + * @see java.text.NumberFormat#getPercentInstance
30.397 + */
30.398 + public DecimalFormat() {
30.399 + Locale def = Locale.getDefault(Locale.Category.FORMAT);
30.400 + // try to get the pattern from the cache
30.401 + String pattern = cachedLocaleData.get(def);
30.402 + if (pattern == null) { /* cache miss */
30.403 + // Get the pattern for the default locale.
30.404 + ResourceBundle rb = LocaleData.getNumberFormatData(def);
30.405 + String[] all = rb.getStringArray("NumberPatterns");
30.406 + pattern = all[0];
30.407 + /* update cache */
30.408 + cachedLocaleData.putIfAbsent(def, pattern);
30.409 + }
30.410 +
30.411 + // Always applyPattern after the symbols are set
30.412 + this.symbols = new DecimalFormatSymbols(def);
30.413 + applyPattern(pattern, false);
30.414 + }
30.415 +
30.416 +
30.417 + /**
30.418 + * Creates a DecimalFormat using the given pattern and the symbols
30.419 + * for the default locale. This is a convenient way to obtain a
30.420 + * DecimalFormat when internationalization is not the main concern.
30.421 + * <p>
30.422 + * To obtain standard formats for a given locale, use the factory methods
30.423 + * on NumberFormat such as getNumberInstance. These factories will
30.424 + * return the most appropriate sub-class of NumberFormat for a given
30.425 + * locale.
30.426 + *
30.427 + * @param pattern A non-localized pattern string.
30.428 + * @exception NullPointerException if <code>pattern</code> is null
30.429 + * @exception IllegalArgumentException if the given pattern is invalid.
30.430 + * @see java.text.NumberFormat#getInstance
30.431 + * @see java.text.NumberFormat#getNumberInstance
30.432 + * @see java.text.NumberFormat#getCurrencyInstance
30.433 + * @see java.text.NumberFormat#getPercentInstance
30.434 + */
30.435 + public DecimalFormat(String pattern) {
30.436 + // Always applyPattern after the symbols are set
30.437 + this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
30.438 + applyPattern(pattern, false);
30.439 + }
30.440 +
30.441 +
30.442 + /**
30.443 + * Creates a DecimalFormat using the given pattern and symbols.
30.444 + * Use this constructor when you need to completely customize the
30.445 + * behavior of the format.
30.446 + * <p>
30.447 + * To obtain standard formats for a given
30.448 + * locale, use the factory methods on NumberFormat such as
30.449 + * getInstance or getCurrencyInstance. If you need only minor adjustments
30.450 + * to a standard format, you can modify the format returned by
30.451 + * a NumberFormat factory method.
30.452 + *
30.453 + * @param pattern a non-localized pattern string
30.454 + * @param symbols the set of symbols to be used
30.455 + * @exception NullPointerException if any of the given arguments is null
30.456 + * @exception IllegalArgumentException if the given pattern is invalid
30.457 + * @see java.text.NumberFormat#getInstance
30.458 + * @see java.text.NumberFormat#getNumberInstance
30.459 + * @see java.text.NumberFormat#getCurrencyInstance
30.460 + * @see java.text.NumberFormat#getPercentInstance
30.461 + * @see java.text.DecimalFormatSymbols
30.462 + */
30.463 + public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
30.464 + // Always applyPattern after the symbols are set
30.465 + this.symbols = (DecimalFormatSymbols)symbols.clone();
30.466 + applyPattern(pattern, false);
30.467 + }
30.468 +
30.469 +
30.470 + // Overrides
30.471 + /**
30.472 + * Formats a number and appends the resulting text to the given string
30.473 + * buffer.
30.474 + * The number can be of any subclass of {@link java.lang.Number}.
30.475 + * <p>
30.476 + * This implementation uses the maximum precision permitted.
30.477 + * @param number the number to format
30.478 + * @param toAppendTo the <code>StringBuffer</code> to which the formatted
30.479 + * text is to be appended
30.480 + * @param pos On input: an alignment field, if desired.
30.481 + * On output: the offsets of the alignment field.
30.482 + * @return the value passed in as <code>toAppendTo</code>
30.483 + * @exception IllegalArgumentException if <code>number</code> is
30.484 + * null or not an instance of <code>Number</code>.
30.485 + * @exception NullPointerException if <code>toAppendTo</code> or
30.486 + * <code>pos</code> is null
30.487 + * @exception ArithmeticException if rounding is needed with rounding
30.488 + * mode being set to RoundingMode.UNNECESSARY
30.489 + * @see java.text.FieldPosition
30.490 + */
30.491 + public final StringBuffer format(Object number,
30.492 + StringBuffer toAppendTo,
30.493 + FieldPosition pos) {
30.494 + if (number instanceof Long || number instanceof Integer ||
30.495 + number instanceof Short || number instanceof Byte ||
30.496 + number instanceof AtomicInteger ||
30.497 + number instanceof AtomicLong ||
30.498 + (number instanceof BigInteger &&
30.499 + ((BigInteger)number).bitLength () < 64)) {
30.500 + return format(((Number)number).longValue(), toAppendTo, pos);
30.501 + } else if (number instanceof BigDecimal) {
30.502 + return format((BigDecimal)number, toAppendTo, pos);
30.503 + } else if (number instanceof BigInteger) {
30.504 + return format((BigInteger)number, toAppendTo, pos);
30.505 + } else if (number instanceof Number) {
30.506 + return format(((Number)number).doubleValue(), toAppendTo, pos);
30.507 + } else {
30.508 + throw new IllegalArgumentException("Cannot format given Object as a Number");
30.509 + }
30.510 + }
30.511 +
30.512 + /**
30.513 + * Formats a double to produce a string.
30.514 + * @param number The double to format
30.515 + * @param result where the text is to be appended
30.516 + * @param fieldPosition On input: an alignment field, if desired.
30.517 + * On output: the offsets of the alignment field.
30.518 + * @exception ArithmeticException if rounding is needed with rounding
30.519 + * mode being set to RoundingMode.UNNECESSARY
30.520 + * @return The formatted number string
30.521 + * @see java.text.FieldPosition
30.522 + */
30.523 + public StringBuffer format(double number, StringBuffer result,
30.524 + FieldPosition fieldPosition) {
30.525 + fieldPosition.setBeginIndex(0);
30.526 + fieldPosition.setEndIndex(0);
30.527 +
30.528 + return format(number, result, fieldPosition.getFieldDelegate());
30.529 + }
30.530 +
30.531 + /**
30.532 + * Formats a double to produce a string.
30.533 + * @param number The double to format
30.534 + * @param result where the text is to be appended
30.535 + * @param delegate notified of locations of sub fields
30.536 + * @exception ArithmeticException if rounding is needed with rounding
30.537 + * mode being set to RoundingMode.UNNECESSARY
30.538 + * @return The formatted number string
30.539 + */
30.540 + private StringBuffer format(double number, StringBuffer result,
30.541 + FieldDelegate delegate) {
30.542 + if (Double.isNaN(number) ||
30.543 + (Double.isInfinite(number) && multiplier == 0)) {
30.544 + int iFieldStart = result.length();
30.545 + result.append(symbols.getNaN());
30.546 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
30.547 + iFieldStart, result.length(), result);
30.548 + return result;
30.549 + }
30.550 +
30.551 + /* Detecting whether a double is negative is easy with the exception of
30.552 + * the value -0.0. This is a double which has a zero mantissa (and
30.553 + * exponent), but a negative sign bit. It is semantically distinct from
30.554 + * a zero with a positive sign bit, and this distinction is important
30.555 + * to certain kinds of computations. However, it's a little tricky to
30.556 + * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
30.557 + * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
30.558 + * -Infinity. Proper detection of -0.0 is needed to deal with the
30.559 + * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
30.560 + */
30.561 + boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
30.562 +
30.563 + if (multiplier != 1) {
30.564 + number *= multiplier;
30.565 + }
30.566 +
30.567 + if (Double.isInfinite(number)) {
30.568 + if (isNegative) {
30.569 + append(result, negativePrefix, delegate,
30.570 + getNegativePrefixFieldPositions(), Field.SIGN);
30.571 + } else {
30.572 + append(result, positivePrefix, delegate,
30.573 + getPositivePrefixFieldPositions(), Field.SIGN);
30.574 + }
30.575 +
30.576 + int iFieldStart = result.length();
30.577 + result.append(symbols.getInfinity());
30.578 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
30.579 + iFieldStart, result.length(), result);
30.580 +
30.581 + if (isNegative) {
30.582 + append(result, negativeSuffix, delegate,
30.583 + getNegativeSuffixFieldPositions(), Field.SIGN);
30.584 + } else {
30.585 + append(result, positiveSuffix, delegate,
30.586 + getPositiveSuffixFieldPositions(), Field.SIGN);
30.587 + }
30.588 +
30.589 + return result;
30.590 + }
30.591 +
30.592 + if (isNegative) {
30.593 + number = -number;
30.594 + }
30.595 +
30.596 + // at this point we are guaranteed a nonnegative finite number.
30.597 + assert(number >= 0 && !Double.isInfinite(number));
30.598 +
30.599 + synchronized(digitList) {
30.600 + int maxIntDigits = super.getMaximumIntegerDigits();
30.601 + int minIntDigits = super.getMinimumIntegerDigits();
30.602 + int maxFraDigits = super.getMaximumFractionDigits();
30.603 + int minFraDigits = super.getMinimumFractionDigits();
30.604 +
30.605 + digitList.set(isNegative, number, useExponentialNotation ?
30.606 + maxIntDigits + maxFraDigits : maxFraDigits,
30.607 + !useExponentialNotation);
30.608 + return subformat(result, delegate, isNegative, false,
30.609 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
30.610 + }
30.611 + }
30.612 +
30.613 + /**
30.614 + * Format a long to produce a string.
30.615 + * @param number The long to format
30.616 + * @param result where the text is to be appended
30.617 + * @param fieldPosition On input: an alignment field, if desired.
30.618 + * On output: the offsets of the alignment field.
30.619 + * @exception ArithmeticException if rounding is needed with rounding
30.620 + * mode being set to RoundingMode.UNNECESSARY
30.621 + * @return The formatted number string
30.622 + * @see java.text.FieldPosition
30.623 + */
30.624 + public StringBuffer format(long number, StringBuffer result,
30.625 + FieldPosition fieldPosition) {
30.626 + fieldPosition.setBeginIndex(0);
30.627 + fieldPosition.setEndIndex(0);
30.628 +
30.629 + return format(number, result, fieldPosition.getFieldDelegate());
30.630 + }
30.631 +
30.632 + /**
30.633 + * Format a long to produce a string.
30.634 + * @param number The long to format
30.635 + * @param result where the text is to be appended
30.636 + * @param delegate notified of locations of sub fields
30.637 + * @return The formatted number string
30.638 + * @exception ArithmeticException if rounding is needed with rounding
30.639 + * mode being set to RoundingMode.UNNECESSARY
30.640 + * @see java.text.FieldPosition
30.641 + */
30.642 + private StringBuffer format(long number, StringBuffer result,
30.643 + FieldDelegate delegate) {
30.644 + boolean isNegative = (number < 0);
30.645 + if (isNegative) {
30.646 + number = -number;
30.647 + }
30.648 +
30.649 + // In general, long values always represent real finite numbers, so
30.650 + // we don't have to check for +/- Infinity or NaN. However, there
30.651 + // is one case we have to be careful of: The multiplier can push
30.652 + // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
30.653 + // check for this before multiplying, and if it happens we use
30.654 + // BigInteger instead.
30.655 + boolean useBigInteger = false;
30.656 + if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
30.657 + if (multiplier != 0) {
30.658 + useBigInteger = true;
30.659 + }
30.660 + } else if (multiplier != 1 && multiplier != 0) {
30.661 + long cutoff = Long.MAX_VALUE / multiplier;
30.662 + if (cutoff < 0) {
30.663 + cutoff = -cutoff;
30.664 + }
30.665 + useBigInteger = (number > cutoff);
30.666 + }
30.667 +
30.668 + if (useBigInteger) {
30.669 + if (isNegative) {
30.670 + number = -number;
30.671 + }
30.672 + BigInteger bigIntegerValue = BigInteger.valueOf(number);
30.673 + return format(bigIntegerValue, result, delegate, true);
30.674 + }
30.675 +
30.676 + number *= multiplier;
30.677 + if (number == 0) {
30.678 + isNegative = false;
30.679 + } else {
30.680 + if (multiplier < 0) {
30.681 + number = -number;
30.682 + isNegative = !isNegative;
30.683 + }
30.684 + }
30.685 +
30.686 + synchronized(digitList) {
30.687 + int maxIntDigits = super.getMaximumIntegerDigits();
30.688 + int minIntDigits = super.getMinimumIntegerDigits();
30.689 + int maxFraDigits = super.getMaximumFractionDigits();
30.690 + int minFraDigits = super.getMinimumFractionDigits();
30.691 +
30.692 + digitList.set(isNegative, number,
30.693 + useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
30.694 +
30.695 + return subformat(result, delegate, isNegative, true,
30.696 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
30.697 + }
30.698 + }
30.699 +
30.700 + /**
30.701 + * Formats a BigDecimal to produce a string.
30.702 + * @param number The BigDecimal to format
30.703 + * @param result where the text is to be appended
30.704 + * @param fieldPosition On input: an alignment field, if desired.
30.705 + * On output: the offsets of the alignment field.
30.706 + * @return The formatted number string
30.707 + * @exception ArithmeticException if rounding is needed with rounding
30.708 + * mode being set to RoundingMode.UNNECESSARY
30.709 + * @see java.text.FieldPosition
30.710 + */
30.711 + private StringBuffer format(BigDecimal number, StringBuffer result,
30.712 + FieldPosition fieldPosition) {
30.713 + fieldPosition.setBeginIndex(0);
30.714 + fieldPosition.setEndIndex(0);
30.715 + return format(number, result, fieldPosition.getFieldDelegate());
30.716 + }
30.717 +
30.718 + /**
30.719 + * Formats a BigDecimal to produce a string.
30.720 + * @param number The BigDecimal to format
30.721 + * @param result where the text is to be appended
30.722 + * @param delegate notified of locations of sub fields
30.723 + * @exception ArithmeticException if rounding is needed with rounding
30.724 + * mode being set to RoundingMode.UNNECESSARY
30.725 + * @return The formatted number string
30.726 + */
30.727 + private StringBuffer format(BigDecimal number, StringBuffer result,
30.728 + FieldDelegate delegate) {
30.729 + if (multiplier != 1) {
30.730 + number = number.multiply(getBigDecimalMultiplier());
30.731 + }
30.732 + boolean isNegative = number.signum() == -1;
30.733 + if (isNegative) {
30.734 + number = number.negate();
30.735 + }
30.736 +
30.737 + synchronized(digitList) {
30.738 + int maxIntDigits = getMaximumIntegerDigits();
30.739 + int minIntDigits = getMinimumIntegerDigits();
30.740 + int maxFraDigits = getMaximumFractionDigits();
30.741 + int minFraDigits = getMinimumFractionDigits();
30.742 + int maximumDigits = maxIntDigits + maxFraDigits;
30.743 +
30.744 + digitList.set(isNegative, number, useExponentialNotation ?
30.745 + ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
30.746 + maxFraDigits, !useExponentialNotation);
30.747 +
30.748 + return subformat(result, delegate, isNegative, false,
30.749 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
30.750 + }
30.751 + }
30.752 +
30.753 + /**
30.754 + * Format a BigInteger to produce a string.
30.755 + * @param number The BigInteger to format
30.756 + * @param result where the text is to be appended
30.757 + * @param fieldPosition On input: an alignment field, if desired.
30.758 + * On output: the offsets of the alignment field.
30.759 + * @return The formatted number string
30.760 + * @exception ArithmeticException if rounding is needed with rounding
30.761 + * mode being set to RoundingMode.UNNECESSARY
30.762 + * @see java.text.FieldPosition
30.763 + */
30.764 + private StringBuffer format(BigInteger number, StringBuffer result,
30.765 + FieldPosition fieldPosition) {
30.766 + fieldPosition.setBeginIndex(0);
30.767 + fieldPosition.setEndIndex(0);
30.768 +
30.769 + return format(number, result, fieldPosition.getFieldDelegate(), false);
30.770 + }
30.771 +
30.772 + /**
30.773 + * Format a BigInteger to produce a string.
30.774 + * @param number The BigInteger to format
30.775 + * @param result where the text is to be appended
30.776 + * @param delegate notified of locations of sub fields
30.777 + * @return The formatted number string
30.778 + * @exception ArithmeticException if rounding is needed with rounding
30.779 + * mode being set to RoundingMode.UNNECESSARY
30.780 + * @see java.text.FieldPosition
30.781 + */
30.782 + private StringBuffer format(BigInteger number, StringBuffer result,
30.783 + FieldDelegate delegate, boolean formatLong) {
30.784 + if (multiplier != 1) {
30.785 + number = number.multiply(getBigIntegerMultiplier());
30.786 + }
30.787 + boolean isNegative = number.signum() == -1;
30.788 + if (isNegative) {
30.789 + number = number.negate();
30.790 + }
30.791 +
30.792 + synchronized(digitList) {
30.793 + int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
30.794 + if (formatLong) {
30.795 + maxIntDigits = super.getMaximumIntegerDigits();
30.796 + minIntDigits = super.getMinimumIntegerDigits();
30.797 + maxFraDigits = super.getMaximumFractionDigits();
30.798 + minFraDigits = super.getMinimumFractionDigits();
30.799 + maximumDigits = maxIntDigits + maxFraDigits;
30.800 + } else {
30.801 + maxIntDigits = getMaximumIntegerDigits();
30.802 + minIntDigits = getMinimumIntegerDigits();
30.803 + maxFraDigits = getMaximumFractionDigits();
30.804 + minFraDigits = getMinimumFractionDigits();
30.805 + maximumDigits = maxIntDigits + maxFraDigits;
30.806 + if (maximumDigits < 0) {
30.807 + maximumDigits = Integer.MAX_VALUE;
30.808 + }
30.809 + }
30.810 +
30.811 + digitList.set(isNegative, number,
30.812 + useExponentialNotation ? maximumDigits : 0);
30.813 +
30.814 + return subformat(result, delegate, isNegative, true,
30.815 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
30.816 + }
30.817 + }
30.818 +
30.819 + /**
30.820 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
30.821 + * You can use the returned <code>AttributedCharacterIterator</code>
30.822 + * to build the resulting String, as well as to determine information
30.823 + * about the resulting String.
30.824 + * <p>
30.825 + * Each attribute key of the AttributedCharacterIterator will be of type
30.826 + * <code>NumberFormat.Field</code>, with the attribute value being the
30.827 + * same as the attribute key.
30.828 + *
30.829 + * @exception NullPointerException if obj is null.
30.830 + * @exception IllegalArgumentException when the Format cannot format the
30.831 + * given object.
30.832 + * @exception ArithmeticException if rounding is needed with rounding
30.833 + * mode being set to RoundingMode.UNNECESSARY
30.834 + * @param obj The object to format
30.835 + * @return AttributedCharacterIterator describing the formatted value.
30.836 + * @since 1.4
30.837 + */
30.838 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
30.839 + CharacterIteratorFieldDelegate delegate =
30.840 + new CharacterIteratorFieldDelegate();
30.841 + StringBuffer sb = new StringBuffer();
30.842 +
30.843 + if (obj instanceof Double || obj instanceof Float) {
30.844 + format(((Number)obj).doubleValue(), sb, delegate);
30.845 + } else if (obj instanceof Long || obj instanceof Integer ||
30.846 + obj instanceof Short || obj instanceof Byte ||
30.847 + obj instanceof AtomicInteger || obj instanceof AtomicLong) {
30.848 + format(((Number)obj).longValue(), sb, delegate);
30.849 + } else if (obj instanceof BigDecimal) {
30.850 + format((BigDecimal)obj, sb, delegate);
30.851 + } else if (obj instanceof BigInteger) {
30.852 + format((BigInteger)obj, sb, delegate, false);
30.853 + } else if (obj == null) {
30.854 + throw new NullPointerException(
30.855 + "formatToCharacterIterator must be passed non-null object");
30.856 + } else {
30.857 + throw new IllegalArgumentException(
30.858 + "Cannot format given Object as a Number");
30.859 + }
30.860 + return delegate.getIterator(sb.toString());
30.861 + }
30.862 +
30.863 + /**
30.864 + * Complete the formatting of a finite number. On entry, the digitList must
30.865 + * be filled in with the correct digits.
30.866 + */
30.867 + private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
30.868 + boolean isNegative, boolean isInteger,
30.869 + int maxIntDigits, int minIntDigits,
30.870 + int maxFraDigits, int minFraDigits) {
30.871 + // NOTE: This isn't required anymore because DigitList takes care of this.
30.872 + //
30.873 + // // The negative of the exponent represents the number of leading
30.874 + // // zeros between the decimal and the first non-zero digit, for
30.875 + // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
30.876 + // // is more than the maximum fraction digits, then we have an underflow
30.877 + // // for the printed representation. We recognize this here and set
30.878 + // // the DigitList representation to zero in this situation.
30.879 + //
30.880 + // if (-digitList.decimalAt >= getMaximumFractionDigits())
30.881 + // {
30.882 + // digitList.count = 0;
30.883 + // }
30.884 +
30.885 + char zero = symbols.getZeroDigit();
30.886 + int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
30.887 + char grouping = symbols.getGroupingSeparator();
30.888 + char decimal = isCurrencyFormat ?
30.889 + symbols.getMonetaryDecimalSeparator() :
30.890 + symbols.getDecimalSeparator();
30.891 +
30.892 + /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
30.893 + * format as zero. This allows sensible computations and preserves
30.894 + * relations such as signum(1/x) = signum(x), where x is +Infinity or
30.895 + * -Infinity. Prior to this fix, we always formatted zero values as if
30.896 + * they were positive. Liu 7/6/98.
30.897 + */
30.898 + if (digitList.isZero()) {
30.899 + digitList.decimalAt = 0; // Normalize
30.900 + }
30.901 +
30.902 + if (isNegative) {
30.903 + append(result, negativePrefix, delegate,
30.904 + getNegativePrefixFieldPositions(), Field.SIGN);
30.905 + } else {
30.906 + append(result, positivePrefix, delegate,
30.907 + getPositivePrefixFieldPositions(), Field.SIGN);
30.908 + }
30.909 +
30.910 + if (useExponentialNotation) {
30.911 + int iFieldStart = result.length();
30.912 + int iFieldEnd = -1;
30.913 + int fFieldStart = -1;
30.914 +
30.915 + // Minimum integer digits are handled in exponential format by
30.916 + // adjusting the exponent. For example, 0.01234 with 3 minimum
30.917 + // integer digits is "123.4E-4".
30.918 +
30.919 + // Maximum integer digits are interpreted as indicating the
30.920 + // repeating range. This is useful for engineering notation, in
30.921 + // which the exponent is restricted to a multiple of 3. For
30.922 + // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
30.923 + // If maximum integer digits are > 1 and are larger than
30.924 + // minimum integer digits, then minimum integer digits are
30.925 + // ignored.
30.926 + int exponent = digitList.decimalAt;
30.927 + int repeat = maxIntDigits;
30.928 + int minimumIntegerDigits = minIntDigits;
30.929 + if (repeat > 1 && repeat > minIntDigits) {
30.930 + // A repeating range is defined; adjust to it as follows.
30.931 + // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
30.932 + // -3,-4,-5=>-6, etc. This takes into account that the
30.933 + // exponent we have here is off by one from what we expect;
30.934 + // it is for the format 0.MMMMMx10^n.
30.935 + if (exponent >= 1) {
30.936 + exponent = ((exponent - 1) / repeat) * repeat;
30.937 + } else {
30.938 + // integer division rounds towards 0
30.939 + exponent = ((exponent - repeat) / repeat) * repeat;
30.940 + }
30.941 + minimumIntegerDigits = 1;
30.942 + } else {
30.943 + // No repeating range is defined; use minimum integer digits.
30.944 + exponent -= minimumIntegerDigits;
30.945 + }
30.946 +
30.947 + // We now output a minimum number of digits, and more if there
30.948 + // are more digits, up to the maximum number of digits. We
30.949 + // place the decimal point after the "integer" digits, which
30.950 + // are the first (decimalAt - exponent) digits.
30.951 + int minimumDigits = minIntDigits + minFraDigits;
30.952 + if (minimumDigits < 0) { // overflow?
30.953 + minimumDigits = Integer.MAX_VALUE;
30.954 + }
30.955 +
30.956 + // The number of integer digits is handled specially if the number
30.957 + // is zero, since then there may be no digits.
30.958 + int integerDigits = digitList.isZero() ? minimumIntegerDigits :
30.959 + digitList.decimalAt - exponent;
30.960 + if (minimumDigits < integerDigits) {
30.961 + minimumDigits = integerDigits;
30.962 + }
30.963 + int totalDigits = digitList.count;
30.964 + if (minimumDigits > totalDigits) {
30.965 + totalDigits = minimumDigits;
30.966 + }
30.967 + boolean addedDecimalSeparator = false;
30.968 +
30.969 + for (int i=0; i<totalDigits; ++i) {
30.970 + if (i == integerDigits) {
30.971 + // Record field information for caller.
30.972 + iFieldEnd = result.length();
30.973 +
30.974 + result.append(decimal);
30.975 + addedDecimalSeparator = true;
30.976 +
30.977 + // Record field information for caller.
30.978 + fFieldStart = result.length();
30.979 + }
30.980 + result.append((i < digitList.count) ?
30.981 + (char)(digitList.digits[i] + zeroDelta) :
30.982 + zero);
30.983 + }
30.984 +
30.985 + if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
30.986 + // Record field information for caller.
30.987 + iFieldEnd = result.length();
30.988 +
30.989 + result.append(decimal);
30.990 + addedDecimalSeparator = true;
30.991 +
30.992 + // Record field information for caller.
30.993 + fFieldStart = result.length();
30.994 + }
30.995 +
30.996 + // Record field information
30.997 + if (iFieldEnd == -1) {
30.998 + iFieldEnd = result.length();
30.999 + }
30.1000 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
30.1001 + iFieldStart, iFieldEnd, result);
30.1002 + if (addedDecimalSeparator) {
30.1003 + delegate.formatted(Field.DECIMAL_SEPARATOR,
30.1004 + Field.DECIMAL_SEPARATOR,
30.1005 + iFieldEnd, fFieldStart, result);
30.1006 + }
30.1007 + if (fFieldStart == -1) {
30.1008 + fFieldStart = result.length();
30.1009 + }
30.1010 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
30.1011 + fFieldStart, result.length(), result);
30.1012 +
30.1013 + // The exponent is output using the pattern-specified minimum
30.1014 + // exponent digits. There is no maximum limit to the exponent
30.1015 + // digits, since truncating the exponent would result in an
30.1016 + // unacceptable inaccuracy.
30.1017 + int fieldStart = result.length();
30.1018 +
30.1019 + result.append(symbols.getExponentSeparator());
30.1020 +
30.1021 + delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
30.1022 + fieldStart, result.length(), result);
30.1023 +
30.1024 + // For zero values, we force the exponent to zero. We
30.1025 + // must do this here, and not earlier, because the value
30.1026 + // is used to determine integer digit count above.
30.1027 + if (digitList.isZero()) {
30.1028 + exponent = 0;
30.1029 + }
30.1030 +
30.1031 + boolean negativeExponent = exponent < 0;
30.1032 + if (negativeExponent) {
30.1033 + exponent = -exponent;
30.1034 + fieldStart = result.length();
30.1035 + result.append(symbols.getMinusSign());
30.1036 + delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
30.1037 + fieldStart, result.length(), result);
30.1038 + }
30.1039 + digitList.set(negativeExponent, exponent);
30.1040 +
30.1041 + int eFieldStart = result.length();
30.1042 +
30.1043 + for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
30.1044 + result.append(zero);
30.1045 + }
30.1046 + for (int i=0; i<digitList.decimalAt; ++i) {
30.1047 + result.append((i < digitList.count) ?
30.1048 + (char)(digitList.digits[i] + zeroDelta) : zero);
30.1049 + }
30.1050 + delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
30.1051 + result.length(), result);
30.1052 + } else {
30.1053 + int iFieldStart = result.length();
30.1054 +
30.1055 + // Output the integer portion. Here 'count' is the total
30.1056 + // number of integer digits we will display, including both
30.1057 + // leading zeros required to satisfy getMinimumIntegerDigits,
30.1058 + // and actual digits present in the number.
30.1059 + int count = minIntDigits;
30.1060 + int digitIndex = 0; // Index into digitList.fDigits[]
30.1061 + if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
30.1062 + count = digitList.decimalAt;
30.1063 + }
30.1064 +
30.1065 + // Handle the case where getMaximumIntegerDigits() is smaller
30.1066 + // than the real number of integer digits. If this is so, we
30.1067 + // output the least significant max integer digits. For example,
30.1068 + // the value 1997 printed with 2 max integer digits is just "97".
30.1069 + if (count > maxIntDigits) {
30.1070 + count = maxIntDigits;
30.1071 + digitIndex = digitList.decimalAt - count;
30.1072 + }
30.1073 +
30.1074 + int sizeBeforeIntegerPart = result.length();
30.1075 + for (int i=count-1; i>=0; --i) {
30.1076 + if (i < digitList.decimalAt && digitIndex < digitList.count) {
30.1077 + // Output a real digit
30.1078 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
30.1079 + } else {
30.1080 + // Output a leading zero
30.1081 + result.append(zero);
30.1082 + }
30.1083 +
30.1084 + // Output grouping separator if necessary. Don't output a
30.1085 + // grouping separator if i==0 though; that's at the end of
30.1086 + // the integer part.
30.1087 + if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
30.1088 + (i % groupingSize == 0)) {
30.1089 + int gStart = result.length();
30.1090 + result.append(grouping);
30.1091 + delegate.formatted(Field.GROUPING_SEPARATOR,
30.1092 + Field.GROUPING_SEPARATOR, gStart,
30.1093 + result.length(), result);
30.1094 + }
30.1095 + }
30.1096 +
30.1097 + // Determine whether or not there are any printable fractional
30.1098 + // digits. If we've used up the digits we know there aren't.
30.1099 + boolean fractionPresent = (minFraDigits > 0) ||
30.1100 + (!isInteger && digitIndex < digitList.count);
30.1101 +
30.1102 + // If there is no fraction present, and we haven't printed any
30.1103 + // integer digits, then print a zero. Otherwise we won't print
30.1104 + // _any_ digits, and we won't be able to parse this string.
30.1105 + if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
30.1106 + result.append(zero);
30.1107 + }
30.1108 +
30.1109 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
30.1110 + iFieldStart, result.length(), result);
30.1111 +
30.1112 + // Output the decimal separator if we always do so.
30.1113 + int sStart = result.length();
30.1114 + if (decimalSeparatorAlwaysShown || fractionPresent) {
30.1115 + result.append(decimal);
30.1116 + }
30.1117 +
30.1118 + if (sStart != result.length()) {
30.1119 + delegate.formatted(Field.DECIMAL_SEPARATOR,
30.1120 + Field.DECIMAL_SEPARATOR,
30.1121 + sStart, result.length(), result);
30.1122 + }
30.1123 + int fFieldStart = result.length();
30.1124 +
30.1125 + for (int i=0; i < maxFraDigits; ++i) {
30.1126 + // Here is where we escape from the loop. We escape if we've
30.1127 + // output the maximum fraction digits (specified in the for
30.1128 + // expression above).
30.1129 + // We also stop when we've output the minimum digits and either:
30.1130 + // we have an integer, so there is no fractional stuff to
30.1131 + // display, or we're out of significant digits.
30.1132 + if (i >= minFraDigits &&
30.1133 + (isInteger || digitIndex >= digitList.count)) {
30.1134 + break;
30.1135 + }
30.1136 +
30.1137 + // Output leading fractional zeros. These are zeros that come
30.1138 + // after the decimal but before any significant digits. These
30.1139 + // are only output if abs(number being formatted) < 1.0.
30.1140 + if (-1-i > (digitList.decimalAt-1)) {
30.1141 + result.append(zero);
30.1142 + continue;
30.1143 + }
30.1144 +
30.1145 + // Output a digit, if we have any precision left, or a
30.1146 + // zero if we don't. We don't want to output noise digits.
30.1147 + if (!isInteger && digitIndex < digitList.count) {
30.1148 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
30.1149 + } else {
30.1150 + result.append(zero);
30.1151 + }
30.1152 + }
30.1153 +
30.1154 + // Record field information for caller.
30.1155 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
30.1156 + fFieldStart, result.length(), result);
30.1157 + }
30.1158 +
30.1159 + if (isNegative) {
30.1160 + append(result, negativeSuffix, delegate,
30.1161 + getNegativeSuffixFieldPositions(), Field.SIGN);
30.1162 + }
30.1163 + else {
30.1164 + append(result, positiveSuffix, delegate,
30.1165 + getPositiveSuffixFieldPositions(), Field.SIGN);
30.1166 + }
30.1167 +
30.1168 + return result;
30.1169 + }
30.1170 +
30.1171 + /**
30.1172 + * Appends the String <code>string</code> to <code>result</code>.
30.1173 + * <code>delegate</code> is notified of all the
30.1174 + * <code>FieldPosition</code>s in <code>positions</code>.
30.1175 + * <p>
30.1176 + * If one of the <code>FieldPosition</code>s in <code>positions</code>
30.1177 + * identifies a <code>SIGN</code> attribute, it is mapped to
30.1178 + * <code>signAttribute</code>. This is used
30.1179 + * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
30.1180 + * attribute as necessary.
30.1181 + * <p>
30.1182 + * This is used by <code>subformat</code> to add the prefix/suffix.
30.1183 + */
30.1184 + private void append(StringBuffer result, String string,
30.1185 + FieldDelegate delegate,
30.1186 + FieldPosition[] positions,
30.1187 + Format.Field signAttribute) {
30.1188 + int start = result.length();
30.1189 +
30.1190 + if (string.length() > 0) {
30.1191 + result.append(string);
30.1192 + for (int counter = 0, max = positions.length; counter < max;
30.1193 + counter++) {
30.1194 + FieldPosition fp = positions[counter];
30.1195 + Format.Field attribute = fp.getFieldAttribute();
30.1196 +
30.1197 + if (attribute == Field.SIGN) {
30.1198 + attribute = signAttribute;
30.1199 + }
30.1200 + delegate.formatted(attribute, attribute,
30.1201 + start + fp.getBeginIndex(),
30.1202 + start + fp.getEndIndex(), result);
30.1203 + }
30.1204 + }
30.1205 + }
30.1206 +
30.1207 + /**
30.1208 + * Parses text from a string to produce a <code>Number</code>.
30.1209 + * <p>
30.1210 + * The method attempts to parse text starting at the index given by
30.1211 + * <code>pos</code>.
30.1212 + * If parsing succeeds, then the index of <code>pos</code> is updated
30.1213 + * to the index after the last character used (parsing does not necessarily
30.1214 + * use all characters up to the end of the string), and the parsed
30.1215 + * number is returned. The updated <code>pos</code> can be used to
30.1216 + * indicate the starting point for the next call to this method.
30.1217 + * If an error occurs, then the index of <code>pos</code> is not
30.1218 + * changed, the error index of <code>pos</code> is set to the index of
30.1219 + * the character where the error occurred, and null is returned.
30.1220 + * <p>
30.1221 + * The subclass returned depends on the value of {@link #isParseBigDecimal}
30.1222 + * as well as on the string being parsed.
30.1223 + * <ul>
30.1224 + * <li>If <code>isParseBigDecimal()</code> is false (the default),
30.1225 + * most integer values are returned as <code>Long</code>
30.1226 + * objects, no matter how they are written: <code>"17"</code> and
30.1227 + * <code>"17.000"</code> both parse to <code>Long(17)</code>.
30.1228 + * Values that cannot fit into a <code>Long</code> are returned as
30.1229 + * <code>Double</code>s. This includes values with a fractional part,
30.1230 + * infinite values, <code>NaN</code>, and the value -0.0.
30.1231 + * <code>DecimalFormat</code> does <em>not</em> decide whether to
30.1232 + * return a <code>Double</code> or a <code>Long</code> based on the
30.1233 + * presence of a decimal separator in the source string. Doing so
30.1234 + * would prevent integers that overflow the mantissa of a double,
30.1235 + * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
30.1236 + * parsed accurately.
30.1237 + * <p>
30.1238 + * Callers may use the <code>Number</code> methods
30.1239 + * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
30.1240 + * the type they want.
30.1241 + * <li>If <code>isParseBigDecimal()</code> is true, values are returned
30.1242 + * as <code>BigDecimal</code> objects. The values are the ones
30.1243 + * constructed by {@link java.math.BigDecimal#BigDecimal(String)}
30.1244 + * for corresponding strings in locale-independent format. The
30.1245 + * special cases negative and positive infinity and NaN are returned
30.1246 + * as <code>Double</code> instances holding the values of the
30.1247 + * corresponding <code>Double</code> constants.
30.1248 + * </ul>
30.1249 + * <p>
30.1250 + * <code>DecimalFormat</code> parses all Unicode characters that represent
30.1251 + * decimal digits, as defined by <code>Character.digit()</code>. In
30.1252 + * addition, <code>DecimalFormat</code> also recognizes as digits the ten
30.1253 + * consecutive characters starting with the localized zero digit defined in
30.1254 + * the <code>DecimalFormatSymbols</code> object.
30.1255 + *
30.1256 + * @param text the string to be parsed
30.1257 + * @param pos A <code>ParsePosition</code> object with index and error
30.1258 + * index information as described above.
30.1259 + * @return the parsed value, or <code>null</code> if the parse fails
30.1260 + * @exception NullPointerException if <code>text</code> or
30.1261 + * <code>pos</code> is null.
30.1262 + */
30.1263 + public Number parse(String text, ParsePosition pos) {
30.1264 + // special case NaN
30.1265 + if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
30.1266 + pos.index = pos.index + symbols.getNaN().length();
30.1267 + return new Double(Double.NaN);
30.1268 + }
30.1269 +
30.1270 + boolean[] status = new boolean[STATUS_LENGTH];
30.1271 + if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
30.1272 + return null;
30.1273 + }
30.1274 +
30.1275 + // special case INFINITY
30.1276 + if (status[STATUS_INFINITE]) {
30.1277 + if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
30.1278 + return new Double(Double.POSITIVE_INFINITY);
30.1279 + } else {
30.1280 + return new Double(Double.NEGATIVE_INFINITY);
30.1281 + }
30.1282 + }
30.1283 +
30.1284 + if (multiplier == 0) {
30.1285 + if (digitList.isZero()) {
30.1286 + return new Double(Double.NaN);
30.1287 + } else if (status[STATUS_POSITIVE]) {
30.1288 + return new Double(Double.POSITIVE_INFINITY);
30.1289 + } else {
30.1290 + return new Double(Double.NEGATIVE_INFINITY);
30.1291 + }
30.1292 + }
30.1293 +
30.1294 + if (isParseBigDecimal()) {
30.1295 + BigDecimal bigDecimalResult = digitList.getBigDecimal();
30.1296 +
30.1297 + if (multiplier != 1) {
30.1298 + try {
30.1299 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
30.1300 + }
30.1301 + catch (ArithmeticException e) { // non-terminating decimal expansion
30.1302 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
30.1303 + }
30.1304 + }
30.1305 +
30.1306 + if (!status[STATUS_POSITIVE]) {
30.1307 + bigDecimalResult = bigDecimalResult.negate();
30.1308 + }
30.1309 + return bigDecimalResult;
30.1310 + } else {
30.1311 + boolean gotDouble = true;
30.1312 + boolean gotLongMinimum = false;
30.1313 + double doubleResult = 0.0;
30.1314 + long longResult = 0;
30.1315 +
30.1316 + // Finally, have DigitList parse the digits into a value.
30.1317 + if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
30.1318 + gotDouble = false;
30.1319 + longResult = digitList.getLong();
30.1320 + if (longResult < 0) { // got Long.MIN_VALUE
30.1321 + gotLongMinimum = true;
30.1322 + }
30.1323 + } else {
30.1324 + doubleResult = digitList.getDouble();
30.1325 + }
30.1326 +
30.1327 + // Divide by multiplier. We have to be careful here not to do
30.1328 + // unneeded conversions between double and long.
30.1329 + if (multiplier != 1) {
30.1330 + if (gotDouble) {
30.1331 + doubleResult /= multiplier;
30.1332 + } else {
30.1333 + // Avoid converting to double if we can
30.1334 + if (longResult % multiplier == 0) {
30.1335 + longResult /= multiplier;
30.1336 + } else {
30.1337 + doubleResult = ((double)longResult) / multiplier;
30.1338 + gotDouble = true;
30.1339 + }
30.1340 + }
30.1341 + }
30.1342 +
30.1343 + if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
30.1344 + doubleResult = -doubleResult;
30.1345 + longResult = -longResult;
30.1346 + }
30.1347 +
30.1348 + // At this point, if we divided the result by the multiplier, the
30.1349 + // result may fit into a long. We check for this case and return
30.1350 + // a long if possible.
30.1351 + // We must do this AFTER applying the negative (if appropriate)
30.1352 + // in order to handle the case of LONG_MIN; otherwise, if we do
30.1353 + // this with a positive value -LONG_MIN, the double is > 0, but
30.1354 + // the long is < 0. We also must retain a double in the case of
30.1355 + // -0.0, which will compare as == to a long 0 cast to a double
30.1356 + // (bug 4162852).
30.1357 + if (multiplier != 1 && gotDouble) {
30.1358 + longResult = (long)doubleResult;
30.1359 + gotDouble = ((doubleResult != (double)longResult) ||
30.1360 + (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
30.1361 + !isParseIntegerOnly();
30.1362 + }
30.1363 +
30.1364 + return gotDouble ?
30.1365 + (Number)new Double(doubleResult) : (Number)new Long(longResult);
30.1366 + }
30.1367 + }
30.1368 +
30.1369 + /**
30.1370 + * Return a BigInteger multiplier.
30.1371 + */
30.1372 + private BigInteger getBigIntegerMultiplier() {
30.1373 + if (bigIntegerMultiplier == null) {
30.1374 + bigIntegerMultiplier = BigInteger.valueOf(multiplier);
30.1375 + }
30.1376 + return bigIntegerMultiplier;
30.1377 + }
30.1378 + private transient BigInteger bigIntegerMultiplier;
30.1379 +
30.1380 + /**
30.1381 + * Return a BigDecimal multiplier.
30.1382 + */
30.1383 + private BigDecimal getBigDecimalMultiplier() {
30.1384 + if (bigDecimalMultiplier == null) {
30.1385 + bigDecimalMultiplier = new BigDecimal(multiplier);
30.1386 + }
30.1387 + return bigDecimalMultiplier;
30.1388 + }
30.1389 + private transient BigDecimal bigDecimalMultiplier;
30.1390 +
30.1391 + private static final int STATUS_INFINITE = 0;
30.1392 + private static final int STATUS_POSITIVE = 1;
30.1393 + private static final int STATUS_LENGTH = 2;
30.1394 +
30.1395 + /**
30.1396 + * Parse the given text into a number. The text is parsed beginning at
30.1397 + * parsePosition, until an unparseable character is seen.
30.1398 + * @param text The string to parse.
30.1399 + * @param parsePosition The position at which to being parsing. Upon
30.1400 + * return, the first unparseable character.
30.1401 + * @param digits The DigitList to set to the parsed value.
30.1402 + * @param isExponent If true, parse an exponent. This means no
30.1403 + * infinite values and integer only.
30.1404 + * @param status Upon return contains boolean status flags indicating
30.1405 + * whether the value was infinite and whether it was positive.
30.1406 + */
30.1407 + private final boolean subparse(String text, ParsePosition parsePosition,
30.1408 + String positivePrefix, String negativePrefix,
30.1409 + DigitList digits, boolean isExponent,
30.1410 + boolean status[]) {
30.1411 + int position = parsePosition.index;
30.1412 + int oldStart = parsePosition.index;
30.1413 + int backup;
30.1414 + boolean gotPositive, gotNegative;
30.1415 +
30.1416 + // check for positivePrefix; take longest
30.1417 + gotPositive = text.regionMatches(position, positivePrefix, 0,
30.1418 + positivePrefix.length());
30.1419 + gotNegative = text.regionMatches(position, negativePrefix, 0,
30.1420 + negativePrefix.length());
30.1421 +
30.1422 + if (gotPositive && gotNegative) {
30.1423 + if (positivePrefix.length() > negativePrefix.length()) {
30.1424 + gotNegative = false;
30.1425 + } else if (positivePrefix.length() < negativePrefix.length()) {
30.1426 + gotPositive = false;
30.1427 + }
30.1428 + }
30.1429 +
30.1430 + if (gotPositive) {
30.1431 + position += positivePrefix.length();
30.1432 + } else if (gotNegative) {
30.1433 + position += negativePrefix.length();
30.1434 + } else {
30.1435 + parsePosition.errorIndex = position;
30.1436 + return false;
30.1437 + }
30.1438 +
30.1439 + // process digits or Inf, find decimal position
30.1440 + status[STATUS_INFINITE] = false;
30.1441 + if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
30.1442 + symbols.getInfinity().length())) {
30.1443 + position += symbols.getInfinity().length();
30.1444 + status[STATUS_INFINITE] = true;
30.1445 + } else {
30.1446 + // We now have a string of digits, possibly with grouping symbols,
30.1447 + // and decimal points. We want to process these into a DigitList.
30.1448 + // We don't want to put a bunch of leading zeros into the DigitList
30.1449 + // though, so we keep track of the location of the decimal point,
30.1450 + // put only significant digits into the DigitList, and adjust the
30.1451 + // exponent as needed.
30.1452 +
30.1453 + digits.decimalAt = digits.count = 0;
30.1454 + char zero = symbols.getZeroDigit();
30.1455 + char decimal = isCurrencyFormat ?
30.1456 + symbols.getMonetaryDecimalSeparator() :
30.1457 + symbols.getDecimalSeparator();
30.1458 + char grouping = symbols.getGroupingSeparator();
30.1459 + String exponentString = symbols.getExponentSeparator();
30.1460 + boolean sawDecimal = false;
30.1461 + boolean sawExponent = false;
30.1462 + boolean sawDigit = false;
30.1463 + int exponent = 0; // Set to the exponent value, if any
30.1464 +
30.1465 + // We have to track digitCount ourselves, because digits.count will
30.1466 + // pin when the maximum allowable digits is reached.
30.1467 + int digitCount = 0;
30.1468 +
30.1469 + backup = -1;
30.1470 + for (; position < text.length(); ++position) {
30.1471 + char ch = text.charAt(position);
30.1472 +
30.1473 + /* We recognize all digit ranges, not only the Latin digit range
30.1474 + * '0'..'9'. We do so by using the Character.digit() method,
30.1475 + * which converts a valid Unicode digit to the range 0..9.
30.1476 + *
30.1477 + * The character 'ch' may be a digit. If so, place its value
30.1478 + * from 0 to 9 in 'digit'. First try using the locale digit,
30.1479 + * which may or MAY NOT be a standard Unicode digit range. If
30.1480 + * this fails, try using the standard Unicode digit ranges by
30.1481 + * calling Character.digit(). If this also fails, digit will
30.1482 + * have a value outside the range 0..9.
30.1483 + */
30.1484 + int digit = ch - zero;
30.1485 + if (digit < 0 || digit > 9) {
30.1486 + digit = Character.digit(ch, 10);
30.1487 + }
30.1488 +
30.1489 + if (digit == 0) {
30.1490 + // Cancel out backup setting (see grouping handler below)
30.1491 + backup = -1; // Do this BEFORE continue statement below!!!
30.1492 + sawDigit = true;
30.1493 +
30.1494 + // Handle leading zeros
30.1495 + if (digits.count == 0) {
30.1496 + // Ignore leading zeros in integer part of number.
30.1497 + if (!sawDecimal) {
30.1498 + continue;
30.1499 + }
30.1500 +
30.1501 + // If we have seen the decimal, but no significant
30.1502 + // digits yet, then we account for leading zeros by
30.1503 + // decrementing the digits.decimalAt into negative
30.1504 + // values.
30.1505 + --digits.decimalAt;
30.1506 + } else {
30.1507 + ++digitCount;
30.1508 + digits.append((char)(digit + '0'));
30.1509 + }
30.1510 + } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
30.1511 + sawDigit = true;
30.1512 + ++digitCount;
30.1513 + digits.append((char)(digit + '0'));
30.1514 +
30.1515 + // Cancel out backup setting (see grouping handler below)
30.1516 + backup = -1;
30.1517 + } else if (!isExponent && ch == decimal) {
30.1518 + // If we're only parsing integers, or if we ALREADY saw the
30.1519 + // decimal, then don't parse this one.
30.1520 + if (isParseIntegerOnly() || sawDecimal) {
30.1521 + break;
30.1522 + }
30.1523 + digits.decimalAt = digitCount; // Not digits.count!
30.1524 + sawDecimal = true;
30.1525 + } else if (!isExponent && ch == grouping && isGroupingUsed()) {
30.1526 + if (sawDecimal) {
30.1527 + break;
30.1528 + }
30.1529 + // Ignore grouping characters, if we are using them, but
30.1530 + // require that they be followed by a digit. Otherwise
30.1531 + // we backup and reprocess them.
30.1532 + backup = position;
30.1533 + } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
30.1534 + && !sawExponent) {
30.1535 + // Process the exponent by recursively calling this method.
30.1536 + ParsePosition pos = new ParsePosition(position + exponentString.length());
30.1537 + boolean[] stat = new boolean[STATUS_LENGTH];
30.1538 + DigitList exponentDigits = new DigitList();
30.1539 +
30.1540 + if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
30.1541 + exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
30.1542 + position = pos.index; // Advance past the exponent
30.1543 + exponent = (int)exponentDigits.getLong();
30.1544 + if (!stat[STATUS_POSITIVE]) {
30.1545 + exponent = -exponent;
30.1546 + }
30.1547 + sawExponent = true;
30.1548 + }
30.1549 + break; // Whether we fail or succeed, we exit this loop
30.1550 + }
30.1551 + else {
30.1552 + break;
30.1553 + }
30.1554 + }
30.1555 +
30.1556 + if (backup != -1) {
30.1557 + position = backup;
30.1558 + }
30.1559 +
30.1560 + // If there was no decimal point we have an integer
30.1561 + if (!sawDecimal) {
30.1562 + digits.decimalAt = digitCount; // Not digits.count!
30.1563 + }
30.1564 +
30.1565 + // Adjust for exponent, if any
30.1566 + digits.decimalAt += exponent;
30.1567 +
30.1568 + // If none of the text string was recognized. For example, parse
30.1569 + // "x" with pattern "#0.00" (return index and error index both 0)
30.1570 + // parse "$" with pattern "$#0.00". (return index 0 and error
30.1571 + // index 1).
30.1572 + if (!sawDigit && digitCount == 0) {
30.1573 + parsePosition.index = oldStart;
30.1574 + parsePosition.errorIndex = oldStart;
30.1575 + return false;
30.1576 + }
30.1577 + }
30.1578 +
30.1579 + // check for suffix
30.1580 + if (!isExponent) {
30.1581 + if (gotPositive) {
30.1582 + gotPositive = text.regionMatches(position,positiveSuffix,0,
30.1583 + positiveSuffix.length());
30.1584 + }
30.1585 + if (gotNegative) {
30.1586 + gotNegative = text.regionMatches(position,negativeSuffix,0,
30.1587 + negativeSuffix.length());
30.1588 + }
30.1589 +
30.1590 + // if both match, take longest
30.1591 + if (gotPositive && gotNegative) {
30.1592 + if (positiveSuffix.length() > negativeSuffix.length()) {
30.1593 + gotNegative = false;
30.1594 + } else if (positiveSuffix.length() < negativeSuffix.length()) {
30.1595 + gotPositive = false;
30.1596 + }
30.1597 + }
30.1598 +
30.1599 + // fail if neither or both
30.1600 + if (gotPositive == gotNegative) {
30.1601 + parsePosition.errorIndex = position;
30.1602 + return false;
30.1603 + }
30.1604 +
30.1605 + parsePosition.index = position +
30.1606 + (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
30.1607 + } else {
30.1608 + parsePosition.index = position;
30.1609 + }
30.1610 +
30.1611 + status[STATUS_POSITIVE] = gotPositive;
30.1612 + if (parsePosition.index == oldStart) {
30.1613 + parsePosition.errorIndex = position;
30.1614 + return false;
30.1615 + }
30.1616 + return true;
30.1617 + }
30.1618 +
30.1619 + /**
30.1620 + * Returns a copy of the decimal format symbols, which is generally not
30.1621 + * changed by the programmer or user.
30.1622 + * @return a copy of the desired DecimalFormatSymbols
30.1623 + * @see java.text.DecimalFormatSymbols
30.1624 + */
30.1625 + public DecimalFormatSymbols getDecimalFormatSymbols() {
30.1626 + try {
30.1627 + // don't allow multiple references
30.1628 + return (DecimalFormatSymbols) symbols.clone();
30.1629 + } catch (Exception foo) {
30.1630 + return null; // should never happen
30.1631 + }
30.1632 + }
30.1633 +
30.1634 +
30.1635 + /**
30.1636 + * Sets the decimal format symbols, which is generally not changed
30.1637 + * by the programmer or user.
30.1638 + * @param newSymbols desired DecimalFormatSymbols
30.1639 + * @see java.text.DecimalFormatSymbols
30.1640 + */
30.1641 + public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
30.1642 + try {
30.1643 + // don't allow multiple references
30.1644 + symbols = (DecimalFormatSymbols) newSymbols.clone();
30.1645 + expandAffixes();
30.1646 + } catch (Exception foo) {
30.1647 + // should never happen
30.1648 + }
30.1649 + }
30.1650 +
30.1651 + /**
30.1652 + * Get the positive prefix.
30.1653 + * <P>Examples: +123, $123, sFr123
30.1654 + */
30.1655 + public String getPositivePrefix () {
30.1656 + return positivePrefix;
30.1657 + }
30.1658 +
30.1659 + /**
30.1660 + * Set the positive prefix.
30.1661 + * <P>Examples: +123, $123, sFr123
30.1662 + */
30.1663 + public void setPositivePrefix (String newValue) {
30.1664 + positivePrefix = newValue;
30.1665 + posPrefixPattern = null;
30.1666 + positivePrefixFieldPositions = null;
30.1667 + }
30.1668 +
30.1669 + /**
30.1670 + * Returns the FieldPositions of the fields in the prefix used for
30.1671 + * positive numbers. This is not used if the user has explicitly set
30.1672 + * a positive prefix via <code>setPositivePrefix</code>. This is
30.1673 + * lazily created.
30.1674 + *
30.1675 + * @return FieldPositions in positive prefix
30.1676 + */
30.1677 + private FieldPosition[] getPositivePrefixFieldPositions() {
30.1678 + if (positivePrefixFieldPositions == null) {
30.1679 + if (posPrefixPattern != null) {
30.1680 + positivePrefixFieldPositions = expandAffix(posPrefixPattern);
30.1681 + }
30.1682 + else {
30.1683 + positivePrefixFieldPositions = EmptyFieldPositionArray;
30.1684 + }
30.1685 + }
30.1686 + return positivePrefixFieldPositions;
30.1687 + }
30.1688 +
30.1689 + /**
30.1690 + * Get the negative prefix.
30.1691 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
30.1692 + */
30.1693 + public String getNegativePrefix () {
30.1694 + return negativePrefix;
30.1695 + }
30.1696 +
30.1697 + /**
30.1698 + * Set the negative prefix.
30.1699 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
30.1700 + */
30.1701 + public void setNegativePrefix (String newValue) {
30.1702 + negativePrefix = newValue;
30.1703 + negPrefixPattern = null;
30.1704 + }
30.1705 +
30.1706 + /**
30.1707 + * Returns the FieldPositions of the fields in the prefix used for
30.1708 + * negative numbers. This is not used if the user has explicitly set
30.1709 + * a negative prefix via <code>setNegativePrefix</code>. This is
30.1710 + * lazily created.
30.1711 + *
30.1712 + * @return FieldPositions in positive prefix
30.1713 + */
30.1714 + private FieldPosition[] getNegativePrefixFieldPositions() {
30.1715 + if (negativePrefixFieldPositions == null) {
30.1716 + if (negPrefixPattern != null) {
30.1717 + negativePrefixFieldPositions = expandAffix(negPrefixPattern);
30.1718 + }
30.1719 + else {
30.1720 + negativePrefixFieldPositions = EmptyFieldPositionArray;
30.1721 + }
30.1722 + }
30.1723 + return negativePrefixFieldPositions;
30.1724 + }
30.1725 +
30.1726 + /**
30.1727 + * Get the positive suffix.
30.1728 + * <P>Example: 123%
30.1729 + */
30.1730 + public String getPositiveSuffix () {
30.1731 + return positiveSuffix;
30.1732 + }
30.1733 +
30.1734 + /**
30.1735 + * Set the positive suffix.
30.1736 + * <P>Example: 123%
30.1737 + */
30.1738 + public void setPositiveSuffix (String newValue) {
30.1739 + positiveSuffix = newValue;
30.1740 + posSuffixPattern = null;
30.1741 + }
30.1742 +
30.1743 + /**
30.1744 + * Returns the FieldPositions of the fields in the suffix used for
30.1745 + * positive numbers. This is not used if the user has explicitly set
30.1746 + * a positive suffix via <code>setPositiveSuffix</code>. This is
30.1747 + * lazily created.
30.1748 + *
30.1749 + * @return FieldPositions in positive prefix
30.1750 + */
30.1751 + private FieldPosition[] getPositiveSuffixFieldPositions() {
30.1752 + if (positiveSuffixFieldPositions == null) {
30.1753 + if (posSuffixPattern != null) {
30.1754 + positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
30.1755 + }
30.1756 + else {
30.1757 + positiveSuffixFieldPositions = EmptyFieldPositionArray;
30.1758 + }
30.1759 + }
30.1760 + return positiveSuffixFieldPositions;
30.1761 + }
30.1762 +
30.1763 + /**
30.1764 + * Get the negative suffix.
30.1765 + * <P>Examples: -123%, ($123) (with positive suffixes)
30.1766 + */
30.1767 + public String getNegativeSuffix () {
30.1768 + return negativeSuffix;
30.1769 + }
30.1770 +
30.1771 + /**
30.1772 + * Set the negative suffix.
30.1773 + * <P>Examples: 123%
30.1774 + */
30.1775 + public void setNegativeSuffix (String newValue) {
30.1776 + negativeSuffix = newValue;
30.1777 + negSuffixPattern = null;
30.1778 + }
30.1779 +
30.1780 + /**
30.1781 + * Returns the FieldPositions of the fields in the suffix used for
30.1782 + * negative numbers. This is not used if the user has explicitly set
30.1783 + * a negative suffix via <code>setNegativeSuffix</code>. This is
30.1784 + * lazily created.
30.1785 + *
30.1786 + * @return FieldPositions in positive prefix
30.1787 + */
30.1788 + private FieldPosition[] getNegativeSuffixFieldPositions() {
30.1789 + if (negativeSuffixFieldPositions == null) {
30.1790 + if (negSuffixPattern != null) {
30.1791 + negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
30.1792 + }
30.1793 + else {
30.1794 + negativeSuffixFieldPositions = EmptyFieldPositionArray;
30.1795 + }
30.1796 + }
30.1797 + return negativeSuffixFieldPositions;
30.1798 + }
30.1799 +
30.1800 + /**
30.1801 + * Gets the multiplier for use in percent, per mille, and similar
30.1802 + * formats.
30.1803 + *
30.1804 + * @see #setMultiplier(int)
30.1805 + */
30.1806 + public int getMultiplier () {
30.1807 + return multiplier;
30.1808 + }
30.1809 +
30.1810 + /**
30.1811 + * Sets the multiplier for use in percent, per mille, and similar
30.1812 + * formats.
30.1813 + * For a percent format, set the multiplier to 100 and the suffixes to
30.1814 + * have '%' (for Arabic, use the Arabic percent sign).
30.1815 + * For a per mille format, set the multiplier to 1000 and the suffixes to
30.1816 + * have '\u2030'.
30.1817 + *
30.1818 + * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
30.1819 + * "123" is parsed into 1.23.
30.1820 + *
30.1821 + * @see #getMultiplier
30.1822 + */
30.1823 + public void setMultiplier (int newValue) {
30.1824 + multiplier = newValue;
30.1825 + bigDecimalMultiplier = null;
30.1826 + bigIntegerMultiplier = null;
30.1827 + }
30.1828 +
30.1829 + /**
30.1830 + * Return the grouping size. Grouping size is the number of digits between
30.1831 + * grouping separators in the integer portion of a number. For example,
30.1832 + * in the number "123,456.78", the grouping size is 3.
30.1833 + * @see #setGroupingSize
30.1834 + * @see java.text.NumberFormat#isGroupingUsed
30.1835 + * @see java.text.DecimalFormatSymbols#getGroupingSeparator
30.1836 + */
30.1837 + public int getGroupingSize () {
30.1838 + return groupingSize;
30.1839 + }
30.1840 +
30.1841 + /**
30.1842 + * Set the grouping size. Grouping size is the number of digits between
30.1843 + * grouping separators in the integer portion of a number. For example,
30.1844 + * in the number "123,456.78", the grouping size is 3.
30.1845 + * <br>
30.1846 + * The value passed in is converted to a byte, which may lose information.
30.1847 + * @see #getGroupingSize
30.1848 + * @see java.text.NumberFormat#setGroupingUsed
30.1849 + * @see java.text.DecimalFormatSymbols#setGroupingSeparator
30.1850 + */
30.1851 + public void setGroupingSize (int newValue) {
30.1852 + groupingSize = (byte)newValue;
30.1853 + }
30.1854 +
30.1855 + /**
30.1856 + * Allows you to get the behavior of the decimal separator with integers.
30.1857 + * (The decimal separator will always appear with decimals.)
30.1858 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
30.1859 + */
30.1860 + public boolean isDecimalSeparatorAlwaysShown() {
30.1861 + return decimalSeparatorAlwaysShown;
30.1862 + }
30.1863 +
30.1864 + /**
30.1865 + * Allows you to set the behavior of the decimal separator with integers.
30.1866 + * (The decimal separator will always appear with decimals.)
30.1867 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
30.1868 + */
30.1869 + public void setDecimalSeparatorAlwaysShown(boolean newValue) {
30.1870 + decimalSeparatorAlwaysShown = newValue;
30.1871 + }
30.1872 +
30.1873 + /**
30.1874 + * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
30.1875 + * method returns <code>BigDecimal</code>. The default value is false.
30.1876 + * @see #setParseBigDecimal
30.1877 + * @since 1.5
30.1878 + */
30.1879 + public boolean isParseBigDecimal() {
30.1880 + return parseBigDecimal;
30.1881 + }
30.1882 +
30.1883 + /**
30.1884 + * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
30.1885 + * method returns <code>BigDecimal</code>.
30.1886 + * @see #isParseBigDecimal
30.1887 + * @since 1.5
30.1888 + */
30.1889 + public void setParseBigDecimal(boolean newValue) {
30.1890 + parseBigDecimal = newValue;
30.1891 + }
30.1892 +
30.1893 + /**
30.1894 + * Standard override; no change in semantics.
30.1895 + */
30.1896 + public Object clone() {
30.1897 + try {
30.1898 + DecimalFormat other = (DecimalFormat) super.clone();
30.1899 + other.symbols = (DecimalFormatSymbols) symbols.clone();
30.1900 + other.digitList = (DigitList) digitList.clone();
30.1901 + return other;
30.1902 + } catch (Exception e) {
30.1903 + throw new InternalError();
30.1904 + }
30.1905 + }
30.1906 +
30.1907 + /**
30.1908 + * Overrides equals
30.1909 + */
30.1910 + public boolean equals(Object obj)
30.1911 + {
30.1912 + if (obj == null) return false;
30.1913 + if (!super.equals(obj)) return false; // super does class check
30.1914 + DecimalFormat other = (DecimalFormat) obj;
30.1915 + return ((posPrefixPattern == other.posPrefixPattern &&
30.1916 + positivePrefix.equals(other.positivePrefix))
30.1917 + || (posPrefixPattern != null &&
30.1918 + posPrefixPattern.equals(other.posPrefixPattern)))
30.1919 + && ((posSuffixPattern == other.posSuffixPattern &&
30.1920 + positiveSuffix.equals(other.positiveSuffix))
30.1921 + || (posSuffixPattern != null &&
30.1922 + posSuffixPattern.equals(other.posSuffixPattern)))
30.1923 + && ((negPrefixPattern == other.negPrefixPattern &&
30.1924 + negativePrefix.equals(other.negativePrefix))
30.1925 + || (negPrefixPattern != null &&
30.1926 + negPrefixPattern.equals(other.negPrefixPattern)))
30.1927 + && ((negSuffixPattern == other.negSuffixPattern &&
30.1928 + negativeSuffix.equals(other.negativeSuffix))
30.1929 + || (negSuffixPattern != null &&
30.1930 + negSuffixPattern.equals(other.negSuffixPattern)))
30.1931 + && multiplier == other.multiplier
30.1932 + && groupingSize == other.groupingSize
30.1933 + && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
30.1934 + && parseBigDecimal == other.parseBigDecimal
30.1935 + && useExponentialNotation == other.useExponentialNotation
30.1936 + && (!useExponentialNotation ||
30.1937 + minExponentDigits == other.minExponentDigits)
30.1938 + && maximumIntegerDigits == other.maximumIntegerDigits
30.1939 + && minimumIntegerDigits == other.minimumIntegerDigits
30.1940 + && maximumFractionDigits == other.maximumFractionDigits
30.1941 + && minimumFractionDigits == other.minimumFractionDigits
30.1942 + && roundingMode == other.roundingMode
30.1943 + && symbols.equals(other.symbols);
30.1944 + }
30.1945 +
30.1946 + /**
30.1947 + * Overrides hashCode
30.1948 + */
30.1949 + public int hashCode() {
30.1950 + return super.hashCode() * 37 + positivePrefix.hashCode();
30.1951 + // just enough fields for a reasonable distribution
30.1952 + }
30.1953 +
30.1954 + /**
30.1955 + * Synthesizes a pattern string that represents the current state
30.1956 + * of this Format object.
30.1957 + * @see #applyPattern
30.1958 + */
30.1959 + public String toPattern() {
30.1960 + return toPattern( false );
30.1961 + }
30.1962 +
30.1963 + /**
30.1964 + * Synthesizes a localized pattern string that represents the current
30.1965 + * state of this Format object.
30.1966 + * @see #applyPattern
30.1967 + */
30.1968 + public String toLocalizedPattern() {
30.1969 + return toPattern( true );
30.1970 + }
30.1971 +
30.1972 + /**
30.1973 + * Expand the affix pattern strings into the expanded affix strings. If any
30.1974 + * affix pattern string is null, do not expand it. This method should be
30.1975 + * called any time the symbols or the affix patterns change in order to keep
30.1976 + * the expanded affix strings up to date.
30.1977 + */
30.1978 + private void expandAffixes() {
30.1979 + // Reuse one StringBuffer for better performance
30.1980 + StringBuffer buffer = new StringBuffer();
30.1981 + if (posPrefixPattern != null) {
30.1982 + positivePrefix = expandAffix(posPrefixPattern, buffer);
30.1983 + positivePrefixFieldPositions = null;
30.1984 + }
30.1985 + if (posSuffixPattern != null) {
30.1986 + positiveSuffix = expandAffix(posSuffixPattern, buffer);
30.1987 + positiveSuffixFieldPositions = null;
30.1988 + }
30.1989 + if (negPrefixPattern != null) {
30.1990 + negativePrefix = expandAffix(negPrefixPattern, buffer);
30.1991 + negativePrefixFieldPositions = null;
30.1992 + }
30.1993 + if (negSuffixPattern != null) {
30.1994 + negativeSuffix = expandAffix(negSuffixPattern, buffer);
30.1995 + negativeSuffixFieldPositions = null;
30.1996 + }
30.1997 + }
30.1998 +
30.1999 + /**
30.2000 + * Expand an affix pattern into an affix string. All characters in the
30.2001 + * pattern are literal unless prefixed by QUOTE. The following characters
30.2002 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
30.2003 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
30.2004 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
30.2005 + * currency code. Any other character after a QUOTE represents itself.
30.2006 + * QUOTE must be followed by another character; QUOTE may not occur by
30.2007 + * itself at the end of the pattern.
30.2008 + *
30.2009 + * @param pattern the non-null, possibly empty pattern
30.2010 + * @param buffer a scratch StringBuffer; its contents will be lost
30.2011 + * @return the expanded equivalent of pattern
30.2012 + */
30.2013 + private String expandAffix(String pattern, StringBuffer buffer) {
30.2014 + buffer.setLength(0);
30.2015 + for (int i=0; i<pattern.length(); ) {
30.2016 + char c = pattern.charAt(i++);
30.2017 + if (c == QUOTE) {
30.2018 + c = pattern.charAt(i++);
30.2019 + switch (c) {
30.2020 + case CURRENCY_SIGN:
30.2021 + if (i<pattern.length() &&
30.2022 + pattern.charAt(i) == CURRENCY_SIGN) {
30.2023 + ++i;
30.2024 + buffer.append(symbols.getInternationalCurrencySymbol());
30.2025 + } else {
30.2026 + buffer.append(symbols.getCurrencySymbol());
30.2027 + }
30.2028 + continue;
30.2029 + case PATTERN_PERCENT:
30.2030 + c = symbols.getPercent();
30.2031 + break;
30.2032 + case PATTERN_PER_MILLE:
30.2033 + c = symbols.getPerMill();
30.2034 + break;
30.2035 + case PATTERN_MINUS:
30.2036 + c = symbols.getMinusSign();
30.2037 + break;
30.2038 + }
30.2039 + }
30.2040 + buffer.append(c);
30.2041 + }
30.2042 + return buffer.toString();
30.2043 + }
30.2044 +
30.2045 + /**
30.2046 + * Expand an affix pattern into an array of FieldPositions describing
30.2047 + * how the pattern would be expanded.
30.2048 + * All characters in the
30.2049 + * pattern are literal unless prefixed by QUOTE. The following characters
30.2050 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
30.2051 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
30.2052 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
30.2053 + * currency code. Any other character after a QUOTE represents itself.
30.2054 + * QUOTE must be followed by another character; QUOTE may not occur by
30.2055 + * itself at the end of the pattern.
30.2056 + *
30.2057 + * @param pattern the non-null, possibly empty pattern
30.2058 + * @return FieldPosition array of the resulting fields.
30.2059 + */
30.2060 + private FieldPosition[] expandAffix(String pattern) {
30.2061 + ArrayList positions = null;
30.2062 + int stringIndex = 0;
30.2063 + for (int i=0; i<pattern.length(); ) {
30.2064 + char c = pattern.charAt(i++);
30.2065 + if (c == QUOTE) {
30.2066 + int field = -1;
30.2067 + Format.Field fieldID = null;
30.2068 + c = pattern.charAt(i++);
30.2069 + switch (c) {
30.2070 + case CURRENCY_SIGN:
30.2071 + String string;
30.2072 + if (i<pattern.length() &&
30.2073 + pattern.charAt(i) == CURRENCY_SIGN) {
30.2074 + ++i;
30.2075 + string = symbols.getInternationalCurrencySymbol();
30.2076 + } else {
30.2077 + string = symbols.getCurrencySymbol();
30.2078 + }
30.2079 + if (string.length() > 0) {
30.2080 + if (positions == null) {
30.2081 + positions = new ArrayList(2);
30.2082 + }
30.2083 + FieldPosition fp = new FieldPosition(Field.CURRENCY);
30.2084 + fp.setBeginIndex(stringIndex);
30.2085 + fp.setEndIndex(stringIndex + string.length());
30.2086 + positions.add(fp);
30.2087 + stringIndex += string.length();
30.2088 + }
30.2089 + continue;
30.2090 + case PATTERN_PERCENT:
30.2091 + c = symbols.getPercent();
30.2092 + field = -1;
30.2093 + fieldID = Field.PERCENT;
30.2094 + break;
30.2095 + case PATTERN_PER_MILLE:
30.2096 + c = symbols.getPerMill();
30.2097 + field = -1;
30.2098 + fieldID = Field.PERMILLE;
30.2099 + break;
30.2100 + case PATTERN_MINUS:
30.2101 + c = symbols.getMinusSign();
30.2102 + field = -1;
30.2103 + fieldID = Field.SIGN;
30.2104 + break;
30.2105 + }
30.2106 + if (fieldID != null) {
30.2107 + if (positions == null) {
30.2108 + positions = new ArrayList(2);
30.2109 + }
30.2110 + FieldPosition fp = new FieldPosition(fieldID, field);
30.2111 + fp.setBeginIndex(stringIndex);
30.2112 + fp.setEndIndex(stringIndex + 1);
30.2113 + positions.add(fp);
30.2114 + }
30.2115 + }
30.2116 + stringIndex++;
30.2117 + }
30.2118 + if (positions != null) {
30.2119 + return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
30.2120 + }
30.2121 + return EmptyFieldPositionArray;
30.2122 + }
30.2123 +
30.2124 + /**
30.2125 + * Appends an affix pattern to the given StringBuffer, quoting special
30.2126 + * characters as needed. Uses the internal affix pattern, if that exists,
30.2127 + * or the literal affix, if the internal affix pattern is null. The
30.2128 + * appended string will generate the same affix pattern (or literal affix)
30.2129 + * when passed to toPattern().
30.2130 + *
30.2131 + * @param buffer the affix string is appended to this
30.2132 + * @param affixPattern a pattern such as posPrefixPattern; may be null
30.2133 + * @param expAffix a corresponding expanded affix, such as positivePrefix.
30.2134 + * Ignored unless affixPattern is null. If affixPattern is null, then
30.2135 + * expAffix is appended as a literal affix.
30.2136 + * @param localized true if the appended pattern should contain localized
30.2137 + * pattern characters; otherwise, non-localized pattern chars are appended
30.2138 + */
30.2139 + private void appendAffix(StringBuffer buffer, String affixPattern,
30.2140 + String expAffix, boolean localized) {
30.2141 + if (affixPattern == null) {
30.2142 + appendAffix(buffer, expAffix, localized);
30.2143 + } else {
30.2144 + int i;
30.2145 + for (int pos=0; pos<affixPattern.length(); pos=i) {
30.2146 + i = affixPattern.indexOf(QUOTE, pos);
30.2147 + if (i < 0) {
30.2148 + appendAffix(buffer, affixPattern.substring(pos), localized);
30.2149 + break;
30.2150 + }
30.2151 + if (i > pos) {
30.2152 + appendAffix(buffer, affixPattern.substring(pos, i), localized);
30.2153 + }
30.2154 + char c = affixPattern.charAt(++i);
30.2155 + ++i;
30.2156 + if (c == QUOTE) {
30.2157 + buffer.append(c);
30.2158 + // Fall through and append another QUOTE below
30.2159 + } else if (c == CURRENCY_SIGN &&
30.2160 + i<affixPattern.length() &&
30.2161 + affixPattern.charAt(i) == CURRENCY_SIGN) {
30.2162 + ++i;
30.2163 + buffer.append(c);
30.2164 + // Fall through and append another CURRENCY_SIGN below
30.2165 + } else if (localized) {
30.2166 + switch (c) {
30.2167 + case PATTERN_PERCENT:
30.2168 + c = symbols.getPercent();
30.2169 + break;
30.2170 + case PATTERN_PER_MILLE:
30.2171 + c = symbols.getPerMill();
30.2172 + break;
30.2173 + case PATTERN_MINUS:
30.2174 + c = symbols.getMinusSign();
30.2175 + break;
30.2176 + }
30.2177 + }
30.2178 + buffer.append(c);
30.2179 + }
30.2180 + }
30.2181 + }
30.2182 +
30.2183 + /**
30.2184 + * Append an affix to the given StringBuffer, using quotes if
30.2185 + * there are special characters. Single quotes themselves must be
30.2186 + * escaped in either case.
30.2187 + */
30.2188 + private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
30.2189 + boolean needQuote;
30.2190 + if (localized) {
30.2191 + needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
30.2192 + || affix.indexOf(symbols.getGroupingSeparator()) >= 0
30.2193 + || affix.indexOf(symbols.getDecimalSeparator()) >= 0
30.2194 + || affix.indexOf(symbols.getPercent()) >= 0
30.2195 + || affix.indexOf(symbols.getPerMill()) >= 0
30.2196 + || affix.indexOf(symbols.getDigit()) >= 0
30.2197 + || affix.indexOf(symbols.getPatternSeparator()) >= 0
30.2198 + || affix.indexOf(symbols.getMinusSign()) >= 0
30.2199 + || affix.indexOf(CURRENCY_SIGN) >= 0;
30.2200 + }
30.2201 + else {
30.2202 + needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
30.2203 + || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
30.2204 + || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
30.2205 + || affix.indexOf(PATTERN_PERCENT) >= 0
30.2206 + || affix.indexOf(PATTERN_PER_MILLE) >= 0
30.2207 + || affix.indexOf(PATTERN_DIGIT) >= 0
30.2208 + || affix.indexOf(PATTERN_SEPARATOR) >= 0
30.2209 + || affix.indexOf(PATTERN_MINUS) >= 0
30.2210 + || affix.indexOf(CURRENCY_SIGN) >= 0;
30.2211 + }
30.2212 + if (needQuote) buffer.append('\'');
30.2213 + if (affix.indexOf('\'') < 0) buffer.append(affix);
30.2214 + else {
30.2215 + for (int j=0; j<affix.length(); ++j) {
30.2216 + char c = affix.charAt(j);
30.2217 + buffer.append(c);
30.2218 + if (c == '\'') buffer.append(c);
30.2219 + }
30.2220 + }
30.2221 + if (needQuote) buffer.append('\'');
30.2222 + }
30.2223 +
30.2224 + /**
30.2225 + * Does the real work of generating a pattern. */
30.2226 + private String toPattern(boolean localized) {
30.2227 + StringBuffer result = new StringBuffer();
30.2228 + for (int j = 1; j >= 0; --j) {
30.2229 + if (j == 1)
30.2230 + appendAffix(result, posPrefixPattern, positivePrefix, localized);
30.2231 + else appendAffix(result, negPrefixPattern, negativePrefix, localized);
30.2232 + int i;
30.2233 + int digitCount = useExponentialNotation
30.2234 + ? getMaximumIntegerDigits()
30.2235 + : Math.max(groupingSize, getMinimumIntegerDigits())+1;
30.2236 + for (i = digitCount; i > 0; --i) {
30.2237 + if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
30.2238 + i % groupingSize == 0) {
30.2239 + result.append(localized ? symbols.getGroupingSeparator() :
30.2240 + PATTERN_GROUPING_SEPARATOR);
30.2241 + }
30.2242 + result.append(i <= getMinimumIntegerDigits()
30.2243 + ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
30.2244 + : (localized ? symbols.getDigit() : PATTERN_DIGIT));
30.2245 + }
30.2246 + if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
30.2247 + result.append(localized ? symbols.getDecimalSeparator() :
30.2248 + PATTERN_DECIMAL_SEPARATOR);
30.2249 + for (i = 0; i < getMaximumFractionDigits(); ++i) {
30.2250 + if (i < getMinimumFractionDigits()) {
30.2251 + result.append(localized ? symbols.getZeroDigit() :
30.2252 + PATTERN_ZERO_DIGIT);
30.2253 + } else {
30.2254 + result.append(localized ? symbols.getDigit() :
30.2255 + PATTERN_DIGIT);
30.2256 + }
30.2257 + }
30.2258 + if (useExponentialNotation)
30.2259 + {
30.2260 + result.append(localized ? symbols.getExponentSeparator() :
30.2261 + PATTERN_EXPONENT);
30.2262 + for (i=0; i<minExponentDigits; ++i)
30.2263 + result.append(localized ? symbols.getZeroDigit() :
30.2264 + PATTERN_ZERO_DIGIT);
30.2265 + }
30.2266 + if (j == 1) {
30.2267 + appendAffix(result, posSuffixPattern, positiveSuffix, localized);
30.2268 + if ((negSuffixPattern == posSuffixPattern && // n == p == null
30.2269 + negativeSuffix.equals(positiveSuffix))
30.2270 + || (negSuffixPattern != null &&
30.2271 + negSuffixPattern.equals(posSuffixPattern))) {
30.2272 + if ((negPrefixPattern != null && posPrefixPattern != null &&
30.2273 + negPrefixPattern.equals("'-" + posPrefixPattern)) ||
30.2274 + (negPrefixPattern == posPrefixPattern && // n == p == null
30.2275 + negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
30.2276 + break;
30.2277 + }
30.2278 + result.append(localized ? symbols.getPatternSeparator() :
30.2279 + PATTERN_SEPARATOR);
30.2280 + } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
30.2281 + }
30.2282 + return result.toString();
30.2283 + }
30.2284 +
30.2285 + /**
30.2286 + * Apply the given pattern to this Format object. A pattern is a
30.2287 + * short-hand specification for the various formatting properties.
30.2288 + * These properties can also be changed individually through the
30.2289 + * various setter methods.
30.2290 + * <p>
30.2291 + * There is no limit to integer digits set
30.2292 + * by this routine, since that is the typical end-user desire;
30.2293 + * use setMaximumInteger if you want to set a real value.
30.2294 + * For negative numbers, use a second pattern, separated by a semicolon
30.2295 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
30.2296 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
30.2297 + * a maximum of 2 fraction digits.
30.2298 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
30.2299 + * parentheses.
30.2300 + * <p>In negative patterns, the minimum and maximum counts are ignored;
30.2301 + * these are presumed to be set in the positive pattern.
30.2302 + *
30.2303 + * @exception NullPointerException if <code>pattern</code> is null
30.2304 + * @exception IllegalArgumentException if the given pattern is invalid.
30.2305 + */
30.2306 + public void applyPattern(String pattern) {
30.2307 + applyPattern(pattern, false);
30.2308 + }
30.2309 +
30.2310 + /**
30.2311 + * Apply the given pattern to this Format object. The pattern
30.2312 + * is assumed to be in a localized notation. A pattern is a
30.2313 + * short-hand specification for the various formatting properties.
30.2314 + * These properties can also be changed individually through the
30.2315 + * various setter methods.
30.2316 + * <p>
30.2317 + * There is no limit to integer digits set
30.2318 + * by this routine, since that is the typical end-user desire;
30.2319 + * use setMaximumInteger if you want to set a real value.
30.2320 + * For negative numbers, use a second pattern, separated by a semicolon
30.2321 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
30.2322 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
30.2323 + * a maximum of 2 fraction digits.
30.2324 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
30.2325 + * parentheses.
30.2326 + * <p>In negative patterns, the minimum and maximum counts are ignored;
30.2327 + * these are presumed to be set in the positive pattern.
30.2328 + *
30.2329 + * @exception NullPointerException if <code>pattern</code> is null
30.2330 + * @exception IllegalArgumentException if the given pattern is invalid.
30.2331 + */
30.2332 + public void applyLocalizedPattern(String pattern) {
30.2333 + applyPattern(pattern, true);
30.2334 + }
30.2335 +
30.2336 + /**
30.2337 + * Does the real work of applying a pattern.
30.2338 + */
30.2339 + private void applyPattern(String pattern, boolean localized) {
30.2340 + char zeroDigit = PATTERN_ZERO_DIGIT;
30.2341 + char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
30.2342 + char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
30.2343 + char percent = PATTERN_PERCENT;
30.2344 + char perMill = PATTERN_PER_MILLE;
30.2345 + char digit = PATTERN_DIGIT;
30.2346 + char separator = PATTERN_SEPARATOR;
30.2347 + String exponent = PATTERN_EXPONENT;
30.2348 + char minus = PATTERN_MINUS;
30.2349 + if (localized) {
30.2350 + zeroDigit = symbols.getZeroDigit();
30.2351 + groupingSeparator = symbols.getGroupingSeparator();
30.2352 + decimalSeparator = symbols.getDecimalSeparator();
30.2353 + percent = symbols.getPercent();
30.2354 + perMill = symbols.getPerMill();
30.2355 + digit = symbols.getDigit();
30.2356 + separator = symbols.getPatternSeparator();
30.2357 + exponent = symbols.getExponentSeparator();
30.2358 + minus = symbols.getMinusSign();
30.2359 + }
30.2360 + boolean gotNegative = false;
30.2361 + decimalSeparatorAlwaysShown = false;
30.2362 + isCurrencyFormat = false;
30.2363 + useExponentialNotation = false;
30.2364 +
30.2365 + // Two variables are used to record the subrange of the pattern
30.2366 + // occupied by phase 1. This is used during the processing of the
30.2367 + // second pattern (the one representing negative numbers) to ensure
30.2368 + // that no deviation exists in phase 1 between the two patterns.
30.2369 + int phaseOneStart = 0;
30.2370 + int phaseOneLength = 0;
30.2371 +
30.2372 + int start = 0;
30.2373 + for (int j = 1; j >= 0 && start < pattern.length(); --j) {
30.2374 + boolean inQuote = false;
30.2375 + StringBuffer prefix = new StringBuffer();
30.2376 + StringBuffer suffix = new StringBuffer();
30.2377 + int decimalPos = -1;
30.2378 + int multiplier = 1;
30.2379 + int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
30.2380 + byte groupingCount = -1;
30.2381 +
30.2382 + // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is
30.2383 + // the section of the pattern with digits, decimal separator,
30.2384 + // grouping characters. Phase 2 is the suffix. In phases 0 and 2,
30.2385 + // percent, per mille, and currency symbols are recognized and
30.2386 + // translated. The separation of the characters into phases is
30.2387 + // strictly enforced; if phase 1 characters are to appear in the
30.2388 + // suffix, for example, they must be quoted.
30.2389 + int phase = 0;
30.2390 +
30.2391 + // The affix is either the prefix or the suffix.
30.2392 + StringBuffer affix = prefix;
30.2393 +
30.2394 + for (int pos = start; pos < pattern.length(); ++pos) {
30.2395 + char ch = pattern.charAt(pos);
30.2396 + switch (phase) {
30.2397 + case 0:
30.2398 + case 2:
30.2399 + // Process the prefix / suffix characters
30.2400 + if (inQuote) {
30.2401 + // A quote within quotes indicates either the closing
30.2402 + // quote or two quotes, which is a quote literal. That
30.2403 + // is, we have the second quote in 'do' or 'don''t'.
30.2404 + if (ch == QUOTE) {
30.2405 + if ((pos+1) < pattern.length() &&
30.2406 + pattern.charAt(pos+1) == QUOTE) {
30.2407 + ++pos;
30.2408 + affix.append("''"); // 'don''t'
30.2409 + } else {
30.2410 + inQuote = false; // 'do'
30.2411 + }
30.2412 + continue;
30.2413 + }
30.2414 + } else {
30.2415 + // Process unquoted characters seen in prefix or suffix
30.2416 + // phase.
30.2417 + if (ch == digit ||
30.2418 + ch == zeroDigit ||
30.2419 + ch == groupingSeparator ||
30.2420 + ch == decimalSeparator) {
30.2421 + phase = 1;
30.2422 + if (j == 1) {
30.2423 + phaseOneStart = pos;
30.2424 + }
30.2425 + --pos; // Reprocess this character
30.2426 + continue;
30.2427 + } else if (ch == CURRENCY_SIGN) {
30.2428 + // Use lookahead to determine if the currency sign
30.2429 + // is doubled or not.
30.2430 + boolean doubled = (pos + 1) < pattern.length() &&
30.2431 + pattern.charAt(pos + 1) == CURRENCY_SIGN;
30.2432 + if (doubled) { // Skip over the doubled character
30.2433 + ++pos;
30.2434 + }
30.2435 + isCurrencyFormat = true;
30.2436 + affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
30.2437 + continue;
30.2438 + } else if (ch == QUOTE) {
30.2439 + // A quote outside quotes indicates either the
30.2440 + // opening quote or two quotes, which is a quote
30.2441 + // literal. That is, we have the first quote in 'do'
30.2442 + // or o''clock.
30.2443 + if (ch == QUOTE) {
30.2444 + if ((pos+1) < pattern.length() &&
30.2445 + pattern.charAt(pos+1) == QUOTE) {
30.2446 + ++pos;
30.2447 + affix.append("''"); // o''clock
30.2448 + } else {
30.2449 + inQuote = true; // 'do'
30.2450 + }
30.2451 + continue;
30.2452 + }
30.2453 + } else if (ch == separator) {
30.2454 + // Don't allow separators before we see digit
30.2455 + // characters of phase 1, and don't allow separators
30.2456 + // in the second pattern (j == 0).
30.2457 + if (phase == 0 || j == 0) {
30.2458 + throw new IllegalArgumentException("Unquoted special character '" +
30.2459 + ch + "' in pattern \"" + pattern + '"');
30.2460 + }
30.2461 + start = pos + 1;
30.2462 + pos = pattern.length();
30.2463 + continue;
30.2464 + }
30.2465 +
30.2466 + // Next handle characters which are appended directly.
30.2467 + else if (ch == percent) {
30.2468 + if (multiplier != 1) {
30.2469 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
30.2470 + pattern + '"');
30.2471 + }
30.2472 + multiplier = 100;
30.2473 + affix.append("'%");
30.2474 + continue;
30.2475 + } else if (ch == perMill) {
30.2476 + if (multiplier != 1) {
30.2477 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
30.2478 + pattern + '"');
30.2479 + }
30.2480 + multiplier = 1000;
30.2481 + affix.append("'\u2030");
30.2482 + continue;
30.2483 + } else if (ch == minus) {
30.2484 + affix.append("'-");
30.2485 + continue;
30.2486 + }
30.2487 + }
30.2488 + // Note that if we are within quotes, or if this is an
30.2489 + // unquoted, non-special character, then we usually fall
30.2490 + // through to here.
30.2491 + affix.append(ch);
30.2492 + break;
30.2493 +
30.2494 + case 1:
30.2495 + // Phase one must be identical in the two sub-patterns. We
30.2496 + // enforce this by doing a direct comparison. While
30.2497 + // processing the first sub-pattern, we just record its
30.2498 + // length. While processing the second, we compare
30.2499 + // characters.
30.2500 + if (j == 1) {
30.2501 + ++phaseOneLength;
30.2502 + } else {
30.2503 + if (--phaseOneLength == 0) {
30.2504 + phase = 2;
30.2505 + affix = suffix;
30.2506 + }
30.2507 + continue;
30.2508 + }
30.2509 +
30.2510 + // Process the digits, decimal, and grouping characters. We
30.2511 + // record five pieces of information. We expect the digits
30.2512 + // to occur in the pattern ####0000.####, and we record the
30.2513 + // number of left digits, zero (central) digits, and right
30.2514 + // digits. The position of the last grouping character is
30.2515 + // recorded (should be somewhere within the first two blocks
30.2516 + // of characters), as is the position of the decimal point,
30.2517 + // if any (should be in the zero digits). If there is no
30.2518 + // decimal point, then there should be no right digits.
30.2519 + if (ch == digit) {
30.2520 + if (zeroDigitCount > 0) {
30.2521 + ++digitRightCount;
30.2522 + } else {
30.2523 + ++digitLeftCount;
30.2524 + }
30.2525 + if (groupingCount >= 0 && decimalPos < 0) {
30.2526 + ++groupingCount;
30.2527 + }
30.2528 + } else if (ch == zeroDigit) {
30.2529 + if (digitRightCount > 0) {
30.2530 + throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
30.2531 + pattern + '"');
30.2532 + }
30.2533 + ++zeroDigitCount;
30.2534 + if (groupingCount >= 0 && decimalPos < 0) {
30.2535 + ++groupingCount;
30.2536 + }
30.2537 + } else if (ch == groupingSeparator) {
30.2538 + groupingCount = 0;
30.2539 + } else if (ch == decimalSeparator) {
30.2540 + if (decimalPos >= 0) {
30.2541 + throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
30.2542 + pattern + '"');
30.2543 + }
30.2544 + decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
30.2545 + } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
30.2546 + if (useExponentialNotation) {
30.2547 + throw new IllegalArgumentException("Multiple exponential " +
30.2548 + "symbols in pattern \"" + pattern + '"');
30.2549 + }
30.2550 + useExponentialNotation = true;
30.2551 + minExponentDigits = 0;
30.2552 +
30.2553 + // Use lookahead to parse out the exponential part
30.2554 + // of the pattern, then jump into phase 2.
30.2555 + pos = pos+exponent.length();
30.2556 + while (pos < pattern.length() &&
30.2557 + pattern.charAt(pos) == zeroDigit) {
30.2558 + ++minExponentDigits;
30.2559 + ++phaseOneLength;
30.2560 + ++pos;
30.2561 + }
30.2562 +
30.2563 + if ((digitLeftCount + zeroDigitCount) < 1 ||
30.2564 + minExponentDigits < 1) {
30.2565 + throw new IllegalArgumentException("Malformed exponential " +
30.2566 + "pattern \"" + pattern + '"');
30.2567 + }
30.2568 +
30.2569 + // Transition to phase 2
30.2570 + phase = 2;
30.2571 + affix = suffix;
30.2572 + --pos;
30.2573 + continue;
30.2574 + } else {
30.2575 + phase = 2;
30.2576 + affix = suffix;
30.2577 + --pos;
30.2578 + --phaseOneLength;
30.2579 + continue;
30.2580 + }
30.2581 + break;
30.2582 + }
30.2583 + }
30.2584 +
30.2585 + // Handle patterns with no '0' pattern character. These patterns
30.2586 + // are legal, but must be interpreted. "##.###" -> "#0.###".
30.2587 + // ".###" -> ".0##".
30.2588 + /* We allow patterns of the form "####" to produce a zeroDigitCount
30.2589 + * of zero (got that?); although this seems like it might make it
30.2590 + * possible for format() to produce empty strings, format() checks
30.2591 + * for this condition and outputs a zero digit in this situation.
30.2592 + * Having a zeroDigitCount of zero yields a minimum integer digits
30.2593 + * of zero, which allows proper round-trip patterns. That is, we
30.2594 + * don't want "#" to become "#0" when toPattern() is called (even
30.2595 + * though that's what it really is, semantically).
30.2596 + */
30.2597 + if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
30.2598 + // Handle "###.###" and "###." and ".###"
30.2599 + int n = decimalPos;
30.2600 + if (n == 0) { // Handle ".###"
30.2601 + ++n;
30.2602 + }
30.2603 + digitRightCount = digitLeftCount - n;
30.2604 + digitLeftCount = n - 1;
30.2605 + zeroDigitCount = 1;
30.2606 + }
30.2607 +
30.2608 + // Do syntax checking on the digits.
30.2609 + if ((decimalPos < 0 && digitRightCount > 0) ||
30.2610 + (decimalPos >= 0 && (decimalPos < digitLeftCount ||
30.2611 + decimalPos > (digitLeftCount + zeroDigitCount))) ||
30.2612 + groupingCount == 0 || inQuote) {
30.2613 + throw new IllegalArgumentException("Malformed pattern \"" +
30.2614 + pattern + '"');
30.2615 + }
30.2616 +
30.2617 + if (j == 1) {
30.2618 + posPrefixPattern = prefix.toString();
30.2619 + posSuffixPattern = suffix.toString();
30.2620 + negPrefixPattern = posPrefixPattern; // assume these for now
30.2621 + negSuffixPattern = posSuffixPattern;
30.2622 + int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
30.2623 + /* The effectiveDecimalPos is the position the decimal is at or
30.2624 + * would be at if there is no decimal. Note that if decimalPos<0,
30.2625 + * then digitTotalCount == digitLeftCount + zeroDigitCount.
30.2626 + */
30.2627 + int effectiveDecimalPos = decimalPos >= 0 ?
30.2628 + decimalPos : digitTotalCount;
30.2629 + setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
30.2630 + setMaximumIntegerDigits(useExponentialNotation ?
30.2631 + digitLeftCount + getMinimumIntegerDigits() :
30.2632 + MAXIMUM_INTEGER_DIGITS);
30.2633 + setMaximumFractionDigits(decimalPos >= 0 ?
30.2634 + (digitTotalCount - decimalPos) : 0);
30.2635 + setMinimumFractionDigits(decimalPos >= 0 ?
30.2636 + (digitLeftCount + zeroDigitCount - decimalPos) : 0);
30.2637 + setGroupingUsed(groupingCount > 0);
30.2638 + this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
30.2639 + this.multiplier = multiplier;
30.2640 + setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
30.2641 + decimalPos == digitTotalCount);
30.2642 + } else {
30.2643 + negPrefixPattern = prefix.toString();
30.2644 + negSuffixPattern = suffix.toString();
30.2645 + gotNegative = true;
30.2646 + }
30.2647 + }
30.2648 +
30.2649 + if (pattern.length() == 0) {
30.2650 + posPrefixPattern = posSuffixPattern = "";
30.2651 + setMinimumIntegerDigits(0);
30.2652 + setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
30.2653 + setMinimumFractionDigits(0);
30.2654 + setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
30.2655 + }
30.2656 +
30.2657 + // If there was no negative pattern, or if the negative pattern is
30.2658 + // identical to the positive pattern, then prepend the minus sign to
30.2659 + // the positive pattern to form the negative pattern.
30.2660 + if (!gotNegative ||
30.2661 + (negPrefixPattern.equals(posPrefixPattern)
30.2662 + && negSuffixPattern.equals(posSuffixPattern))) {
30.2663 + negSuffixPattern = posSuffixPattern;
30.2664 + negPrefixPattern = "'-" + posPrefixPattern;
30.2665 + }
30.2666 +
30.2667 + expandAffixes();
30.2668 + }
30.2669 +
30.2670 + /**
30.2671 + * Sets the maximum number of digits allowed in the integer portion of a
30.2672 + * number.
30.2673 + * For formatting numbers other than <code>BigInteger</code> and
30.2674 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
30.2675 + * 309 is used. Negative input values are replaced with 0.
30.2676 + * @see NumberFormat#setMaximumIntegerDigits
30.2677 + */
30.2678 + public void setMaximumIntegerDigits(int newValue) {
30.2679 + maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
30.2680 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
30.2681 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
30.2682 + if (minimumIntegerDigits > maximumIntegerDigits) {
30.2683 + minimumIntegerDigits = maximumIntegerDigits;
30.2684 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
30.2685 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
30.2686 + }
30.2687 + }
30.2688 +
30.2689 + /**
30.2690 + * Sets the minimum number of digits allowed in the integer portion of a
30.2691 + * number.
30.2692 + * For formatting numbers other than <code>BigInteger</code> and
30.2693 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
30.2694 + * 309 is used. Negative input values are replaced with 0.
30.2695 + * @see NumberFormat#setMinimumIntegerDigits
30.2696 + */
30.2697 + public void setMinimumIntegerDigits(int newValue) {
30.2698 + minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
30.2699 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
30.2700 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
30.2701 + if (minimumIntegerDigits > maximumIntegerDigits) {
30.2702 + maximumIntegerDigits = minimumIntegerDigits;
30.2703 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
30.2704 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
30.2705 + }
30.2706 + }
30.2707 +
30.2708 + /**
30.2709 + * Sets the maximum number of digits allowed in the fraction portion of a
30.2710 + * number.
30.2711 + * For formatting numbers other than <code>BigInteger</code> and
30.2712 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
30.2713 + * 340 is used. Negative input values are replaced with 0.
30.2714 + * @see NumberFormat#setMaximumFractionDigits
30.2715 + */
30.2716 + public void setMaximumFractionDigits(int newValue) {
30.2717 + maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
30.2718 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
30.2719 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
30.2720 + if (minimumFractionDigits > maximumFractionDigits) {
30.2721 + minimumFractionDigits = maximumFractionDigits;
30.2722 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
30.2723 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
30.2724 + }
30.2725 + }
30.2726 +
30.2727 + /**
30.2728 + * Sets the minimum number of digits allowed in the fraction portion of a
30.2729 + * number.
30.2730 + * For formatting numbers other than <code>BigInteger</code> and
30.2731 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
30.2732 + * 340 is used. Negative input values are replaced with 0.
30.2733 + * @see NumberFormat#setMinimumFractionDigits
30.2734 + */
30.2735 + public void setMinimumFractionDigits(int newValue) {
30.2736 + minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
30.2737 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
30.2738 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
30.2739 + if (minimumFractionDigits > maximumFractionDigits) {
30.2740 + maximumFractionDigits = minimumFractionDigits;
30.2741 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
30.2742 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
30.2743 + }
30.2744 + }
30.2745 +
30.2746 + /**
30.2747 + * Gets the maximum number of digits allowed in the integer portion of a
30.2748 + * number.
30.2749 + * For formatting numbers other than <code>BigInteger</code> and
30.2750 + * <code>BigDecimal</code> objects, the lower of the return value and
30.2751 + * 309 is used.
30.2752 + * @see #setMaximumIntegerDigits
30.2753 + */
30.2754 + public int getMaximumIntegerDigits() {
30.2755 + return maximumIntegerDigits;
30.2756 + }
30.2757 +
30.2758 + /**
30.2759 + * Gets the minimum number of digits allowed in the integer portion of a
30.2760 + * number.
30.2761 + * For formatting numbers other than <code>BigInteger</code> and
30.2762 + * <code>BigDecimal</code> objects, the lower of the return value and
30.2763 + * 309 is used.
30.2764 + * @see #setMinimumIntegerDigits
30.2765 + */
30.2766 + public int getMinimumIntegerDigits() {
30.2767 + return minimumIntegerDigits;
30.2768 + }
30.2769 +
30.2770 + /**
30.2771 + * Gets the maximum number of digits allowed in the fraction portion of a
30.2772 + * number.
30.2773 + * For formatting numbers other than <code>BigInteger</code> and
30.2774 + * <code>BigDecimal</code> objects, the lower of the return value and
30.2775 + * 340 is used.
30.2776 + * @see #setMaximumFractionDigits
30.2777 + */
30.2778 + public int getMaximumFractionDigits() {
30.2779 + return maximumFractionDigits;
30.2780 + }
30.2781 +
30.2782 + /**
30.2783 + * Gets the minimum number of digits allowed in the fraction portion of a
30.2784 + * number.
30.2785 + * For formatting numbers other than <code>BigInteger</code> and
30.2786 + * <code>BigDecimal</code> objects, the lower of the return value and
30.2787 + * 340 is used.
30.2788 + * @see #setMinimumFractionDigits
30.2789 + */
30.2790 + public int getMinimumFractionDigits() {
30.2791 + return minimumFractionDigits;
30.2792 + }
30.2793 +
30.2794 + /**
30.2795 + * Gets the currency used by this decimal format when formatting
30.2796 + * currency values.
30.2797 + * The currency is obtained by calling
30.2798 + * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
30.2799 + * on this number format's symbols.
30.2800 + *
30.2801 + * @return the currency used by this decimal format, or <code>null</code>
30.2802 + * @since 1.4
30.2803 + */
30.2804 + public Currency getCurrency() {
30.2805 + return symbols.getCurrency();
30.2806 + }
30.2807 +
30.2808 + /**
30.2809 + * Sets the currency used by this number format when formatting
30.2810 + * currency values. This does not update the minimum or maximum
30.2811 + * number of fraction digits used by the number format.
30.2812 + * The currency is set by calling
30.2813 + * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
30.2814 + * on this number format's symbols.
30.2815 + *
30.2816 + * @param currency the new currency to be used by this decimal format
30.2817 + * @exception NullPointerException if <code>currency</code> is null
30.2818 + * @since 1.4
30.2819 + */
30.2820 + public void setCurrency(Currency currency) {
30.2821 + if (currency != symbols.getCurrency()) {
30.2822 + symbols.setCurrency(currency);
30.2823 + if (isCurrencyFormat) {
30.2824 + expandAffixes();
30.2825 + }
30.2826 + }
30.2827 + }
30.2828 +
30.2829 + /**
30.2830 + * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
30.2831 + *
30.2832 + * @return The <code>RoundingMode</code> used for this DecimalFormat.
30.2833 + * @see #setRoundingMode(RoundingMode)
30.2834 + * @since 1.6
30.2835 + */
30.2836 + public RoundingMode getRoundingMode() {
30.2837 + return roundingMode;
30.2838 + }
30.2839 +
30.2840 + /**
30.2841 + * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
30.2842 + *
30.2843 + * @param roundingMode The <code>RoundingMode</code> to be used
30.2844 + * @see #getRoundingMode()
30.2845 + * @exception NullPointerException if <code>roundingMode</code> is null.
30.2846 + * @since 1.6
30.2847 + */
30.2848 + public void setRoundingMode(RoundingMode roundingMode) {
30.2849 + if (roundingMode == null) {
30.2850 + throw new NullPointerException();
30.2851 + }
30.2852 +
30.2853 + this.roundingMode = roundingMode;
30.2854 + digitList.setRoundingMode(roundingMode);
30.2855 + }
30.2856 +
30.2857 + /**
30.2858 + * Adjusts the minimum and maximum fraction digits to values that
30.2859 + * are reasonable for the currency's default fraction digits.
30.2860 + */
30.2861 + void adjustForCurrencyDefaultFractionDigits() {
30.2862 + Currency currency = symbols.getCurrency();
30.2863 + if (currency == null) {
30.2864 + try {
30.2865 + currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
30.2866 + } catch (IllegalArgumentException e) {
30.2867 + }
30.2868 + }
30.2869 + if (currency != null) {
30.2870 + int digits = currency.getDefaultFractionDigits();
30.2871 + if (digits != -1) {
30.2872 + int oldMinDigits = getMinimumFractionDigits();
30.2873 + // Common patterns are "#.##", "#.00", "#".
30.2874 + // Try to adjust all of them in a reasonable way.
30.2875 + if (oldMinDigits == getMaximumFractionDigits()) {
30.2876 + setMinimumFractionDigits(digits);
30.2877 + setMaximumFractionDigits(digits);
30.2878 + } else {
30.2879 + setMinimumFractionDigits(Math.min(digits, oldMinDigits));
30.2880 + setMaximumFractionDigits(digits);
30.2881 + }
30.2882 + }
30.2883 + }
30.2884 + }
30.2885 +
30.2886 + /**
30.2887 + * Reads the default serializable fields from the stream and performs
30.2888 + * validations and adjustments for older serialized versions. The
30.2889 + * validations and adjustments are:
30.2890 + * <ol>
30.2891 + * <li>
30.2892 + * Verify that the superclass's digit count fields correctly reflect
30.2893 + * the limits imposed on formatting numbers other than
30.2894 + * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
30.2895 + * limits are stored in the superclass for serialization compatibility
30.2896 + * with older versions, while the limits for <code>BigInteger</code> and
30.2897 + * <code>BigDecimal</code> objects are kept in this class.
30.2898 + * If, in the superclass, the minimum or maximum integer digit count is
30.2899 + * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
30.2900 + * maximum fraction digit count is larger than
30.2901 + * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
30.2902 + * and this method throws an <code>InvalidObjectException</code>.
30.2903 + * <li>
30.2904 + * If <code>serialVersionOnStream</code> is less than 4, initialize
30.2905 + * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
30.2906 + * RoundingMode.HALF_EVEN}. This field is new with version 4.
30.2907 + * <li>
30.2908 + * If <code>serialVersionOnStream</code> is less than 3, then call
30.2909 + * the setters for the minimum and maximum integer and fraction digits with
30.2910 + * the values of the corresponding superclass getters to initialize the
30.2911 + * fields in this class. The fields in this class are new with version 3.
30.2912 + * <li>
30.2913 + * If <code>serialVersionOnStream</code> is less than 1, indicating that
30.2914 + * the stream was written by JDK 1.1, initialize
30.2915 + * <code>useExponentialNotation</code>
30.2916 + * to false, since it was not present in JDK 1.1.
30.2917 + * <li>
30.2918 + * Set <code>serialVersionOnStream</code> to the maximum allowed value so
30.2919 + * that default serialization will work properly if this object is streamed
30.2920 + * out again.
30.2921 + * </ol>
30.2922 + *
30.2923 + * <p>Stream versions older than 2 will not have the affix pattern variables
30.2924 + * <code>posPrefixPattern</code> etc. As a result, they will be initialized
30.2925 + * to <code>null</code>, which means the affix strings will be taken as
30.2926 + * literal values. This is exactly what we want, since that corresponds to
30.2927 + * the pre-version-2 behavior.
30.2928 + */
30.2929 + private void readObject(ObjectInputStream stream)
30.2930 + throws IOException, ClassNotFoundException
30.2931 + {
30.2932 + stream.defaultReadObject();
30.2933 + digitList = new DigitList();
30.2934 +
30.2935 + if (serialVersionOnStream < 4) {
30.2936 + setRoundingMode(RoundingMode.HALF_EVEN);
30.2937 + }
30.2938 + // We only need to check the maximum counts because NumberFormat
30.2939 + // .readObject has already ensured that the maximum is greater than the
30.2940 + // minimum count.
30.2941 + if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
30.2942 + super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
30.2943 + throw new InvalidObjectException("Digit count out of range");
30.2944 + }
30.2945 + if (serialVersionOnStream < 3) {
30.2946 + setMaximumIntegerDigits(super.getMaximumIntegerDigits());
30.2947 + setMinimumIntegerDigits(super.getMinimumIntegerDigits());
30.2948 + setMaximumFractionDigits(super.getMaximumFractionDigits());
30.2949 + setMinimumFractionDigits(super.getMinimumFractionDigits());
30.2950 + }
30.2951 + if (serialVersionOnStream < 1) {
30.2952 + // Didn't have exponential fields
30.2953 + useExponentialNotation = false;
30.2954 + }
30.2955 + serialVersionOnStream = currentSerialVersion;
30.2956 + }
30.2957 +
30.2958 + //----------------------------------------------------------------------
30.2959 + // INSTANCE VARIABLES
30.2960 + //----------------------------------------------------------------------
30.2961 +
30.2962 + private transient DigitList digitList = new DigitList();
30.2963 +
30.2964 + /**
30.2965 + * The symbol used as a prefix when formatting positive numbers, e.g. "+".
30.2966 + *
30.2967 + * @serial
30.2968 + * @see #getPositivePrefix
30.2969 + */
30.2970 + private String positivePrefix = "";
30.2971 +
30.2972 + /**
30.2973 + * The symbol used as a suffix when formatting positive numbers.
30.2974 + * This is often an empty string.
30.2975 + *
30.2976 + * @serial
30.2977 + * @see #getPositiveSuffix
30.2978 + */
30.2979 + private String positiveSuffix = "";
30.2980 +
30.2981 + /**
30.2982 + * The symbol used as a prefix when formatting negative numbers, e.g. "-".
30.2983 + *
30.2984 + * @serial
30.2985 + * @see #getNegativePrefix
30.2986 + */
30.2987 + private String negativePrefix = "-";
30.2988 +
30.2989 + /**
30.2990 + * The symbol used as a suffix when formatting negative numbers.
30.2991 + * This is often an empty string.
30.2992 + *
30.2993 + * @serial
30.2994 + * @see #getNegativeSuffix
30.2995 + */
30.2996 + private String negativeSuffix = "";
30.2997 +
30.2998 + /**
30.2999 + * The prefix pattern for non-negative numbers. This variable corresponds
30.3000 + * to <code>positivePrefix</code>.
30.3001 + *
30.3002 + * <p>This pattern is expanded by the method <code>expandAffix()</code> to
30.3003 + * <code>positivePrefix</code> to update the latter to reflect changes in
30.3004 + * <code>symbols</code>. If this variable is <code>null</code> then
30.3005 + * <code>positivePrefix</code> is taken as a literal value that does not
30.3006 + * change when <code>symbols</code> changes. This variable is always
30.3007 + * <code>null</code> for <code>DecimalFormat</code> objects older than
30.3008 + * stream version 2 restored from stream.
30.3009 + *
30.3010 + * @serial
30.3011 + * @since 1.3
30.3012 + */
30.3013 + private String posPrefixPattern;
30.3014 +
30.3015 + /**
30.3016 + * The suffix pattern for non-negative numbers. This variable corresponds
30.3017 + * to <code>positiveSuffix</code>. This variable is analogous to
30.3018 + * <code>posPrefixPattern</code>; see that variable for further
30.3019 + * documentation.
30.3020 + *
30.3021 + * @serial
30.3022 + * @since 1.3
30.3023 + */
30.3024 + private String posSuffixPattern;
30.3025 +
30.3026 + /**
30.3027 + * The prefix pattern for negative numbers. This variable corresponds
30.3028 + * to <code>negativePrefix</code>. This variable is analogous to
30.3029 + * <code>posPrefixPattern</code>; see that variable for further
30.3030 + * documentation.
30.3031 + *
30.3032 + * @serial
30.3033 + * @since 1.3
30.3034 + */
30.3035 + private String negPrefixPattern;
30.3036 +
30.3037 + /**
30.3038 + * The suffix pattern for negative numbers. This variable corresponds
30.3039 + * to <code>negativeSuffix</code>. This variable is analogous to
30.3040 + * <code>posPrefixPattern</code>; see that variable for further
30.3041 + * documentation.
30.3042 + *
30.3043 + * @serial
30.3044 + * @since 1.3
30.3045 + */
30.3046 + private String negSuffixPattern;
30.3047 +
30.3048 + /**
30.3049 + * The multiplier for use in percent, per mille, etc.
30.3050 + *
30.3051 + * @serial
30.3052 + * @see #getMultiplier
30.3053 + */
30.3054 + private int multiplier = 1;
30.3055 +
30.3056 + /**
30.3057 + * The number of digits between grouping separators in the integer
30.3058 + * portion of a number. Must be greater than 0 if
30.3059 + * <code>NumberFormat.groupingUsed</code> is true.
30.3060 + *
30.3061 + * @serial
30.3062 + * @see #getGroupingSize
30.3063 + * @see java.text.NumberFormat#isGroupingUsed
30.3064 + */
30.3065 + private byte groupingSize = 3; // invariant, > 0 if useThousands
30.3066 +
30.3067 + /**
30.3068 + * If true, forces the decimal separator to always appear in a formatted
30.3069 + * number, even if the fractional part of the number is zero.
30.3070 + *
30.3071 + * @serial
30.3072 + * @see #isDecimalSeparatorAlwaysShown
30.3073 + */
30.3074 + private boolean decimalSeparatorAlwaysShown = false;
30.3075 +
30.3076 + /**
30.3077 + * If true, parse returns BigDecimal wherever possible.
30.3078 + *
30.3079 + * @serial
30.3080 + * @see #isParseBigDecimal
30.3081 + * @since 1.5
30.3082 + */
30.3083 + private boolean parseBigDecimal = false;
30.3084 +
30.3085 +
30.3086 + /**
30.3087 + * True if this object represents a currency format. This determines
30.3088 + * whether the monetary decimal separator is used instead of the normal one.
30.3089 + */
30.3090 + private transient boolean isCurrencyFormat = false;
30.3091 +
30.3092 + /**
30.3093 + * The <code>DecimalFormatSymbols</code> object used by this format.
30.3094 + * It contains the symbols used to format numbers, e.g. the grouping separator,
30.3095 + * decimal separator, and so on.
30.3096 + *
30.3097 + * @serial
30.3098 + * @see #setDecimalFormatSymbols
30.3099 + * @see java.text.DecimalFormatSymbols
30.3100 + */
30.3101 + private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
30.3102 +
30.3103 + /**
30.3104 + * True to force the use of exponential (i.e. scientific) notation when formatting
30.3105 + * numbers.
30.3106 + *
30.3107 + * @serial
30.3108 + * @since 1.2
30.3109 + */
30.3110 + private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2
30.3111 +
30.3112 + /**
30.3113 + * FieldPositions describing the positive prefix String. This is
30.3114 + * lazily created. Use <code>getPositivePrefixFieldPositions</code>
30.3115 + * when needed.
30.3116 + */
30.3117 + private transient FieldPosition[] positivePrefixFieldPositions;
30.3118 +
30.3119 + /**
30.3120 + * FieldPositions describing the positive suffix String. This is
30.3121 + * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
30.3122 + * when needed.
30.3123 + */
30.3124 + private transient FieldPosition[] positiveSuffixFieldPositions;
30.3125 +
30.3126 + /**
30.3127 + * FieldPositions describing the negative prefix String. This is
30.3128 + * lazily created. Use <code>getNegativePrefixFieldPositions</code>
30.3129 + * when needed.
30.3130 + */
30.3131 + private transient FieldPosition[] negativePrefixFieldPositions;
30.3132 +
30.3133 + /**
30.3134 + * FieldPositions describing the negative suffix String. This is
30.3135 + * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
30.3136 + * when needed.
30.3137 + */
30.3138 + private transient FieldPosition[] negativeSuffixFieldPositions;
30.3139 +
30.3140 + /**
30.3141 + * The minimum number of digits used to display the exponent when a number is
30.3142 + * formatted in exponential notation. This field is ignored if
30.3143 + * <code>useExponentialNotation</code> is not true.
30.3144 + *
30.3145 + * @serial
30.3146 + * @since 1.2
30.3147 + */
30.3148 + private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2
30.3149 +
30.3150 + /**
30.3151 + * The maximum number of digits allowed in the integer portion of a
30.3152 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
30.3153 + * <code>maximumIntegerDigits</code> must be greater than or equal to
30.3154 + * <code>minimumIntegerDigits</code>.
30.3155 + *
30.3156 + * @serial
30.3157 + * @see #getMaximumIntegerDigits
30.3158 + * @since 1.5
30.3159 + */
30.3160 + private int maximumIntegerDigits = super.getMaximumIntegerDigits();
30.3161 +
30.3162 + /**
30.3163 + * The minimum number of digits allowed in the integer portion of a
30.3164 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
30.3165 + * <code>minimumIntegerDigits</code> must be less than or equal to
30.3166 + * <code>maximumIntegerDigits</code>.
30.3167 + *
30.3168 + * @serial
30.3169 + * @see #getMinimumIntegerDigits
30.3170 + * @since 1.5
30.3171 + */
30.3172 + private int minimumIntegerDigits = super.getMinimumIntegerDigits();
30.3173 +
30.3174 + /**
30.3175 + * The maximum number of digits allowed in the fractional portion of a
30.3176 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
30.3177 + * <code>maximumFractionDigits</code> must be greater than or equal to
30.3178 + * <code>minimumFractionDigits</code>.
30.3179 + *
30.3180 + * @serial
30.3181 + * @see #getMaximumFractionDigits
30.3182 + * @since 1.5
30.3183 + */
30.3184 + private int maximumFractionDigits = super.getMaximumFractionDigits();
30.3185 +
30.3186 + /**
30.3187 + * The minimum number of digits allowed in the fractional portion of a
30.3188 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
30.3189 + * <code>minimumFractionDigits</code> must be less than or equal to
30.3190 + * <code>maximumFractionDigits</code>.
30.3191 + *
30.3192 + * @serial
30.3193 + * @see #getMinimumFractionDigits
30.3194 + * @since 1.5
30.3195 + */
30.3196 + private int minimumFractionDigits = super.getMinimumFractionDigits();
30.3197 +
30.3198 + /**
30.3199 + * The {@link java.math.RoundingMode} used in this DecimalFormat.
30.3200 + *
30.3201 + * @serial
30.3202 + * @since 1.6
30.3203 + */
30.3204 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
30.3205 +
30.3206 + //----------------------------------------------------------------------
30.3207 +
30.3208 + static final int currentSerialVersion = 4;
30.3209 +
30.3210 + /**
30.3211 + * The internal serial version which says which version was written.
30.3212 + * Possible values are:
30.3213 + * <ul>
30.3214 + * <li><b>0</b> (default): versions before the Java 2 platform v1.2
30.3215 + * <li><b>1</b>: version for 1.2, which includes the two new fields
30.3216 + * <code>useExponentialNotation</code> and
30.3217 + * <code>minExponentDigits</code>.
30.3218 + * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
30.3219 + * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
30.3220 + * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
30.3221 + * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
30.3222 + * <code>maximumIntegerDigits</code>,
30.3223 + * <code>minimumIntegerDigits</code>,
30.3224 + * <code>maximumFractionDigits</code>,
30.3225 + * <code>minimumFractionDigits</code>, and
30.3226 + * <code>parseBigDecimal</code>.
30.3227 + * <li><b>4</b>: version for 1.6 and later, which adds one new field:
30.3228 + * <code>roundingMode</code>.
30.3229 + * </ul>
30.3230 + * @since 1.2
30.3231 + * @serial
30.3232 + */
30.3233 + private int serialVersionOnStream = currentSerialVersion;
30.3234 +
30.3235 + //----------------------------------------------------------------------
30.3236 + // CONSTANTS
30.3237 + //----------------------------------------------------------------------
30.3238 +
30.3239 + // Constants for characters used in programmatic (unlocalized) patterns.
30.3240 + private static final char PATTERN_ZERO_DIGIT = '0';
30.3241 + private static final char PATTERN_GROUPING_SEPARATOR = ',';
30.3242 + private static final char PATTERN_DECIMAL_SEPARATOR = '.';
30.3243 + private static final char PATTERN_PER_MILLE = '\u2030';
30.3244 + private static final char PATTERN_PERCENT = '%';
30.3245 + private static final char PATTERN_DIGIT = '#';
30.3246 + private static final char PATTERN_SEPARATOR = ';';
30.3247 + private static final String PATTERN_EXPONENT = "E";
30.3248 + private static final char PATTERN_MINUS = '-';
30.3249 +
30.3250 + /**
30.3251 + * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
30.3252 + * is used in patterns and substituted with either the currency symbol,
30.3253 + * or if it is doubled, with the international currency symbol. If the
30.3254 + * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
30.3255 + * replaced with the monetary decimal separator.
30.3256 + *
30.3257 + * The CURRENCY_SIGN is not localized.
30.3258 + */
30.3259 + private static final char CURRENCY_SIGN = '\u00A4';
30.3260 +
30.3261 + private static final char QUOTE = '\'';
30.3262 +
30.3263 + private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
30.3264 +
30.3265 + // Upper limit on integer and fraction digits for a Java double
30.3266 + static final int DOUBLE_INTEGER_DIGITS = 309;
30.3267 + static final int DOUBLE_FRACTION_DIGITS = 340;
30.3268 +
30.3269 + // Upper limit on integer and fraction digits for BigDecimal and BigInteger
30.3270 + static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE;
30.3271 + static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
30.3272 +
30.3273 + // Proclaim JDK 1.1 serial compatibility.
30.3274 + static final long serialVersionUID = 864413376551465018L;
30.3275 +
30.3276 + /**
30.3277 + * Cache to hold the NumberPattern of a Locale.
30.3278 + */
30.3279 + private static final ConcurrentMap<Locale, String> cachedLocaleData
30.3280 + = new ConcurrentHashMap<Locale, String>(3);
30.3281 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormatSymbols.java Thu Oct 03 15:43:10 2013 +0200
31.3 @@ -0,0 +1,837 @@
31.4 +/*
31.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
31.7 + *
31.8 + * This code is free software; you can redistribute it and/or modify it
31.9 + * under the terms of the GNU General Public License version 2 only, as
31.10 + * published by the Free Software Foundation. Oracle designates this
31.11 + * particular file as subject to the "Classpath" exception as provided
31.12 + * by Oracle in the LICENSE file that accompanied this code.
31.13 + *
31.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
31.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
31.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31.17 + * version 2 for more details (a copy is included in the LICENSE file that
31.18 + * accompanied this code).
31.19 + *
31.20 + * You should have received a copy of the GNU General Public License version
31.21 + * 2 along with this work; if not, write to the Free Software Foundation,
31.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
31.23 + *
31.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
31.25 + * or visit www.oracle.com if you need additional information or have any
31.26 + * questions.
31.27 + */
31.28 +
31.29 +/*
31.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
31.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
31.32 + *
31.33 + * The original version of this source code and documentation is copyrighted
31.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
31.35 + * materials are provided under terms of a License Agreement between Taligent
31.36 + * and Sun. This technology is protected by multiple US and International
31.37 + * patents. This notice and attribution to Taligent may not be removed.
31.38 + * Taligent is a registered trademark of Taligent, Inc.
31.39 + *
31.40 + */
31.41 +
31.42 +package java.text;
31.43 +
31.44 +import java.io.IOException;
31.45 +import java.io.ObjectInputStream;
31.46 +import java.io.Serializable;
31.47 +import java.text.spi.DecimalFormatSymbolsProvider;
31.48 +import java.util.Currency;
31.49 +import java.util.Locale;
31.50 +import java.util.ResourceBundle;
31.51 +import java.util.concurrent.ConcurrentHashMap;
31.52 +
31.53 +import sun.util.LocaleServiceProviderPool;
31.54 +import sun.util.resources.LocaleData;
31.55 +
31.56 +/**
31.57 + * This class represents the set of symbols (such as the decimal separator,
31.58 + * the grouping separator, and so on) needed by <code>DecimalFormat</code>
31.59 + * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
31.60 + * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
31.61 + * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
31.62 + * your <code>DecimalFormat</code> and modify it.
31.63 + *
31.64 + * @see java.util.Locale
31.65 + * @see DecimalFormat
31.66 + * @author Mark Davis
31.67 + * @author Alan Liu
31.68 + */
31.69 +
31.70 +public class DecimalFormatSymbols implements Cloneable, Serializable {
31.71 +
31.72 + /**
31.73 + * Create a DecimalFormatSymbols object for the default locale.
31.74 + * This constructor can only construct instances for the locales
31.75 + * supported by the Java runtime environment, not for those
31.76 + * supported by installed
31.77 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
31.78 + * implementations. For full locale coverage, use the
31.79 + * {@link #getInstance(Locale) getInstance} method.
31.80 + */
31.81 + public DecimalFormatSymbols() {
31.82 + initialize( Locale.getDefault(Locale.Category.FORMAT) );
31.83 + }
31.84 +
31.85 + /**
31.86 + * Create a DecimalFormatSymbols object for the given locale.
31.87 + * This constructor can only construct instances for the locales
31.88 + * supported by the Java runtime environment, not for those
31.89 + * supported by installed
31.90 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
31.91 + * implementations. For full locale coverage, use the
31.92 + * {@link #getInstance(Locale) getInstance} method.
31.93 + *
31.94 + * @exception NullPointerException if <code>locale</code> is null
31.95 + */
31.96 + public DecimalFormatSymbols( Locale locale ) {
31.97 + initialize( locale );
31.98 + }
31.99 +
31.100 + /**
31.101 + * Returns an array of all locales for which the
31.102 + * <code>getInstance</code> methods of this class can return
31.103 + * localized instances.
31.104 + * The returned array represents the union of locales supported by the Java
31.105 + * runtime and by installed
31.106 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
31.107 + * implementations. It must contain at least a <code>Locale</code>
31.108 + * instance equal to {@link java.util.Locale#US Locale.US}.
31.109 + *
31.110 + * @return An array of locales for which localized
31.111 + * <code>DecimalFormatSymbols</code> instances are available.
31.112 + * @since 1.6
31.113 + */
31.114 + public static Locale[] getAvailableLocales() {
31.115 + LocaleServiceProviderPool pool =
31.116 + LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
31.117 + return pool.getAvailableLocales();
31.118 + }
31.119 +
31.120 + /**
31.121 + * Gets the <code>DecimalFormatSymbols</code> instance for the default
31.122 + * locale. This method provides access to <code>DecimalFormatSymbols</code>
31.123 + * instances for locales supported by the Java runtime itself as well
31.124 + * as for those supported by installed
31.125 + * {@link java.text.spi.DecimalFormatSymbolsProvider
31.126 + * DecimalFormatSymbolsProvider} implementations.
31.127 + * @return a <code>DecimalFormatSymbols</code> instance.
31.128 + * @since 1.6
31.129 + */
31.130 + public static final DecimalFormatSymbols getInstance() {
31.131 + return getInstance(Locale.getDefault(Locale.Category.FORMAT));
31.132 + }
31.133 +
31.134 + /**
31.135 + * Gets the <code>DecimalFormatSymbols</code> instance for the specified
31.136 + * locale. This method provides access to <code>DecimalFormatSymbols</code>
31.137 + * instances for locales supported by the Java runtime itself as well
31.138 + * as for those supported by installed
31.139 + * {@link java.text.spi.DecimalFormatSymbolsProvider
31.140 + * DecimalFormatSymbolsProvider} implementations.
31.141 + * @param locale the desired locale.
31.142 + * @return a <code>DecimalFormatSymbols</code> instance.
31.143 + * @exception NullPointerException if <code>locale</code> is null
31.144 + * @since 1.6
31.145 + */
31.146 + public static final DecimalFormatSymbols getInstance(Locale locale) {
31.147 +
31.148 + // Check whether a provider can provide an implementation that's closer
31.149 + // to the requested locale than what the Java runtime itself can provide.
31.150 + LocaleServiceProviderPool pool =
31.151 + LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
31.152 + if (pool.hasProviders()) {
31.153 + DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
31.154 + DecimalFormatSymbolsGetter.INSTANCE, locale);
31.155 + if (providersInstance != null) {
31.156 + return providersInstance;
31.157 + }
31.158 + }
31.159 +
31.160 + return new DecimalFormatSymbols(locale);
31.161 + }
31.162 +
31.163 + /**
31.164 + * Gets the character used for zero. Different for Arabic, etc.
31.165 + */
31.166 + public char getZeroDigit() {
31.167 + return zeroDigit;
31.168 + }
31.169 +
31.170 + /**
31.171 + * Sets the character used for zero. Different for Arabic, etc.
31.172 + */
31.173 + public void setZeroDigit(char zeroDigit) {
31.174 + this.zeroDigit = zeroDigit;
31.175 + }
31.176 +
31.177 + /**
31.178 + * Gets the character used for thousands separator. Different for French, etc.
31.179 + */
31.180 + public char getGroupingSeparator() {
31.181 + return groupingSeparator;
31.182 + }
31.183 +
31.184 + /**
31.185 + * Sets the character used for thousands separator. Different for French, etc.
31.186 + */
31.187 + public void setGroupingSeparator(char groupingSeparator) {
31.188 + this.groupingSeparator = groupingSeparator;
31.189 + }
31.190 +
31.191 + /**
31.192 + * Gets the character used for decimal sign. Different for French, etc.
31.193 + */
31.194 + public char getDecimalSeparator() {
31.195 + return decimalSeparator;
31.196 + }
31.197 +
31.198 + /**
31.199 + * Sets the character used for decimal sign. Different for French, etc.
31.200 + */
31.201 + public void setDecimalSeparator(char decimalSeparator) {
31.202 + this.decimalSeparator = decimalSeparator;
31.203 + }
31.204 +
31.205 + /**
31.206 + * Gets the character used for per mille sign. Different for Arabic, etc.
31.207 + */
31.208 + public char getPerMill() {
31.209 + return perMill;
31.210 + }
31.211 +
31.212 + /**
31.213 + * Sets the character used for per mille sign. Different for Arabic, etc.
31.214 + */
31.215 + public void setPerMill(char perMill) {
31.216 + this.perMill = perMill;
31.217 + }
31.218 +
31.219 + /**
31.220 + * Gets the character used for percent sign. Different for Arabic, etc.
31.221 + */
31.222 + public char getPercent() {
31.223 + return percent;
31.224 + }
31.225 +
31.226 + /**
31.227 + * Sets the character used for percent sign. Different for Arabic, etc.
31.228 + */
31.229 + public void setPercent(char percent) {
31.230 + this.percent = percent;
31.231 + }
31.232 +
31.233 + /**
31.234 + * Gets the character used for a digit in a pattern.
31.235 + */
31.236 + public char getDigit() {
31.237 + return digit;
31.238 + }
31.239 +
31.240 + /**
31.241 + * Sets the character used for a digit in a pattern.
31.242 + */
31.243 + public void setDigit(char digit) {
31.244 + this.digit = digit;
31.245 + }
31.246 +
31.247 + /**
31.248 + * Gets the character used to separate positive and negative subpatterns
31.249 + * in a pattern.
31.250 + */
31.251 + public char getPatternSeparator() {
31.252 + return patternSeparator;
31.253 + }
31.254 +
31.255 + /**
31.256 + * Sets the character used to separate positive and negative subpatterns
31.257 + * in a pattern.
31.258 + */
31.259 + public void setPatternSeparator(char patternSeparator) {
31.260 + this.patternSeparator = patternSeparator;
31.261 + }
31.262 +
31.263 + /**
31.264 + * Gets the string used to represent infinity. Almost always left
31.265 + * unchanged.
31.266 + */
31.267 + public String getInfinity() {
31.268 + return infinity;
31.269 + }
31.270 +
31.271 + /**
31.272 + * Sets the string used to represent infinity. Almost always left
31.273 + * unchanged.
31.274 + */
31.275 + public void setInfinity(String infinity) {
31.276 + this.infinity = infinity;
31.277 + }
31.278 +
31.279 + /**
31.280 + * Gets the string used to represent "not a number". Almost always left
31.281 + * unchanged.
31.282 + */
31.283 + public String getNaN() {
31.284 + return NaN;
31.285 + }
31.286 +
31.287 + /**
31.288 + * Sets the string used to represent "not a number". Almost always left
31.289 + * unchanged.
31.290 + */
31.291 + public void setNaN(String NaN) {
31.292 + this.NaN = NaN;
31.293 + }
31.294 +
31.295 + /**
31.296 + * Gets the character used to represent minus sign. If no explicit
31.297 + * negative format is specified, one is formed by prefixing
31.298 + * minusSign to the positive format.
31.299 + */
31.300 + public char getMinusSign() {
31.301 + return minusSign;
31.302 + }
31.303 +
31.304 + /**
31.305 + * Sets the character used to represent minus sign. If no explicit
31.306 + * negative format is specified, one is formed by prefixing
31.307 + * minusSign to the positive format.
31.308 + */
31.309 + public void setMinusSign(char minusSign) {
31.310 + this.minusSign = minusSign;
31.311 + }
31.312 +
31.313 + /**
31.314 + * Returns the currency symbol for the currency of these
31.315 + * DecimalFormatSymbols in their locale.
31.316 + * @since 1.2
31.317 + */
31.318 + public String getCurrencySymbol()
31.319 + {
31.320 + return currencySymbol;
31.321 + }
31.322 +
31.323 + /**
31.324 + * Sets the currency symbol for the currency of these
31.325 + * DecimalFormatSymbols in their locale.
31.326 + * @since 1.2
31.327 + */
31.328 + public void setCurrencySymbol(String currency)
31.329 + {
31.330 + currencySymbol = currency;
31.331 + }
31.332 +
31.333 + /**
31.334 + * Returns the ISO 4217 currency code of the currency of these
31.335 + * DecimalFormatSymbols.
31.336 + * @since 1.2
31.337 + */
31.338 + public String getInternationalCurrencySymbol()
31.339 + {
31.340 + return intlCurrencySymbol;
31.341 + }
31.342 +
31.343 + /**
31.344 + * Sets the ISO 4217 currency code of the currency of these
31.345 + * DecimalFormatSymbols.
31.346 + * If the currency code is valid (as defined by
31.347 + * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
31.348 + * this also sets the currency attribute to the corresponding Currency
31.349 + * instance and the currency symbol attribute to the currency's symbol
31.350 + * in the DecimalFormatSymbols' locale. If the currency code is not valid,
31.351 + * then the currency attribute is set to null and the currency symbol
31.352 + * attribute is not modified.
31.353 + *
31.354 + * @see #setCurrency
31.355 + * @see #setCurrencySymbol
31.356 + * @since 1.2
31.357 + */
31.358 + public void setInternationalCurrencySymbol(String currencyCode)
31.359 + {
31.360 + intlCurrencySymbol = currencyCode;
31.361 + currency = null;
31.362 + if (currencyCode != null) {
31.363 + try {
31.364 + currency = Currency.getInstance(currencyCode);
31.365 + currencySymbol = currency.getSymbol();
31.366 + } catch (IllegalArgumentException e) {
31.367 + }
31.368 + }
31.369 + }
31.370 +
31.371 + /**
31.372 + * Gets the currency of these DecimalFormatSymbols. May be null if the
31.373 + * currency symbol attribute was previously set to a value that's not
31.374 + * a valid ISO 4217 currency code.
31.375 + *
31.376 + * @return the currency used, or null
31.377 + * @since 1.4
31.378 + */
31.379 + public Currency getCurrency() {
31.380 + return currency;
31.381 + }
31.382 +
31.383 + /**
31.384 + * Sets the currency of these DecimalFormatSymbols.
31.385 + * This also sets the currency symbol attribute to the currency's symbol
31.386 + * in the DecimalFormatSymbols' locale, and the international currency
31.387 + * symbol attribute to the currency's ISO 4217 currency code.
31.388 + *
31.389 + * @param currency the new currency to be used
31.390 + * @exception NullPointerException if <code>currency</code> is null
31.391 + * @since 1.4
31.392 + * @see #setCurrencySymbol
31.393 + * @see #setInternationalCurrencySymbol
31.394 + */
31.395 + public void setCurrency(Currency currency) {
31.396 + if (currency == null) {
31.397 + throw new NullPointerException();
31.398 + }
31.399 + this.currency = currency;
31.400 + intlCurrencySymbol = currency.getCurrencyCode();
31.401 + currencySymbol = currency.getSymbol(locale);
31.402 + }
31.403 +
31.404 +
31.405 + /**
31.406 + * Returns the monetary decimal separator.
31.407 + * @since 1.2
31.408 + */
31.409 + public char getMonetaryDecimalSeparator()
31.410 + {
31.411 + return monetarySeparator;
31.412 + }
31.413 +
31.414 + /**
31.415 + * Sets the monetary decimal separator.
31.416 + * @since 1.2
31.417 + */
31.418 + public void setMonetaryDecimalSeparator(char sep)
31.419 + {
31.420 + monetarySeparator = sep;
31.421 + }
31.422 +
31.423 + //------------------------------------------------------------
31.424 + // BEGIN Package Private methods ... to be made public later
31.425 + //------------------------------------------------------------
31.426 +
31.427 + /**
31.428 + * Returns the character used to separate the mantissa from the exponent.
31.429 + */
31.430 + char getExponentialSymbol()
31.431 + {
31.432 + return exponential;
31.433 + }
31.434 + /**
31.435 + * Returns the string used to separate the mantissa from the exponent.
31.436 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
31.437 + *
31.438 + * @return the exponent separator string
31.439 + * @see #setExponentSeparator(java.lang.String)
31.440 + * @since 1.6
31.441 + */
31.442 + public String getExponentSeparator()
31.443 + {
31.444 + return exponentialSeparator;
31.445 + }
31.446 +
31.447 + /**
31.448 + * Sets the character used to separate the mantissa from the exponent.
31.449 + */
31.450 + void setExponentialSymbol(char exp)
31.451 + {
31.452 + exponential = exp;
31.453 + }
31.454 +
31.455 + /**
31.456 + * Sets the string used to separate the mantissa from the exponent.
31.457 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
31.458 + *
31.459 + * @param exp the exponent separator string
31.460 + * @exception NullPointerException if <code>exp</code> is null
31.461 + * @see #getExponentSeparator()
31.462 + * @since 1.6
31.463 + */
31.464 + public void setExponentSeparator(String exp)
31.465 + {
31.466 + if (exp == null) {
31.467 + throw new NullPointerException();
31.468 + }
31.469 + exponentialSeparator = exp;
31.470 + }
31.471 +
31.472 +
31.473 + //------------------------------------------------------------
31.474 + // END Package Private methods ... to be made public later
31.475 + //------------------------------------------------------------
31.476 +
31.477 + /**
31.478 + * Standard override.
31.479 + */
31.480 + public Object clone() {
31.481 + try {
31.482 + return (DecimalFormatSymbols)super.clone();
31.483 + // other fields are bit-copied
31.484 + } catch (CloneNotSupportedException e) {
31.485 + throw new InternalError();
31.486 + }
31.487 + }
31.488 +
31.489 + /**
31.490 + * Override equals.
31.491 + */
31.492 + public boolean equals(Object obj) {
31.493 + if (obj == null) return false;
31.494 + if (this == obj) return true;
31.495 + if (getClass() != obj.getClass()) return false;
31.496 + DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
31.497 + return (zeroDigit == other.zeroDigit &&
31.498 + groupingSeparator == other.groupingSeparator &&
31.499 + decimalSeparator == other.decimalSeparator &&
31.500 + percent == other.percent &&
31.501 + perMill == other.perMill &&
31.502 + digit == other.digit &&
31.503 + minusSign == other.minusSign &&
31.504 + patternSeparator == other.patternSeparator &&
31.505 + infinity.equals(other.infinity) &&
31.506 + NaN.equals(other.NaN) &&
31.507 + currencySymbol.equals(other.currencySymbol) &&
31.508 + intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
31.509 + currency == other.currency &&
31.510 + monetarySeparator == other.monetarySeparator &&
31.511 + exponentialSeparator.equals(other.exponentialSeparator) &&
31.512 + locale.equals(other.locale));
31.513 + }
31.514 +
31.515 + /**
31.516 + * Override hashCode.
31.517 + */
31.518 + public int hashCode() {
31.519 + int result = zeroDigit;
31.520 + result = result * 37 + groupingSeparator;
31.521 + result = result * 37 + decimalSeparator;
31.522 + return result;
31.523 + }
31.524 +
31.525 + /**
31.526 + * Initializes the symbols from the FormatData resource bundle.
31.527 + */
31.528 + private void initialize( Locale locale ) {
31.529 + this.locale = locale;
31.530 +
31.531 + // get resource bundle data - try the cache first
31.532 + boolean needCacheUpdate = false;
31.533 + Object[] data = cachedLocaleData.get(locale);
31.534 + if (data == null) { /* cache miss */
31.535 + // When numbering system is thai (Locale's extension contains u-nu-thai),
31.536 + // we read the data from th_TH_TH.
31.537 + Locale lookupLocale = locale;
31.538 + String numberType = locale.getUnicodeLocaleType("nu");
31.539 + if (numberType != null && numberType.equals("thai")) {
31.540 + lookupLocale = new Locale("th", "TH", "TH");
31.541 + }
31.542 + data = new Object[3];
31.543 + ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);
31.544 + data[0] = rb.getStringArray("NumberElements");
31.545 + needCacheUpdate = true;
31.546 + }
31.547 +
31.548 + String[] numberElements = (String[]) data[0];
31.549 +
31.550 + decimalSeparator = numberElements[0].charAt(0);
31.551 + groupingSeparator = numberElements[1].charAt(0);
31.552 + patternSeparator = numberElements[2].charAt(0);
31.553 + percent = numberElements[3].charAt(0);
31.554 + zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
31.555 + digit = numberElements[5].charAt(0);
31.556 + minusSign = numberElements[6].charAt(0);
31.557 + exponential = numberElements[7].charAt(0);
31.558 + exponentialSeparator = numberElements[7]; //string representation new since 1.6
31.559 + perMill = numberElements[8].charAt(0);
31.560 + infinity = numberElements[9];
31.561 + NaN = numberElements[10];
31.562 +
31.563 + // Try to obtain the currency used in the locale's country.
31.564 + // Check for empty country string separately because it's a valid
31.565 + // country ID for Locale (and used for the C locale), but not a valid
31.566 + // ISO 3166 country code, and exceptions are expensive.
31.567 + if (!"".equals(locale.getCountry())) {
31.568 + try {
31.569 + currency = Currency.getInstance(locale);
31.570 + } catch (IllegalArgumentException e) {
31.571 + // use default values below for compatibility
31.572 + }
31.573 + }
31.574 + if (currency != null) {
31.575 + intlCurrencySymbol = currency.getCurrencyCode();
31.576 + if (data[1] != null && data[1] == intlCurrencySymbol) {
31.577 + currencySymbol = (String) data[2];
31.578 + } else {
31.579 + currencySymbol = currency.getSymbol(locale);
31.580 + data[1] = intlCurrencySymbol;
31.581 + data[2] = currencySymbol;
31.582 + needCacheUpdate = true;
31.583 + }
31.584 + } else {
31.585 + // default values
31.586 + intlCurrencySymbol = "XXX";
31.587 + try {
31.588 + currency = Currency.getInstance(intlCurrencySymbol);
31.589 + } catch (IllegalArgumentException e) {
31.590 + }
31.591 + currencySymbol = "\u00A4";
31.592 + }
31.593 + // Currently the monetary decimal separator is the same as the
31.594 + // standard decimal separator for all locales that we support.
31.595 + // If that changes, add a new entry to NumberElements.
31.596 + monetarySeparator = decimalSeparator;
31.597 +
31.598 + if (needCacheUpdate) {
31.599 + cachedLocaleData.putIfAbsent(locale, data);
31.600 + }
31.601 + }
31.602 +
31.603 + /**
31.604 + * Reads the default serializable fields, provides default values for objects
31.605 + * in older serial versions, and initializes non-serializable fields.
31.606 + * If <code>serialVersionOnStream</code>
31.607 + * is less than 1, initializes <code>monetarySeparator</code> to be
31.608 + * the same as <code>decimalSeparator</code> and <code>exponential</code>
31.609 + * to be 'E'.
31.610 + * If <code>serialVersionOnStream</code> is less than 2,
31.611 + * initializes <code>locale</code>to the root locale, and initializes
31.612 + * If <code>serialVersionOnStream</code> is less than 3, it initializes
31.613 + * <code>exponentialSeparator</code> using <code>exponential</code>.
31.614 + * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
31.615 + * default serialization will work properly if this object is streamed out again.
31.616 + * Initializes the currency from the intlCurrencySymbol field.
31.617 + *
31.618 + * @since JDK 1.1.6
31.619 + */
31.620 + private void readObject(ObjectInputStream stream)
31.621 + throws IOException, ClassNotFoundException {
31.622 + stream.defaultReadObject();
31.623 + if (serialVersionOnStream < 1) {
31.624 + // Didn't have monetarySeparator or exponential field;
31.625 + // use defaults.
31.626 + monetarySeparator = decimalSeparator;
31.627 + exponential = 'E';
31.628 + }
31.629 + if (serialVersionOnStream < 2) {
31.630 + // didn't have locale; use root locale
31.631 + locale = Locale.ROOT;
31.632 + }
31.633 + if (serialVersionOnStream < 3) {
31.634 + // didn't have exponentialSeparator. Create one using exponential
31.635 + exponentialSeparator = Character.toString(exponential);
31.636 + }
31.637 + serialVersionOnStream = currentSerialVersion;
31.638 +
31.639 + if (intlCurrencySymbol != null) {
31.640 + try {
31.641 + currency = Currency.getInstance(intlCurrencySymbol);
31.642 + } catch (IllegalArgumentException e) {
31.643 + }
31.644 + }
31.645 + }
31.646 +
31.647 + /**
31.648 + * Character used for zero.
31.649 + *
31.650 + * @serial
31.651 + * @see #getZeroDigit
31.652 + */
31.653 + private char zeroDigit;
31.654 +
31.655 + /**
31.656 + * Character used for thousands separator.
31.657 + *
31.658 + * @serial
31.659 + * @see #getGroupingSeparator
31.660 + */
31.661 + private char groupingSeparator;
31.662 +
31.663 + /**
31.664 + * Character used for decimal sign.
31.665 + *
31.666 + * @serial
31.667 + * @see #getDecimalSeparator
31.668 + */
31.669 + private char decimalSeparator;
31.670 +
31.671 + /**
31.672 + * Character used for per mille sign.
31.673 + *
31.674 + * @serial
31.675 + * @see #getPerMill
31.676 + */
31.677 + private char perMill;
31.678 +
31.679 + /**
31.680 + * Character used for percent sign.
31.681 + * @serial
31.682 + * @see #getPercent
31.683 + */
31.684 + private char percent;
31.685 +
31.686 + /**
31.687 + * Character used for a digit in a pattern.
31.688 + *
31.689 + * @serial
31.690 + * @see #getDigit
31.691 + */
31.692 + private char digit;
31.693 +
31.694 + /**
31.695 + * Character used to separate positive and negative subpatterns
31.696 + * in a pattern.
31.697 + *
31.698 + * @serial
31.699 + * @see #getPatternSeparator
31.700 + */
31.701 + private char patternSeparator;
31.702 +
31.703 + /**
31.704 + * String used to represent infinity.
31.705 + * @serial
31.706 + * @see #getInfinity
31.707 + */
31.708 + private String infinity;
31.709 +
31.710 + /**
31.711 + * String used to represent "not a number".
31.712 + * @serial
31.713 + * @see #getNaN
31.714 + */
31.715 + private String NaN;
31.716 +
31.717 + /**
31.718 + * Character used to represent minus sign.
31.719 + * @serial
31.720 + * @see #getMinusSign
31.721 + */
31.722 + private char minusSign;
31.723 +
31.724 + /**
31.725 + * String denoting the local currency, e.g. "$".
31.726 + * @serial
31.727 + * @see #getCurrencySymbol
31.728 + */
31.729 + private String currencySymbol;
31.730 +
31.731 + /**
31.732 + * ISO 4217 currency code denoting the local currency, e.g. "USD".
31.733 + * @serial
31.734 + * @see #getInternationalCurrencySymbol
31.735 + */
31.736 + private String intlCurrencySymbol;
31.737 +
31.738 + /**
31.739 + * The decimal separator used when formatting currency values.
31.740 + * @serial
31.741 + * @since JDK 1.1.6
31.742 + * @see #getMonetaryDecimalSeparator
31.743 + */
31.744 + private char monetarySeparator; // Field new in JDK 1.1.6
31.745 +
31.746 + /**
31.747 + * The character used to distinguish the exponent in a number formatted
31.748 + * in exponential notation, e.g. 'E' for a number such as "1.23E45".
31.749 + * <p>
31.750 + * Note that the public API provides no way to set this field,
31.751 + * even though it is supported by the implementation and the stream format.
31.752 + * The intent is that this will be added to the API in the future.
31.753 + *
31.754 + * @serial
31.755 + * @since JDK 1.1.6
31.756 + */
31.757 + private char exponential; // Field new in JDK 1.1.6
31.758 +
31.759 + /**
31.760 + * The string used to separate the mantissa from the exponent.
31.761 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
31.762 + * <p>
31.763 + * If both <code>exponential</code> and <code>exponentialSeparator</code>
31.764 + * exist, this <code>exponentialSeparator</code> has the precedence.
31.765 + *
31.766 + * @serial
31.767 + * @since 1.6
31.768 + */
31.769 + private String exponentialSeparator; // Field new in JDK 1.6
31.770 +
31.771 + /**
31.772 + * The locale of these currency format symbols.
31.773 + *
31.774 + * @serial
31.775 + * @since 1.4
31.776 + */
31.777 + private Locale locale;
31.778 +
31.779 + // currency; only the ISO code is serialized.
31.780 + private transient Currency currency;
31.781 +
31.782 + // Proclaim JDK 1.1 FCS compatibility
31.783 + static final long serialVersionUID = 5772796243397350300L;
31.784 +
31.785 + // The internal serial version which says which version was written
31.786 + // - 0 (default) for version up to JDK 1.1.5
31.787 + // - 1 for version from JDK 1.1.6, which includes two new fields:
31.788 + // monetarySeparator and exponential.
31.789 + // - 2 for version from J2SE 1.4, which includes locale field.
31.790 + // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
31.791 + private static final int currentSerialVersion = 3;
31.792 +
31.793 + /**
31.794 + * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
31.795 + * Possible values are:
31.796 + * <ul>
31.797 + * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
31.798 + *
31.799 + * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
31.800 + * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
31.801 + * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
31.802 + * new <code>locale</code> field.
31.803 + * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
31.804 + * new <code>exponentialSeparator</code> field.
31.805 + * </ul>
31.806 + * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
31.807 + * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
31.808 + * is always written.
31.809 + *
31.810 + * @serial
31.811 + * @since JDK 1.1.6
31.812 + */
31.813 + private int serialVersionOnStream = currentSerialVersion;
31.814 +
31.815 + /**
31.816 + * cache to hold the NumberElements and the Currency
31.817 + * of a Locale.
31.818 + */
31.819 + private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
31.820 +
31.821 + /**
31.822 + * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
31.823 + * implementation.
31.824 + */
31.825 + private static class DecimalFormatSymbolsGetter
31.826 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
31.827 + DecimalFormatSymbols> {
31.828 + private static final DecimalFormatSymbolsGetter INSTANCE =
31.829 + new DecimalFormatSymbolsGetter();
31.830 +
31.831 + public DecimalFormatSymbols getObject(
31.832 + DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
31.833 + Locale locale,
31.834 + String key,
31.835 + Object... params) {
31.836 + assert params.length == 0;
31.837 + return decimalFormatSymbolsProvider.getInstance(locale);
31.838 + }
31.839 + }
31.840 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/rt/emul/compact/src/main/java/java/text/DigitList.java Thu Oct 03 15:43:10 2013 +0200
32.3 @@ -0,0 +1,715 @@
32.4 +/*
32.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
32.7 + *
32.8 + * This code is free software; you can redistribute it and/or modify it
32.9 + * under the terms of the GNU General Public License version 2 only, as
32.10 + * published by the Free Software Foundation. Oracle designates this
32.11 + * particular file as subject to the "Classpath" exception as provided
32.12 + * by Oracle in the LICENSE file that accompanied this code.
32.13 + *
32.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
32.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
32.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
32.17 + * version 2 for more details (a copy is included in the LICENSE file that
32.18 + * accompanied this code).
32.19 + *
32.20 + * You should have received a copy of the GNU General Public License version
32.21 + * 2 along with this work; if not, write to the Free Software Foundation,
32.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
32.23 + *
32.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
32.25 + * or visit www.oracle.com if you need additional information or have any
32.26 + * questions.
32.27 + */
32.28 +
32.29 +/*
32.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
32.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
32.32 + *
32.33 + * The original version of this source code and documentation is copyrighted
32.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32.35 + * materials are provided under terms of a License Agreement between Taligent
32.36 + * and Sun. This technology is protected by multiple US and International
32.37 + * patents. This notice and attribution to Taligent may not be removed.
32.38 + * Taligent is a registered trademark of Taligent, Inc.
32.39 + *
32.40 + */
32.41 +
32.42 +package java.text;
32.43 +
32.44 +import java.math.BigDecimal;
32.45 +import java.math.BigInteger;
32.46 +import java.math.RoundingMode;
32.47 +
32.48 +/**
32.49 + * Digit List. Private to DecimalFormat.
32.50 + * Handles the transcoding
32.51 + * between numeric values and strings of characters. Only handles
32.52 + * non-negative numbers. The division of labor between DigitList and
32.53 + * DecimalFormat is that DigitList handles the radix 10 representation
32.54 + * issues; DecimalFormat handles the locale-specific issues such as
32.55 + * positive/negative, grouping, decimal point, currency, and so on.
32.56 + *
32.57 + * A DigitList is really a representation of a floating point value.
32.58 + * It may be an integer value; we assume that a double has sufficient
32.59 + * precision to represent all digits of a long.
32.60 + *
32.61 + * The DigitList representation consists of a string of characters,
32.62 + * which are the digits radix 10, from '0' to '9'. It also has a radix
32.63 + * 10 exponent associated with it. The value represented by a DigitList
32.64 + * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
32.65 + * derived by placing all the digits of the list to the right of the
32.66 + * decimal point, by 10^exponent.
32.67 + *
32.68 + * @see Locale
32.69 + * @see Format
32.70 + * @see NumberFormat
32.71 + * @see DecimalFormat
32.72 + * @see ChoiceFormat
32.73 + * @see MessageFormat
32.74 + * @author Mark Davis, Alan Liu
32.75 + */
32.76 +final class DigitList implements Cloneable {
32.77 + /**
32.78 + * The maximum number of significant digits in an IEEE 754 double, that
32.79 + * is, in a Java double. This must not be increased, or garbage digits
32.80 + * will be generated, and should not be decreased, or accuracy will be lost.
32.81 + */
32.82 + public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
32.83 +
32.84 + /**
32.85 + * These data members are intentionally public and can be set directly.
32.86 + *
32.87 + * The value represented is given by placing the decimal point before
32.88 + * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
32.89 + * the decimal point and the first nonzero digit are implied. If decimalAt
32.90 + * is > count, then trailing zeros between the digits[count-1] and the
32.91 + * decimal point are implied.
32.92 + *
32.93 + * Equivalently, the represented value is given by f * 10^decimalAt. Here
32.94 + * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
32.95 + * the right of the decimal.
32.96 + *
32.97 + * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
32.98 + * don't allow denormalized numbers because our exponent is effectively of
32.99 + * unlimited magnitude. The count value contains the number of significant
32.100 + * digits present in digits[].
32.101 + *
32.102 + * Zero is represented by any DigitList with count == 0 or with each digits[i]
32.103 + * for all i <= count == '0'.
32.104 + */
32.105 + public int decimalAt = 0;
32.106 + public int count = 0;
32.107 + public char[] digits = new char[MAX_COUNT];
32.108 +
32.109 + private char[] data;
32.110 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
32.111 + private boolean isNegative = false;
32.112 +
32.113 + /**
32.114 + * Return true if the represented number is zero.
32.115 + */
32.116 + boolean isZero() {
32.117 + for (int i=0; i < count; ++i) {
32.118 + if (digits[i] != '0') {
32.119 + return false;
32.120 + }
32.121 + }
32.122 + return true;
32.123 + }
32.124 +
32.125 + /**
32.126 + * Set the rounding mode
32.127 + */
32.128 + void setRoundingMode(RoundingMode r) {
32.129 + roundingMode = r;
32.130 + }
32.131 +
32.132 + /**
32.133 + * Clears out the digits.
32.134 + * Use before appending them.
32.135 + * Typically, you set a series of digits with append, then at the point
32.136 + * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
32.137 + * then go on appending digits.
32.138 + */
32.139 + public void clear () {
32.140 + decimalAt = 0;
32.141 + count = 0;
32.142 + }
32.143 +
32.144 + /**
32.145 + * Appends a digit to the list, extending the list when necessary.
32.146 + */
32.147 + public void append(char digit) {
32.148 + if (count == digits.length) {
32.149 + char[] data = new char[count + 100];
32.150 + System.arraycopy(digits, 0, data, 0, count);
32.151 + digits = data;
32.152 + }
32.153 + digits[count++] = digit;
32.154 + }
32.155 +
32.156 + /**
32.157 + * Utility routine to get the value of the digit list
32.158 + * If (count == 0) this throws a NumberFormatException, which
32.159 + * mimics Long.parseLong().
32.160 + */
32.161 + public final double getDouble() {
32.162 + if (count == 0) {
32.163 + return 0.0;
32.164 + }
32.165 +
32.166 + StringBuffer temp = getStringBuffer();
32.167 + temp.append('.');
32.168 + temp.append(digits, 0, count);
32.169 + temp.append('E');
32.170 + temp.append(decimalAt);
32.171 + return Double.parseDouble(temp.toString());
32.172 + }
32.173 +
32.174 + /**
32.175 + * Utility routine to get the value of the digit list.
32.176 + * If (count == 0) this returns 0, unlike Long.parseLong().
32.177 + */
32.178 + public final long getLong() {
32.179 + // for now, simple implementation; later, do proper IEEE native stuff
32.180 +
32.181 + if (count == 0) {
32.182 + return 0;
32.183 + }
32.184 +
32.185 + // We have to check for this, because this is the one NEGATIVE value
32.186 + // we represent. If we tried to just pass the digits off to parseLong,
32.187 + // we'd get a parse failure.
32.188 + if (isLongMIN_VALUE()) {
32.189 + return Long.MIN_VALUE;
32.190 + }
32.191 +
32.192 + StringBuffer temp = getStringBuffer();
32.193 + temp.append(digits, 0, count);
32.194 + for (int i = count; i < decimalAt; ++i) {
32.195 + temp.append('0');
32.196 + }
32.197 + return Long.parseLong(temp.toString());
32.198 + }
32.199 +
32.200 + public final BigDecimal getBigDecimal() {
32.201 + if (count == 0) {
32.202 + if (decimalAt == 0) {
32.203 + return BigDecimal.ZERO;
32.204 + } else {
32.205 + return new BigDecimal("0E" + decimalAt);
32.206 + }
32.207 + }
32.208 +
32.209 + if (decimalAt == count) {
32.210 + return new BigDecimal(digits, 0, count);
32.211 + } else {
32.212 + return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
32.213 + }
32.214 + }
32.215 +
32.216 + /**
32.217 + * Return true if the number represented by this object can fit into
32.218 + * a long.
32.219 + * @param isPositive true if this number should be regarded as positive
32.220 + * @param ignoreNegativeZero true if -0 should be regarded as identical to
32.221 + * +0; otherwise they are considered distinct
32.222 + * @return true if this number fits into a Java long
32.223 + */
32.224 + boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
32.225 + // Figure out if the result will fit in a long. We have to
32.226 + // first look for nonzero digits after the decimal point;
32.227 + // then check the size. If the digit count is 18 or less, then
32.228 + // the value can definitely be represented as a long. If it is 19
32.229 + // then it may be too large.
32.230 +
32.231 + // Trim trailing zeros. This does not change the represented value.
32.232 + while (count > 0 && digits[count - 1] == '0') {
32.233 + --count;
32.234 + }
32.235 +
32.236 + if (count == 0) {
32.237 + // Positive zero fits into a long, but negative zero can only
32.238 + // be represented as a double. - bug 4162852
32.239 + return isPositive || ignoreNegativeZero;
32.240 + }
32.241 +
32.242 + if (decimalAt < count || decimalAt > MAX_COUNT) {
32.243 + return false;
32.244 + }
32.245 +
32.246 + if (decimalAt < MAX_COUNT) return true;
32.247 +
32.248 + // At this point we have decimalAt == count, and count == MAX_COUNT.
32.249 + // The number will overflow if it is larger than 9223372036854775807
32.250 + // or smaller than -9223372036854775808.
32.251 + for (int i=0; i<count; ++i) {
32.252 + char dig = digits[i], max = LONG_MIN_REP[i];
32.253 + if (dig > max) return false;
32.254 + if (dig < max) return true;
32.255 + }
32.256 +
32.257 + // At this point the first count digits match. If decimalAt is less
32.258 + // than count, then the remaining digits are zero, and we return true.
32.259 + if (count < decimalAt) return true;
32.260 +
32.261 + // Now we have a representation of Long.MIN_VALUE, without the leading
32.262 + // negative sign. If this represents a positive value, then it does
32.263 + // not fit; otherwise it fits.
32.264 + return !isPositive;
32.265 + }
32.266 +
32.267 + /**
32.268 + * Set the digit list to a representation of the given double value.
32.269 + * This method supports fixed-point notation.
32.270 + * @param isNegative Boolean value indicating whether the number is negative.
32.271 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
32.272 + * or a value <= 0.
32.273 + * @param maximumFractionDigits The most fractional digits which should
32.274 + * be converted.
32.275 + */
32.276 + public final void set(boolean isNegative, double source, int maximumFractionDigits) {
32.277 + set(isNegative, source, maximumFractionDigits, true);
32.278 + }
32.279 +
32.280 + /**
32.281 + * Set the digit list to a representation of the given double value.
32.282 + * This method supports both fixed-point and exponential notation.
32.283 + * @param isNegative Boolean value indicating whether the number is negative.
32.284 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
32.285 + * or a value <= 0.
32.286 + * @param maximumDigits The most fractional or total digits which should
32.287 + * be converted.
32.288 + * @param fixedPoint If true, then maximumDigits is the maximum
32.289 + * fractional digits to be converted. If false, total digits.
32.290 + */
32.291 + final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
32.292 + set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
32.293 + }
32.294 +
32.295 + /**
32.296 + * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
32.297 + * DDDDDE+/-DDDDD.
32.298 + */
32.299 + final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
32.300 + this.isNegative = isNegative;
32.301 + int len = s.length();
32.302 + char[] source = getDataChars(len);
32.303 + s.getChars(0, len, source, 0);
32.304 +
32.305 + decimalAt = -1;
32.306 + count = 0;
32.307 + int exponent = 0;
32.308 + // Number of zeros between decimal point and first non-zero digit after
32.309 + // decimal point, for numbers < 1.
32.310 + int leadingZerosAfterDecimal = 0;
32.311 + boolean nonZeroDigitSeen = false;
32.312 +
32.313 + for (int i = 0; i < len; ) {
32.314 + char c = source[i++];
32.315 + if (c == '.') {
32.316 + decimalAt = count;
32.317 + } else if (c == 'e' || c == 'E') {
32.318 + exponent = parseInt(source, i, len);
32.319 + break;
32.320 + } else {
32.321 + if (!nonZeroDigitSeen) {
32.322 + nonZeroDigitSeen = (c != '0');
32.323 + if (!nonZeroDigitSeen && decimalAt != -1)
32.324 + ++leadingZerosAfterDecimal;
32.325 + }
32.326 + if (nonZeroDigitSeen) {
32.327 + digits[count++] = c;
32.328 + }
32.329 + }
32.330 + }
32.331 + if (decimalAt == -1) {
32.332 + decimalAt = count;
32.333 + }
32.334 + if (nonZeroDigitSeen) {
32.335 + decimalAt += exponent - leadingZerosAfterDecimal;
32.336 + }
32.337 +
32.338 + if (fixedPoint) {
32.339 + // The negative of the exponent represents the number of leading
32.340 + // zeros between the decimal and the first non-zero digit, for
32.341 + // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
32.342 + // is more than the maximum fraction digits, then we have an underflow
32.343 + // for the printed representation.
32.344 + if (-decimalAt > maximumDigits) {
32.345 + // Handle an underflow to zero when we round something like
32.346 + // 0.0009 to 2 fractional digits.
32.347 + count = 0;
32.348 + return;
32.349 + } else if (-decimalAt == maximumDigits) {
32.350 + // If we round 0.0009 to 3 fractional digits, then we have to
32.351 + // create a new one digit in the least significant location.
32.352 + if (shouldRoundUp(0)) {
32.353 + count = 1;
32.354 + ++decimalAt;
32.355 + digits[0] = '1';
32.356 + } else {
32.357 + count = 0;
32.358 + }
32.359 + return;
32.360 + }
32.361 + // else fall through
32.362 + }
32.363 +
32.364 + // Eliminate trailing zeros.
32.365 + while (count > 1 && digits[count - 1] == '0') {
32.366 + --count;
32.367 + }
32.368 +
32.369 + // Eliminate digits beyond maximum digits to be displayed.
32.370 + // Round up if appropriate.
32.371 + round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
32.372 + }
32.373 +
32.374 + /**
32.375 + * Round the representation to the given number of digits.
32.376 + * @param maximumDigits The maximum number of digits to be shown.
32.377 + * Upon return, count will be less than or equal to maximumDigits.
32.378 + */
32.379 + private final void round(int maximumDigits) {
32.380 + // Eliminate digits beyond maximum digits to be displayed.
32.381 + // Round up if appropriate.
32.382 + if (maximumDigits >= 0 && maximumDigits < count) {
32.383 + if (shouldRoundUp(maximumDigits)) {
32.384 + // Rounding up involved incrementing digits from LSD to MSD.
32.385 + // In most cases this is simple, but in a worst case situation
32.386 + // (9999..99) we have to adjust the decimalAt value.
32.387 + for (;;) {
32.388 + --maximumDigits;
32.389 + if (maximumDigits < 0) {
32.390 + // We have all 9's, so we increment to a single digit
32.391 + // of one and adjust the exponent.
32.392 + digits[0] = '1';
32.393 + ++decimalAt;
32.394 + maximumDigits = 0; // Adjust the count
32.395 + break;
32.396 + }
32.397 +
32.398 + ++digits[maximumDigits];
32.399 + if (digits[maximumDigits] <= '9') break;
32.400 + // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
32.401 + }
32.402 + ++maximumDigits; // Increment for use as count
32.403 + }
32.404 + count = maximumDigits;
32.405 +
32.406 + // Eliminate trailing zeros.
32.407 + while (count > 1 && digits[count-1] == '0') {
32.408 + --count;
32.409 + }
32.410 + }
32.411 + }
32.412 +
32.413 +
32.414 + /**
32.415 + * Return true if truncating the representation to the given number
32.416 + * of digits will result in an increment to the last digit. This
32.417 + * method implements the rounding modes defined in the
32.418 + * java.math.RoundingMode class.
32.419 + * [bnf]
32.420 + * @param maximumDigits the number of digits to keep, from 0 to
32.421 + * <code>count-1</code>. If 0, then all digits are rounded away, and
32.422 + * this method returns true if a one should be generated (e.g., formatting
32.423 + * 0.09 with "#.#").
32.424 + * @exception ArithmeticException if rounding is needed with rounding
32.425 + * mode being set to RoundingMode.UNNECESSARY
32.426 + * @return true if digit <code>maximumDigits-1</code> should be
32.427 + * incremented
32.428 + */
32.429 + private boolean shouldRoundUp(int maximumDigits) {
32.430 + if (maximumDigits < count) {
32.431 + switch(roundingMode) {
32.432 + case UP:
32.433 + for (int i=maximumDigits; i<count; ++i) {
32.434 + if (digits[i] != '0') {
32.435 + return true;
32.436 + }
32.437 + }
32.438 + break;
32.439 + case DOWN:
32.440 + break;
32.441 + case CEILING:
32.442 + for (int i=maximumDigits; i<count; ++i) {
32.443 + if (digits[i] != '0') {
32.444 + return !isNegative;
32.445 + }
32.446 + }
32.447 + break;
32.448 + case FLOOR:
32.449 + for (int i=maximumDigits; i<count; ++i) {
32.450 + if (digits[i] != '0') {
32.451 + return isNegative;
32.452 + }
32.453 + }
32.454 + break;
32.455 + case HALF_UP:
32.456 + if (digits[maximumDigits] >= '5') {
32.457 + return true;
32.458 + }
32.459 + break;
32.460 + case HALF_DOWN:
32.461 + if (digits[maximumDigits] > '5') {
32.462 + return true;
32.463 + } else if (digits[maximumDigits] == '5' ) {
32.464 + for (int i=maximumDigits+1; i<count; ++i) {
32.465 + if (digits[i] != '0') {
32.466 + return true;
32.467 + }
32.468 + }
32.469 + }
32.470 + break;
32.471 + case HALF_EVEN:
32.472 + // Implement IEEE half-even rounding
32.473 + if (digits[maximumDigits] > '5') {
32.474 + return true;
32.475 + } else if (digits[maximumDigits] == '5' ) {
32.476 + for (int i=maximumDigits+1; i<count; ++i) {
32.477 + if (digits[i] != '0') {
32.478 + return true;
32.479 + }
32.480 + }
32.481 + return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
32.482 + }
32.483 + break;
32.484 + case UNNECESSARY:
32.485 + for (int i=maximumDigits; i<count; ++i) {
32.486 + if (digits[i] != '0') {
32.487 + throw new ArithmeticException(
32.488 + "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
32.489 + }
32.490 + }
32.491 + break;
32.492 + default:
32.493 + assert false;
32.494 + }
32.495 + }
32.496 + return false;
32.497 + }
32.498 +
32.499 + /**
32.500 + * Utility routine to set the value of the digit list from a long
32.501 + */
32.502 + public final void set(boolean isNegative, long source) {
32.503 + set(isNegative, source, 0);
32.504 + }
32.505 +
32.506 + /**
32.507 + * Set the digit list to a representation of the given long value.
32.508 + * @param isNegative Boolean value indicating whether the number is negative.
32.509 + * @param source Value to be converted; must be >= 0 or ==
32.510 + * Long.MIN_VALUE.
32.511 + * @param maximumDigits The most digits which should be converted.
32.512 + * If maximumDigits is lower than the number of significant digits
32.513 + * in source, the representation will be rounded. Ignored if <= 0.
32.514 + */
32.515 + public final void set(boolean isNegative, long source, int maximumDigits) {
32.516 + this.isNegative = isNegative;
32.517 +
32.518 + // This method does not expect a negative number. However,
32.519 + // "source" can be a Long.MIN_VALUE (-9223372036854775808),
32.520 + // if the number being formatted is a Long.MIN_VALUE. In that
32.521 + // case, it will be formatted as -Long.MIN_VALUE, a number
32.522 + // which is outside the legal range of a long, but which can
32.523 + // be represented by DigitList.
32.524 + if (source <= 0) {
32.525 + if (source == Long.MIN_VALUE) {
32.526 + decimalAt = count = MAX_COUNT;
32.527 + System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
32.528 + } else {
32.529 + decimalAt = count = 0; // Values <= 0 format as zero
32.530 + }
32.531 + } else {
32.532 + // Rewritten to improve performance. I used to call
32.533 + // Long.toString(), which was about 4x slower than this code.
32.534 + int left = MAX_COUNT;
32.535 + int right;
32.536 + while (source > 0) {
32.537 + digits[--left] = (char)('0' + (source % 10));
32.538 + source /= 10;
32.539 + }
32.540 + decimalAt = MAX_COUNT - left;
32.541 + // Don't copy trailing zeros. We are guaranteed that there is at
32.542 + // least one non-zero digit, so we don't have to check lower bounds.
32.543 + for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
32.544 + ;
32.545 + count = right - left + 1;
32.546 + System.arraycopy(digits, left, digits, 0, count);
32.547 + }
32.548 + if (maximumDigits > 0) round(maximumDigits);
32.549 + }
32.550 +
32.551 + /**
32.552 + * Set the digit list to a representation of the given BigDecimal value.
32.553 + * This method supports both fixed-point and exponential notation.
32.554 + * @param isNegative Boolean value indicating whether the number is negative.
32.555 + * @param source Value to be converted; must not be a value <= 0.
32.556 + * @param maximumDigits The most fractional or total digits which should
32.557 + * be converted.
32.558 + * @param fixedPoint If true, then maximumDigits is the maximum
32.559 + * fractional digits to be converted. If false, total digits.
32.560 + */
32.561 + final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
32.562 + String s = source.toString();
32.563 + extendDigits(s.length());
32.564 +
32.565 + set(isNegative, s, maximumDigits, fixedPoint);
32.566 + }
32.567 +
32.568 + /**
32.569 + * Set the digit list to a representation of the given BigInteger value.
32.570 + * @param isNegative Boolean value indicating whether the number is negative.
32.571 + * @param source Value to be converted; must be >= 0.
32.572 + * @param maximumDigits The most digits which should be converted.
32.573 + * If maximumDigits is lower than the number of significant digits
32.574 + * in source, the representation will be rounded. Ignored if <= 0.
32.575 + */
32.576 + final void set(boolean isNegative, BigInteger source, int maximumDigits) {
32.577 + this.isNegative = isNegative;
32.578 + String s = source.toString();
32.579 + int len = s.length();
32.580 + extendDigits(len);
32.581 + s.getChars(0, len, digits, 0);
32.582 +
32.583 + decimalAt = len;
32.584 + int right;
32.585 + for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
32.586 + ;
32.587 + count = right + 1;
32.588 +
32.589 + if (maximumDigits > 0) {
32.590 + round(maximumDigits);
32.591 + }
32.592 + }
32.593 +
32.594 + /**
32.595 + * equality test between two digit lists.
32.596 + */
32.597 + public boolean equals(Object obj) {
32.598 + if (this == obj) // quick check
32.599 + return true;
32.600 + if (!(obj instanceof DigitList)) // (1) same object?
32.601 + return false;
32.602 + DigitList other = (DigitList) obj;
32.603 + if (count != other.count ||
32.604 + decimalAt != other.decimalAt)
32.605 + return false;
32.606 + for (int i = 0; i < count; i++)
32.607 + if (digits[i] != other.digits[i])
32.608 + return false;
32.609 + return true;
32.610 + }
32.611 +
32.612 + /**
32.613 + * Generates the hash code for the digit list.
32.614 + */
32.615 + public int hashCode() {
32.616 + int hashcode = decimalAt;
32.617 +
32.618 + for (int i = 0; i < count; i++) {
32.619 + hashcode = hashcode * 37 + digits[i];
32.620 + }
32.621 +
32.622 + return hashcode;
32.623 + }
32.624 +
32.625 + /**
32.626 + * Creates a copy of this object.
32.627 + * @return a clone of this instance.
32.628 + */
32.629 + public Object clone() {
32.630 + try {
32.631 + DigitList other = (DigitList) super.clone();
32.632 + char[] newDigits = new char[digits.length];
32.633 + System.arraycopy(digits, 0, newDigits, 0, digits.length);
32.634 + other.digits = newDigits;
32.635 + other.tempBuffer = null;
32.636 + return other;
32.637 + } catch (CloneNotSupportedException e) {
32.638 + throw new InternalError();
32.639 + }
32.640 + }
32.641 +
32.642 + /**
32.643 + * Returns true if this DigitList represents Long.MIN_VALUE;
32.644 + * false, otherwise. This is required so that getLong() works.
32.645 + */
32.646 + private boolean isLongMIN_VALUE() {
32.647 + if (decimalAt != count || count != MAX_COUNT) {
32.648 + return false;
32.649 + }
32.650 +
32.651 + for (int i = 0; i < count; ++i) {
32.652 + if (digits[i] != LONG_MIN_REP[i]) return false;
32.653 + }
32.654 +
32.655 + return true;
32.656 + }
32.657 +
32.658 + private static final int parseInt(char[] str, int offset, int strLen) {
32.659 + char c;
32.660 + boolean positive = true;
32.661 + if ((c = str[offset]) == '-') {
32.662 + positive = false;
32.663 + offset++;
32.664 + } else if (c == '+') {
32.665 + offset++;
32.666 + }
32.667 +
32.668 + int value = 0;
32.669 + while (offset < strLen) {
32.670 + c = str[offset++];
32.671 + if (c >= '0' && c <= '9') {
32.672 + value = value * 10 + (c - '0');
32.673 + } else {
32.674 + break;
32.675 + }
32.676 + }
32.677 + return positive ? value : -value;
32.678 + }
32.679 +
32.680 + // The digit part of -9223372036854775808L
32.681 + private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
32.682 +
32.683 + public String toString() {
32.684 + if (isZero()) {
32.685 + return "0";
32.686 + }
32.687 + StringBuffer buf = getStringBuffer();
32.688 + buf.append("0.");
32.689 + buf.append(digits, 0, count);
32.690 + buf.append("x10^");
32.691 + buf.append(decimalAt);
32.692 + return buf.toString();
32.693 + }
32.694 +
32.695 + private StringBuffer tempBuffer;
32.696 +
32.697 + private StringBuffer getStringBuffer() {
32.698 + if (tempBuffer == null) {
32.699 + tempBuffer = new StringBuffer(MAX_COUNT);
32.700 + } else {
32.701 + tempBuffer.setLength(0);
32.702 + }
32.703 + return tempBuffer;
32.704 + }
32.705 +
32.706 + private void extendDigits(int len) {
32.707 + if (len > digits.length) {
32.708 + digits = new char[len];
32.709 + }
32.710 + }
32.711 +
32.712 + private final char[] getDataChars(int length) {
32.713 + if (data == null || data.length < length) {
32.714 + data = new char[length];
32.715 + }
32.716 + return data;
32.717 + }
32.718 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/rt/emul/compact/src/main/java/java/text/DontCareFieldPosition.java Thu Oct 03 15:43:10 2013 +0200
33.3 @@ -0,0 +1,53 @@
33.4 +/*
33.5 + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33.7 + *
33.8 + * This code is free software; you can redistribute it and/or modify it
33.9 + * under the terms of the GNU General Public License version 2 only, as
33.10 + * published by the Free Software Foundation. Oracle designates this
33.11 + * particular file as subject to the "Classpath" exception as provided
33.12 + * by Oracle in the LICENSE file that accompanied this code.
33.13 + *
33.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
33.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
33.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
33.17 + * version 2 for more details (a copy is included in the LICENSE file that
33.18 + * accompanied this code).
33.19 + *
33.20 + * You should have received a copy of the GNU General Public License version
33.21 + * 2 along with this work; if not, write to the Free Software Foundation,
33.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
33.23 + *
33.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
33.25 + * or visit www.oracle.com if you need additional information or have any
33.26 + * questions.
33.27 + */
33.28 +
33.29 +package java.text;
33.30 +
33.31 +/**
33.32 + * DontCareFieldPosition defines no-op FieldDelegate. Its
33.33 + * singleton is used for the format methods that don't take a
33.34 + * FieldPosition.
33.35 + */
33.36 +class DontCareFieldPosition extends FieldPosition {
33.37 + // The singleton of DontCareFieldPosition.
33.38 + static final FieldPosition INSTANCE = new DontCareFieldPosition();
33.39 +
33.40 + private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
33.41 + public void formatted(Format.Field attr, Object value, int start,
33.42 + int end, StringBuffer buffer) {
33.43 + }
33.44 + public void formatted(int fieldID, Format.Field attr, Object value,
33.45 + int start, int end, StringBuffer buffer) {
33.46 + }
33.47 + };
33.48 +
33.49 + private DontCareFieldPosition() {
33.50 + super(0);
33.51 + }
33.52 +
33.53 + Format.FieldDelegate getFieldDelegate() {
33.54 + return noDelegate;
33.55 + }
33.56 +}
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/rt/emul/compact/src/main/java/java/text/FieldPosition.java Thu Oct 03 15:43:10 2013 +0200
34.3 @@ -0,0 +1,303 @@
34.4 +/*
34.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
34.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
34.7 + *
34.8 + * This code is free software; you can redistribute it and/or modify it
34.9 + * under the terms of the GNU General Public License version 2 only, as
34.10 + * published by the Free Software Foundation. Oracle designates this
34.11 + * particular file as subject to the "Classpath" exception as provided
34.12 + * by Oracle in the LICENSE file that accompanied this code.
34.13 + *
34.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
34.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
34.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
34.17 + * version 2 for more details (a copy is included in the LICENSE file that
34.18 + * accompanied this code).
34.19 + *
34.20 + * You should have received a copy of the GNU General Public License version
34.21 + * 2 along with this work; if not, write to the Free Software Foundation,
34.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
34.23 + *
34.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
34.25 + * or visit www.oracle.com if you need additional information or have any
34.26 + * questions.
34.27 + */
34.28 +
34.29 +/*
34.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
34.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
34.32 + *
34.33 + * The original version of this source code and documentation is copyrighted
34.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
34.35 + * materials are provided under terms of a License Agreement between Taligent
34.36 + * and Sun. This technology is protected by multiple US and International
34.37 + * patents. This notice and attribution to Taligent may not be removed.
34.38 + * Taligent is a registered trademark of Taligent, Inc.
34.39 + *
34.40 + */
34.41 +
34.42 +package java.text;
34.43 +
34.44 +/**
34.45 + * <code>FieldPosition</code> is a simple class used by <code>Format</code>
34.46 + * and its subclasses to identify fields in formatted output. Fields can
34.47 + * be identified in two ways:
34.48 + * <ul>
34.49 + * <li>By an integer constant, whose names typically end with
34.50 + * <code>_FIELD</code>. The constants are defined in the various
34.51 + * subclasses of <code>Format</code>.
34.52 + * <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
34.53 + * and its friends in <code>DateFormat</code> for an example.
34.54 + * </ul>
34.55 + * <p>
34.56 + * <code>FieldPosition</code> keeps track of the position of the
34.57 + * field within the formatted output with two indices: the index
34.58 + * of the first character of the field and the index of the last
34.59 + * character of the field.
34.60 + *
34.61 + * <p>
34.62 + * One version of the <code>format</code> method in the various
34.63 + * <code>Format</code> classes requires a <code>FieldPosition</code>
34.64 + * object as an argument. You use this <code>format</code> method
34.65 + * to perform partial formatting or to get information about the
34.66 + * formatted output (such as the position of a field).
34.67 + *
34.68 + * <p>
34.69 + * If you are interested in the positions of all attributes in the
34.70 + * formatted string use the <code>Format</code> method
34.71 + * <code>formatToCharacterIterator</code>.
34.72 + *
34.73 + * @author Mark Davis
34.74 + * @see java.text.Format
34.75 + */
34.76 +public class FieldPosition {
34.77 +
34.78 + /**
34.79 + * Input: Desired field to determine start and end offsets for.
34.80 + * The meaning depends on the subclass of Format.
34.81 + */
34.82 + int field = 0;
34.83 +
34.84 + /**
34.85 + * Output: End offset of field in text.
34.86 + * If the field does not occur in the text, 0 is returned.
34.87 + */
34.88 + int endIndex = 0;
34.89 +
34.90 + /**
34.91 + * Output: Start offset of field in text.
34.92 + * If the field does not occur in the text, 0 is returned.
34.93 + */
34.94 + int beginIndex = 0;
34.95 +
34.96 + /**
34.97 + * Desired field this FieldPosition is for.
34.98 + */
34.99 + private Format.Field attribute;
34.100 +
34.101 + /**
34.102 + * Creates a FieldPosition object for the given field. Fields are
34.103 + * identified by constants, whose names typically end with _FIELD,
34.104 + * in the various subclasses of Format.
34.105 + *
34.106 + * @see java.text.NumberFormat#INTEGER_FIELD
34.107 + * @see java.text.NumberFormat#FRACTION_FIELD
34.108 + * @see java.text.DateFormat#YEAR_FIELD
34.109 + * @see java.text.DateFormat#MONTH_FIELD
34.110 + */
34.111 + public FieldPosition(int field) {
34.112 + this.field = field;
34.113 + }
34.114 +
34.115 + /**
34.116 + * Creates a FieldPosition object for the given field constant. Fields are
34.117 + * identified by constants defined in the various <code>Format</code>
34.118 + * subclasses. This is equivalent to calling
34.119 + * <code>new FieldPosition(attribute, -1)</code>.
34.120 + *
34.121 + * @param attribute Format.Field constant identifying a field
34.122 + * @since 1.4
34.123 + */
34.124 + public FieldPosition(Format.Field attribute) {
34.125 + this(attribute, -1);
34.126 + }
34.127 +
34.128 + /**
34.129 + * Creates a <code>FieldPosition</code> object for the given field.
34.130 + * The field is identified by an attribute constant from one of the
34.131 + * <code>Field</code> subclasses as well as an integer field ID
34.132 + * defined by the <code>Format</code> subclasses. <code>Format</code>
34.133 + * subclasses that are aware of <code>Field</code> should give precedence
34.134 + * to <code>attribute</code> and ignore <code>fieldID</code> if
34.135 + * <code>attribute</code> is not null. However, older <code>Format</code>
34.136 + * subclasses may not be aware of <code>Field</code> and rely on
34.137 + * <code>fieldID</code>. If the field has no corresponding integer
34.138 + * constant, <code>fieldID</code> should be -1.
34.139 + *
34.140 + * @param attribute Format.Field constant identifying a field
34.141 + * @param fieldID integer constantce identifying a field
34.142 + * @since 1.4
34.143 + */
34.144 + public FieldPosition(Format.Field attribute, int fieldID) {
34.145 + this.attribute = attribute;
34.146 + this.field = fieldID;
34.147 + }
34.148 +
34.149 + /**
34.150 + * Returns the field identifier as an attribute constant
34.151 + * from one of the <code>Field</code> subclasses. May return null if
34.152 + * the field is specified only by an integer field ID.
34.153 + *
34.154 + * @return Identifier for the field
34.155 + * @since 1.4
34.156 + */
34.157 + public Format.Field getFieldAttribute() {
34.158 + return attribute;
34.159 + }
34.160 +
34.161 + /**
34.162 + * Retrieves the field identifier.
34.163 + */
34.164 + public int getField() {
34.165 + return field;
34.166 + }
34.167 +
34.168 + /**
34.169 + * Retrieves the index of the first character in the requested field.
34.170 + */
34.171 + public int getBeginIndex() {
34.172 + return beginIndex;
34.173 + }
34.174 +
34.175 + /**
34.176 + * Retrieves the index of the character following the last character in the
34.177 + * requested field.
34.178 + */
34.179 + public int getEndIndex() {
34.180 + return endIndex;
34.181 + }
34.182 +
34.183 + /**
34.184 + * Sets the begin index. For use by subclasses of Format.
34.185 + * @since 1.2
34.186 + */
34.187 + public void setBeginIndex(int bi) {
34.188 + beginIndex = bi;
34.189 + }
34.190 +
34.191 + /**
34.192 + * Sets the end index. For use by subclasses of Format.
34.193 + * @since 1.2
34.194 + */
34.195 + public void setEndIndex(int ei) {
34.196 + endIndex = ei;
34.197 + }
34.198 +
34.199 + /**
34.200 + * Returns a <code>Format.FieldDelegate</code> instance that is associated
34.201 + * with the FieldPosition. When the delegate is notified of the same
34.202 + * field the FieldPosition is associated with, the begin/end will be
34.203 + * adjusted.
34.204 + */
34.205 + Format.FieldDelegate getFieldDelegate() {
34.206 + return new Delegate();
34.207 + }
34.208 +
34.209 + /**
34.210 + * Overrides equals
34.211 + */
34.212 + public boolean equals(Object obj)
34.213 + {
34.214 + if (obj == null) return false;
34.215 + if (!(obj instanceof FieldPosition))
34.216 + return false;
34.217 + FieldPosition other = (FieldPosition) obj;
34.218 + if (attribute == null) {
34.219 + if (other.attribute != null) {
34.220 + return false;
34.221 + }
34.222 + }
34.223 + else if (!attribute.equals(other.attribute)) {
34.224 + return false;
34.225 + }
34.226 + return (beginIndex == other.beginIndex
34.227 + && endIndex == other.endIndex
34.228 + && field == other.field);
34.229 + }
34.230 +
34.231 + /**
34.232 + * Returns a hash code for this FieldPosition.
34.233 + * @return a hash code value for this object
34.234 + */
34.235 + public int hashCode() {
34.236 + return (field << 24) | (beginIndex << 16) | endIndex;
34.237 + }
34.238 +
34.239 + /**
34.240 + * Return a string representation of this FieldPosition.
34.241 + * @return a string representation of this object
34.242 + */
34.243 + public String toString() {
34.244 + return getClass().getName() +
34.245 + "[field=" + field + ",attribute=" + attribute +
34.246 + ",beginIndex=" + beginIndex +
34.247 + ",endIndex=" + endIndex + ']';
34.248 + }
34.249 +
34.250 +
34.251 + /**
34.252 + * Return true if the receiver wants a <code>Format.Field</code> value and
34.253 + * <code>attribute</code> is equal to it.
34.254 + */
34.255 + private boolean matchesField(Format.Field attribute) {
34.256 + if (this.attribute != null) {
34.257 + return this.attribute.equals(attribute);
34.258 + }
34.259 + return false;
34.260 + }
34.261 +
34.262 + /**
34.263 + * Return true if the receiver wants a <code>Format.Field</code> value and
34.264 + * <code>attribute</code> is equal to it, or true if the receiver
34.265 + * represents an inteter constant and <code>field</code> equals it.
34.266 + */
34.267 + private boolean matchesField(Format.Field attribute, int field) {
34.268 + if (this.attribute != null) {
34.269 + return this.attribute.equals(attribute);
34.270 + }
34.271 + return (field == this.field);
34.272 + }
34.273 +
34.274 +
34.275 + /**
34.276 + * An implementation of FieldDelegate that will adjust the begin/end
34.277 + * of the FieldPosition if the arguments match the field of
34.278 + * the FieldPosition.
34.279 + */
34.280 + private class Delegate implements Format.FieldDelegate {
34.281 + /**
34.282 + * Indicates whether the field has been encountered before. If this
34.283 + * is true, and <code>formatted</code> is invoked, the begin/end
34.284 + * are not updated.
34.285 + */
34.286 + private boolean encounteredField;
34.287 +
34.288 + public void formatted(Format.Field attr, Object value, int start,
34.289 + int end, StringBuffer buffer) {
34.290 + if (!encounteredField && matchesField(attr)) {
34.291 + setBeginIndex(start);
34.292 + setEndIndex(end);
34.293 + encounteredField = (start != end);
34.294 + }
34.295 + }
34.296 +
34.297 + public void formatted(int fieldID, Format.Field attr, Object value,
34.298 + int start, int end, StringBuffer buffer) {
34.299 + if (!encounteredField && matchesField(attr, fieldID)) {
34.300 + setBeginIndex(start);
34.301 + setEndIndex(end);
34.302 + encounteredField = (start != end);
34.303 + }
34.304 + }
34.305 + }
34.306 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/rt/emul/compact/src/main/java/java/text/Format.java Thu Oct 03 15:43:10 2013 +0200
35.3 @@ -0,0 +1,406 @@
35.4 +/*
35.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
35.7 + *
35.8 + * This code is free software; you can redistribute it and/or modify it
35.9 + * under the terms of the GNU General Public License version 2 only, as
35.10 + * published by the Free Software Foundation. Oracle designates this
35.11 + * particular file as subject to the "Classpath" exception as provided
35.12 + * by Oracle in the LICENSE file that accompanied this code.
35.13 + *
35.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
35.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
35.17 + * version 2 for more details (a copy is included in the LICENSE file that
35.18 + * accompanied this code).
35.19 + *
35.20 + * You should have received a copy of the GNU General Public License version
35.21 + * 2 along with this work; if not, write to the Free Software Foundation,
35.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
35.23 + *
35.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
35.25 + * or visit www.oracle.com if you need additional information or have any
35.26 + * questions.
35.27 + */
35.28 +
35.29 +/*
35.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
35.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
35.32 + *
35.33 + * The original version of this source code and documentation is copyrighted
35.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
35.35 + * materials are provided under terms of a License Agreement between Taligent
35.36 + * and Sun. This technology is protected by multiple US and International
35.37 + * patents. This notice and attribution to Taligent may not be removed.
35.38 + * Taligent is a registered trademark of Taligent, Inc.
35.39 + *
35.40 + */
35.41 +
35.42 +package java.text;
35.43 +
35.44 +import java.io.Serializable;
35.45 +
35.46 +/**
35.47 + * <code>Format</code> is an abstract base class for formatting locale-sensitive
35.48 + * information such as dates, messages, and numbers.
35.49 + *
35.50 + * <p>
35.51 + * <code>Format</code> defines the programming interface for formatting
35.52 + * locale-sensitive objects into <code>String</code>s (the
35.53 + * <code>format</code> method) and for parsing <code>String</code>s back
35.54 + * into objects (the <code>parseObject</code> method).
35.55 + *
35.56 + * <p>
35.57 + * Generally, a format's <code>parseObject</code> method must be able to parse
35.58 + * any string formatted by its <code>format</code> method. However, there may
35.59 + * be exceptional cases where this is not possible. For example, a
35.60 + * <code>format</code> method might create two adjacent integer numbers with
35.61 + * no separator in between, and in this case the <code>parseObject</code> could
35.62 + * not tell which digits belong to which number.
35.63 + *
35.64 + * <h4>Subclassing</h4>
35.65 + *
35.66 + * <p>
35.67 + * The Java Platform provides three specialized subclasses of <code>Format</code>--
35.68 + * <code>DateFormat</code>, <code>MessageFormat</code>, and
35.69 + * <code>NumberFormat</code>--for formatting dates, messages, and numbers,
35.70 + * respectively.
35.71 + * <p>
35.72 + * Concrete subclasses must implement three methods:
35.73 + * <ol>
35.74 + * <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
35.75 + * <li> <code>formatToCharacterIterator(Object obj)</code>
35.76 + * <li> <code>parseObject(String source, ParsePosition pos)</code>
35.77 + * </ol>
35.78 + * These general methods allow polymorphic parsing and formatting of objects
35.79 + * and are used, for example, by <code>MessageFormat</code>.
35.80 + * Subclasses often also provide additional <code>format</code> methods for
35.81 + * specific input types as well as <code>parse</code> methods for specific
35.82 + * result types. Any <code>parse</code> method that does not take a
35.83 + * <code>ParsePosition</code> argument should throw <code>ParseException</code>
35.84 + * when no text in the required format is at the beginning of the input text.
35.85 + *
35.86 + * <p>
35.87 + * Most subclasses will also implement the following factory methods:
35.88 + * <ol>
35.89 + * <li>
35.90 + * <code>getInstance</code> for getting a useful format object appropriate
35.91 + * for the current locale
35.92 + * <li>
35.93 + * <code>getInstance(Locale)</code> for getting a useful format
35.94 + * object appropriate for the specified locale
35.95 + * </ol>
35.96 + * In addition, some subclasses may also implement other
35.97 + * <code>getXxxxInstance</code> methods for more specialized control. For
35.98 + * example, the <code>NumberFormat</code> class provides
35.99 + * <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
35.100 + * methods for getting specialized number formatters.
35.101 + *
35.102 + * <p>
35.103 + * Subclasses of <code>Format</code> that allow programmers to create objects
35.104 + * for locales (with <code>getInstance(Locale)</code> for example)
35.105 + * must also implement the following class method:
35.106 + * <blockquote>
35.107 + * <pre>
35.108 + * public static Locale[] getAvailableLocales()
35.109 + * </pre>
35.110 + * </blockquote>
35.111 + *
35.112 + * <p>
35.113 + * And finally subclasses may define a set of constants to identify the various
35.114 + * fields in the formatted output. These constants are used to create a FieldPosition
35.115 + * object which identifies what information is contained in the field and its
35.116 + * position in the formatted result. These constants should be named
35.117 + * <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
35.118 + * the field. For examples of these constants, see <code>ERA_FIELD</code> and its
35.119 + * friends in {@link DateFormat}.
35.120 + *
35.121 + * <h4><a name="synchronization">Synchronization</a></h4>
35.122 + *
35.123 + * <p>
35.124 + * Formats are generally not synchronized.
35.125 + * It is recommended to create separate format instances for each thread.
35.126 + * If multiple threads access a format concurrently, it must be synchronized
35.127 + * externally.
35.128 + *
35.129 + * @see java.text.ParsePosition
35.130 + * @see java.text.FieldPosition
35.131 + * @see java.text.NumberFormat
35.132 + * @see java.text.DateFormat
35.133 + * @see java.text.MessageFormat
35.134 + * @author Mark Davis
35.135 + */
35.136 +public abstract class Format implements Serializable, Cloneable {
35.137 +
35.138 + private static final long serialVersionUID = -299282585814624189L;
35.139 +
35.140 + /**
35.141 + * Sole constructor. (For invocation by subclass constructors, typically
35.142 + * implicit.)
35.143 + */
35.144 + protected Format() {
35.145 + }
35.146 +
35.147 + /**
35.148 + * Formats an object to produce a string. This is equivalent to
35.149 + * <blockquote>
35.150 + * {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
35.151 + * new StringBuffer(), new FieldPosition(0)).toString();</code>
35.152 + * </blockquote>
35.153 + *
35.154 + * @param obj The object to format
35.155 + * @return Formatted string.
35.156 + * @exception IllegalArgumentException if the Format cannot format the given
35.157 + * object
35.158 + */
35.159 + public final String format (Object obj) {
35.160 + return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
35.161 + }
35.162 +
35.163 + /**
35.164 + * Formats an object and appends the resulting text to a given string
35.165 + * buffer.
35.166 + * If the <code>pos</code> argument identifies a field used by the format,
35.167 + * then its indices are set to the beginning and end of the first such
35.168 + * field encountered.
35.169 + *
35.170 + * @param obj The object to format
35.171 + * @param toAppendTo where the text is to be appended
35.172 + * @param pos A <code>FieldPosition</code> identifying a field
35.173 + * in the formatted text
35.174 + * @return the string buffer passed in as <code>toAppendTo</code>,
35.175 + * with formatted text appended
35.176 + * @exception NullPointerException if <code>toAppendTo</code> or
35.177 + * <code>pos</code> is null
35.178 + * @exception IllegalArgumentException if the Format cannot format the given
35.179 + * object
35.180 + */
35.181 + public abstract StringBuffer format(Object obj,
35.182 + StringBuffer toAppendTo,
35.183 + FieldPosition pos);
35.184 +
35.185 + /**
35.186 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
35.187 + * You can use the returned <code>AttributedCharacterIterator</code>
35.188 + * to build the resulting String, as well as to determine information
35.189 + * about the resulting String.
35.190 + * <p>
35.191 + * Each attribute key of the AttributedCharacterIterator will be of type
35.192 + * <code>Field</code>. It is up to each <code>Format</code> implementation
35.193 + * to define what the legal values are for each attribute in the
35.194 + * <code>AttributedCharacterIterator</code>, but typically the attribute
35.195 + * key is also used as the attribute value.
35.196 + * <p>The default implementation creates an
35.197 + * <code>AttributedCharacterIterator</code> with no attributes. Subclasses
35.198 + * that support fields should override this and create an
35.199 + * <code>AttributedCharacterIterator</code> with meaningful attributes.
35.200 + *
35.201 + * @exception NullPointerException if obj is null.
35.202 + * @exception IllegalArgumentException when the Format cannot format the
35.203 + * given object.
35.204 + * @param obj The object to format
35.205 + * @return AttributedCharacterIterator describing the formatted value.
35.206 + * @since 1.4
35.207 + */
35.208 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
35.209 + return createAttributedCharacterIterator(format(obj));
35.210 + }
35.211 +
35.212 + /**
35.213 + * Parses text from a string to produce an object.
35.214 + * <p>
35.215 + * The method attempts to parse text starting at the index given by
35.216 + * <code>pos</code>.
35.217 + * If parsing succeeds, then the index of <code>pos</code> is updated
35.218 + * to the index after the last character used (parsing does not necessarily
35.219 + * use all characters up to the end of the string), and the parsed
35.220 + * object is returned. The updated <code>pos</code> can be used to
35.221 + * indicate the starting point for the next call to this method.
35.222 + * If an error occurs, then the index of <code>pos</code> is not
35.223 + * changed, the error index of <code>pos</code> is set to the index of
35.224 + * the character where the error occurred, and null is returned.
35.225 + *
35.226 + * @param source A <code>String</code>, part of which should be parsed.
35.227 + * @param pos A <code>ParsePosition</code> object with index and error
35.228 + * index information as described above.
35.229 + * @return An <code>Object</code> parsed from the string. In case of
35.230 + * error, returns null.
35.231 + * @exception NullPointerException if <code>pos</code> is null.
35.232 + */
35.233 + public abstract Object parseObject (String source, ParsePosition pos);
35.234 +
35.235 + /**
35.236 + * Parses text from the beginning of the given string to produce an object.
35.237 + * The method may not use the entire text of the given string.
35.238 + *
35.239 + * @param source A <code>String</code> whose beginning should be parsed.
35.240 + * @return An <code>Object</code> parsed from the string.
35.241 + * @exception ParseException if the beginning of the specified string
35.242 + * cannot be parsed.
35.243 + */
35.244 + public Object parseObject(String source) throws ParseException {
35.245 + ParsePosition pos = new ParsePosition(0);
35.246 + Object result = parseObject(source, pos);
35.247 + if (pos.index == 0) {
35.248 + throw new ParseException("Format.parseObject(String) failed",
35.249 + pos.errorIndex);
35.250 + }
35.251 + return result;
35.252 + }
35.253 +
35.254 + /**
35.255 + * Creates and returns a copy of this object.
35.256 + *
35.257 + * @return a clone of this instance.
35.258 + */
35.259 + public Object clone() {
35.260 + try {
35.261 + return super.clone();
35.262 + } catch (CloneNotSupportedException e) {
35.263 + // will never happen
35.264 + return null;
35.265 + }
35.266 + }
35.267 +
35.268 + //
35.269 + // Convenience methods for creating AttributedCharacterIterators from
35.270 + // different parameters.
35.271 + //
35.272 +
35.273 + /**
35.274 + * Creates an <code>AttributedCharacterIterator</code> for the String
35.275 + * <code>s</code>.
35.276 + *
35.277 + * @param s String to create AttributedCharacterIterator from
35.278 + * @return AttributedCharacterIterator wrapping s
35.279 + */
35.280 + AttributedCharacterIterator createAttributedCharacterIterator(String s) {
35.281 + AttributedString as = new AttributedString(s);
35.282 +
35.283 + return as.getIterator();
35.284 + }
35.285 +
35.286 + /**
35.287 + * Creates an <code>AttributedCharacterIterator</code> containg the
35.288 + * concatenated contents of the passed in
35.289 + * <code>AttributedCharacterIterator</code>s.
35.290 + *
35.291 + * @param iterators AttributedCharacterIterators used to create resulting
35.292 + * AttributedCharacterIterators
35.293 + * @return AttributedCharacterIterator wrapping passed in
35.294 + * AttributedCharacterIterators
35.295 + */
35.296 + AttributedCharacterIterator createAttributedCharacterIterator(
35.297 + AttributedCharacterIterator[] iterators) {
35.298 + AttributedString as = new AttributedString(iterators);
35.299 +
35.300 + return as.getIterator();
35.301 + }
35.302 +
35.303 + /**
35.304 + * Returns an AttributedCharacterIterator with the String
35.305 + * <code>string</code> and additional key/value pair <code>key</code>,
35.306 + * <code>value</code>.
35.307 + *
35.308 + * @param string String to create AttributedCharacterIterator from
35.309 + * @param key Key for AttributedCharacterIterator
35.310 + * @param value Value associated with key in AttributedCharacterIterator
35.311 + * @return AttributedCharacterIterator wrapping args
35.312 + */
35.313 + AttributedCharacterIterator createAttributedCharacterIterator(
35.314 + String string, AttributedCharacterIterator.Attribute key,
35.315 + Object value) {
35.316 + AttributedString as = new AttributedString(string);
35.317 +
35.318 + as.addAttribute(key, value);
35.319 + return as.getIterator();
35.320 + }
35.321 +
35.322 + /**
35.323 + * Creates an AttributedCharacterIterator with the contents of
35.324 + * <code>iterator</code> and the additional attribute <code>key</code>
35.325 + * <code>value</code>.
35.326 + *
35.327 + * @param iterator Initial AttributedCharacterIterator to add arg to
35.328 + * @param key Key for AttributedCharacterIterator
35.329 + * @param value Value associated with key in AttributedCharacterIterator
35.330 + * @return AttributedCharacterIterator wrapping args
35.331 + */
35.332 + AttributedCharacterIterator createAttributedCharacterIterator(
35.333 + AttributedCharacterIterator iterator,
35.334 + AttributedCharacterIterator.Attribute key, Object value) {
35.335 + AttributedString as = new AttributedString(iterator);
35.336 +
35.337 + as.addAttribute(key, value);
35.338 + return as.getIterator();
35.339 + }
35.340 +
35.341 +
35.342 + /**
35.343 + * Defines constants that are used as attribute keys in the
35.344 + * <code>AttributedCharacterIterator</code> returned
35.345 + * from <code>Format.formatToCharacterIterator</code> and as
35.346 + * field identifiers in <code>FieldPosition</code>.
35.347 + *
35.348 + * @since 1.4
35.349 + */
35.350 + public static class Field extends AttributedCharacterIterator.Attribute {
35.351 +
35.352 + // Proclaim serial compatibility with 1.4 FCS
35.353 + private static final long serialVersionUID = 276966692217360283L;
35.354 +
35.355 + /**
35.356 + * Creates a Field with the specified name.
35.357 + *
35.358 + * @param name Name of the attribute
35.359 + */
35.360 + protected Field(String name) {
35.361 + super(name);
35.362 + }
35.363 + }
35.364 +
35.365 +
35.366 + /**
35.367 + * FieldDelegate is notified by the various <code>Format</code>
35.368 + * implementations as they are formatting the Objects. This allows for
35.369 + * storage of the individual sections of the formatted String for
35.370 + * later use, such as in a <code>FieldPosition</code> or for an
35.371 + * <code>AttributedCharacterIterator</code>.
35.372 + * <p>
35.373 + * Delegates should NOT assume that the <code>Format</code> will notify
35.374 + * the delegate of fields in any particular order.
35.375 + *
35.376 + * @see FieldPosition.Delegate
35.377 + * @see CharacterIteratorFieldDelegate
35.378 + */
35.379 + interface FieldDelegate {
35.380 + /**
35.381 + * Notified when a particular region of the String is formatted. This
35.382 + * method will be invoked if there is no corresponding integer field id
35.383 + * matching <code>attr</code>.
35.384 + *
35.385 + * @param attr Identifies the field matched
35.386 + * @param value Value associated with the field
35.387 + * @param start Beginning location of the field, will be >= 0
35.388 + * @param end End of the field, will be >= start and <= buffer.length()
35.389 + * @param buffer Contains current formatted value, receiver should
35.390 + * NOT modify it.
35.391 + */
35.392 + public void formatted(Format.Field attr, Object value, int start,
35.393 + int end, StringBuffer buffer);
35.394 +
35.395 + /**
35.396 + * Notified when a particular region of the String is formatted.
35.397 + *
35.398 + * @param fieldID Identifies the field by integer
35.399 + * @param attr Identifies the field matched
35.400 + * @param value Value associated with the field
35.401 + * @param start Beginning location of the field, will be >= 0
35.402 + * @param end End of the field, will be >= start and <= buffer.length()
35.403 + * @param buffer Contains current formatted value, receiver should
35.404 + * NOT modify it.
35.405 + */
35.406 + public void formatted(int fieldID, Format.Field attr, Object value,
35.407 + int start, int end, StringBuffer buffer);
35.408 + }
35.409 +}
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/rt/emul/compact/src/main/java/java/text/MessageFormat.java Thu Oct 03 15:43:10 2013 +0200
36.3 @@ -0,0 +1,1594 @@
36.4 +/*
36.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
36.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
36.7 + *
36.8 + * This code is free software; you can redistribute it and/or modify it
36.9 + * under the terms of the GNU General Public License version 2 only, as
36.10 + * published by the Free Software Foundation. Oracle designates this
36.11 + * particular file as subject to the "Classpath" exception as provided
36.12 + * by Oracle in the LICENSE file that accompanied this code.
36.13 + *
36.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
36.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
36.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
36.17 + * version 2 for more details (a copy is included in the LICENSE file that
36.18 + * accompanied this code).
36.19 + *
36.20 + * You should have received a copy of the GNU General Public License version
36.21 + * 2 along with this work; if not, write to the Free Software Foundation,
36.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
36.23 + *
36.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
36.25 + * or visit www.oracle.com if you need additional information or have any
36.26 + * questions.
36.27 + */
36.28 +
36.29 +/*
36.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
36.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
36.32 + *
36.33 + * The original version of this source code and documentation is copyrighted
36.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
36.35 + * materials are provided under terms of a License Agreement between Taligent
36.36 + * and Sun. This technology is protected by multiple US and International
36.37 + * patents. This notice and attribution to Taligent may not be removed.
36.38 + * Taligent is a registered trademark of Taligent, Inc.
36.39 + *
36.40 + */
36.41 +
36.42 +package java.text;
36.43 +
36.44 +import java.io.InvalidObjectException;
36.45 +import java.io.IOException;
36.46 +import java.io.ObjectInputStream;
36.47 +import java.text.DecimalFormat;
36.48 +import java.util.ArrayList;
36.49 +import java.util.Arrays;
36.50 +import java.util.Date;
36.51 +import java.util.List;
36.52 +import java.util.Locale;
36.53 +
36.54 +
36.55 +/**
36.56 + * <code>MessageFormat</code> provides a means to produce concatenated
36.57 + * messages in a language-neutral way. Use this to construct messages
36.58 + * displayed for end users.
36.59 + *
36.60 + * <p>
36.61 + * <code>MessageFormat</code> takes a set of objects, formats them, then
36.62 + * inserts the formatted strings into the pattern at the appropriate places.
36.63 + *
36.64 + * <p>
36.65 + * <strong>Note:</strong>
36.66 + * <code>MessageFormat</code> differs from the other <code>Format</code>
36.67 + * classes in that you create a <code>MessageFormat</code> object with one
36.68 + * of its constructors (not with a <code>getInstance</code> style factory
36.69 + * method). The factory methods aren't necessary because <code>MessageFormat</code>
36.70 + * itself doesn't implement locale specific behavior. Any locale specific
36.71 + * behavior is defined by the pattern that you provide as well as the
36.72 + * subformats used for inserted arguments.
36.73 + *
36.74 + * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
36.75 + *
36.76 + * <code>MessageFormat</code> uses patterns of the following form:
36.77 + * <blockquote><pre>
36.78 + * <i>MessageFormatPattern:</i>
36.79 + * <i>String</i>
36.80 + * <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
36.81 + *
36.82 + * <i>FormatElement:</i>
36.83 + * { <i>ArgumentIndex</i> }
36.84 + * { <i>ArgumentIndex</i> , <i>FormatType</i> }
36.85 + * { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
36.86 + *
36.87 + * <i>FormatType: one of </i>
36.88 + * number date time choice
36.89 + *
36.90 + * <i>FormatStyle:</i>
36.91 + * short
36.92 + * medium
36.93 + * long
36.94 + * full
36.95 + * integer
36.96 + * currency
36.97 + * percent
36.98 + * <i>SubformatPattern</i>
36.99 + * </pre></blockquote>
36.100 + *
36.101 + * <p>Within a <i>String</i>, a pair of single quotes can be used to
36.102 + * quote any arbitrary characters except single quotes. For example,
36.103 + * pattern string <code>"'{0}'"</code> represents string
36.104 + * <code>"{0}"</code>, not a <i>FormatElement</i>. A single quote itself
36.105 + * must be represented by doubled single quotes {@code ''} throughout a
36.106 + * <i>String</i>. For example, pattern string <code>"'{''}'"</code> is
36.107 + * interpreted as a sequence of <code>'{</code> (start of quoting and a
36.108 + * left curly brace), <code>''</code> (a single quote), and
36.109 + * <code>}'</code> (a right curly brace and end of quoting),
36.110 + * <em>not</em> <code>'{'</code> and <code>'}'</code> (quoted left and
36.111 + * right curly braces): representing string <code>"{'}"</code>,
36.112 + * <em>not</em> <code>"{}"</code>.
36.113 + *
36.114 + * <p>A <i>SubformatPattern</i> is interpreted by its corresponding
36.115 + * subformat, and subformat-dependent pattern rules apply. For example,
36.116 + * pattern string <code>"{1,number,<u>$'#',##</u>}"</code>
36.117 + * (<i>SubformatPattern</i> with underline) will produce a number format
36.118 + * with the pound-sign quoted, with a result such as: {@code
36.119 + * "$#31,45"}. Refer to each {@code Format} subclass documentation for
36.120 + * details.
36.121 + *
36.122 + * <p>Any unmatched quote is treated as closed at the end of the given
36.123 + * pattern. For example, pattern string {@code "'{0}"} is treated as
36.124 + * pattern {@code "'{0}'"}.
36.125 + *
36.126 + * <p>Any curly braces within an unquoted pattern must be balanced. For
36.127 + * example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code> are
36.128 + * valid patterns, but <code>"ab {0'}' de"</code>, <code>"ab } de"</code>
36.129 + * and <code>"''{''"</code> are not.
36.130 + *
36.131 + * <p>
36.132 + * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
36.133 + * format patterns unfortunately have shown to be somewhat confusing.
36.134 + * In particular, it isn't always obvious to localizers whether single
36.135 + * quotes need to be doubled or not. Make sure to inform localizers about
36.136 + * the rules, and tell them (for example, by using comments in resource
36.137 + * bundle source files) which strings will be processed by {@code MessageFormat}.
36.138 + * Note that localizers may need to use single quotes in translated
36.139 + * strings where the original version doesn't have them.
36.140 + * </dl>
36.141 + * <p>
36.142 + * The <i>ArgumentIndex</i> value is a non-negative integer written
36.143 + * using the digits {@code '0'} through {@code '9'}, and represents an index into the
36.144 + * {@code arguments} array passed to the {@code format} methods
36.145 + * or the result array returned by the {@code parse} methods.
36.146 + * <p>
36.147 + * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
36.148 + * a {@code Format} instance for the format element. The following
36.149 + * table shows how the values map to {@code Format} instances. Combinations not
36.150 + * shown in the table are illegal. A <i>SubformatPattern</i> must
36.151 + * be a valid pattern string for the {@code Format} subclass used.
36.152 + * <p>
36.153 + * <table border=1 summary="Shows how FormatType and FormatStyle values map to Format instances">
36.154 + * <tr>
36.155 + * <th id="ft" class="TableHeadingColor">FormatType
36.156 + * <th id="fs" class="TableHeadingColor">FormatStyle
36.157 + * <th id="sc" class="TableHeadingColor">Subformat Created
36.158 + * <tr>
36.159 + * <td headers="ft"><i>(none)</i>
36.160 + * <td headers="fs"><i>(none)</i>
36.161 + * <td headers="sc"><code>null</code>
36.162 + * <tr>
36.163 + * <td headers="ft" rowspan=5><code>number</code>
36.164 + * <td headers="fs"><i>(none)</i>
36.165 + * <td headers="sc">{@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())}
36.166 + * <tr>
36.167 + * <td headers="fs"><code>integer</code>
36.168 + * <td headers="sc">{@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())}
36.169 + * <tr>
36.170 + * <td headers="fs"><code>currency</code>
36.171 + * <td headers="sc">{@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())}
36.172 + * <tr>
36.173 + * <td headers="fs"><code>percent</code>
36.174 + * <td headers="sc">{@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())}
36.175 + * <tr>
36.176 + * <td headers="fs"><i>SubformatPattern</i>
36.177 + * <td headers="sc">{@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))}
36.178 + * <tr>
36.179 + * <td headers="ft" rowspan=6><code>date</code>
36.180 + * <td headers="fs"><i>(none)</i>
36.181 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
36.182 + * <tr>
36.183 + * <td headers="fs"><code>short</code>
36.184 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
36.185 + * <tr>
36.186 + * <td headers="fs"><code>medium</code>
36.187 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
36.188 + * <tr>
36.189 + * <td headers="fs"><code>long</code>
36.190 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
36.191 + * <tr>
36.192 + * <td headers="fs"><code>full</code>
36.193 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
36.194 + * <tr>
36.195 + * <td headers="fs"><i>SubformatPattern</i>
36.196 + * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
36.197 + * <tr>
36.198 + * <td headers="ft" rowspan=6><code>time</code>
36.199 + * <td headers="fs"><i>(none)</i>
36.200 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
36.201 + * <tr>
36.202 + * <td headers="fs"><code>short</code>
36.203 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
36.204 + * <tr>
36.205 + * <td headers="fs"><code>medium</code>
36.206 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
36.207 + * <tr>
36.208 + * <td headers="fs"><code>long</code>
36.209 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
36.210 + * <tr>
36.211 + * <td headers="fs"><code>full</code>
36.212 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
36.213 + * <tr>
36.214 + * <td headers="fs"><i>SubformatPattern</i>
36.215 + * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
36.216 + * <tr>
36.217 + * <td headers="ft"><code>choice</code>
36.218 + * <td headers="fs"><i>SubformatPattern</i>
36.219 + * <td headers="sc">{@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)}
36.220 + * </table>
36.221 + * <p>
36.222 + *
36.223 + * <h4>Usage Information</h4>
36.224 + *
36.225 + * <p>
36.226 + * Here are some examples of usage.
36.227 + * In real internationalized programs, the message format pattern and other
36.228 + * static strings will, of course, be obtained from resource bundles.
36.229 + * Other parameters will be dynamically determined at runtime.
36.230 + * <p>
36.231 + * The first example uses the static method <code>MessageFormat.format</code>,
36.232 + * which internally creates a <code>MessageFormat</code> for one-time use:
36.233 + * <blockquote><pre>
36.234 + * int planet = 7;
36.235 + * String event = "a disturbance in the Force";
36.236 + *
36.237 + * String result = MessageFormat.format(
36.238 + * "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
36.239 + * planet, new Date(), event);
36.240 + * </pre></blockquote>
36.241 + * The output is:
36.242 + * <blockquote><pre>
36.243 + * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
36.244 + * </pre></blockquote>
36.245 + *
36.246 + * <p>
36.247 + * The following example creates a <code>MessageFormat</code> instance that
36.248 + * can be used repeatedly:
36.249 + * <blockquote><pre>
36.250 + * int fileCount = 1273;
36.251 + * String diskName = "MyDisk";
36.252 + * Object[] testArgs = {new Long(fileCount), diskName};
36.253 + *
36.254 + * MessageFormat form = new MessageFormat(
36.255 + * "The disk \"{1}\" contains {0} file(s).");
36.256 + *
36.257 + * System.out.println(form.format(testArgs));
36.258 + * </pre></blockquote>
36.259 + * The output with different values for <code>fileCount</code>:
36.260 + * <blockquote><pre>
36.261 + * The disk "MyDisk" contains 0 file(s).
36.262 + * The disk "MyDisk" contains 1 file(s).
36.263 + * The disk "MyDisk" contains 1,273 file(s).
36.264 + * </pre></blockquote>
36.265 + *
36.266 + * <p>
36.267 + * For more sophisticated patterns, you can use a <code>ChoiceFormat</code>
36.268 + * to produce correct forms for singular and plural:
36.269 + * <blockquote><pre>
36.270 + * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
36.271 + * double[] filelimits = {0,1,2};
36.272 + * String[] filepart = {"no files","one file","{0,number} files"};
36.273 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
36.274 + * form.setFormatByArgumentIndex(0, fileform);
36.275 + *
36.276 + * int fileCount = 1273;
36.277 + * String diskName = "MyDisk";
36.278 + * Object[] testArgs = {new Long(fileCount), diskName};
36.279 + *
36.280 + * System.out.println(form.format(testArgs));
36.281 + * </pre></blockquote>
36.282 + * The output with different values for <code>fileCount</code>:
36.283 + * <blockquote><pre>
36.284 + * The disk "MyDisk" contains no files.
36.285 + * The disk "MyDisk" contains one file.
36.286 + * The disk "MyDisk" contains 1,273 files.
36.287 + * </pre></blockquote>
36.288 + *
36.289 + * <p>
36.290 + * You can create the <code>ChoiceFormat</code> programmatically, as in the
36.291 + * above example, or by using a pattern. See {@link ChoiceFormat}
36.292 + * for more information.
36.293 + * <blockquote><pre>
36.294 + * form.applyPattern(
36.295 + * "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");
36.296 + * </pre></blockquote>
36.297 + *
36.298 + * <p>
36.299 + * <strong>Note:</strong> As we see above, the string produced
36.300 + * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated as special;
36.301 + * occurrences of '{' are used to indicate subformats, and cause recursion.
36.302 + * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
36.303 + * programmatically (instead of using the string patterns), then be careful not to
36.304 + * produce a format that recurses on itself, which will cause an infinite loop.
36.305 + * <p>
36.306 + * When a single argument is parsed more than once in the string, the last match
36.307 + * will be the final result of the parsing. For example,
36.308 + * <blockquote><pre>
36.309 + * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
36.310 + * Object[] objs = {new Double(3.1415)};
36.311 + * String result = mf.format( objs );
36.312 + * // result now equals "3.14, 3.1"
36.313 + * objs = null;
36.314 + * objs = mf.parse(result, new ParsePosition(0));
36.315 + * // objs now equals {new Double(3.1)}
36.316 + * </pre></blockquote>
36.317 + *
36.318 + * <p>
36.319 + * Likewise, parsing with a {@code MessageFormat} object using patterns containing
36.320 + * multiple occurrences of the same argument would return the last match. For
36.321 + * example,
36.322 + * <blockquote><pre>
36.323 + * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
36.324 + * String forParsing = "x, y, z";
36.325 + * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
36.326 + * // result now equals {new String("z")}
36.327 + * </pre></blockquote>
36.328 + *
36.329 + * <h4><a name="synchronization">Synchronization</a></h4>
36.330 + *
36.331 + * <p>
36.332 + * Message formats are not synchronized.
36.333 + * It is recommended to create separate format instances for each thread.
36.334 + * If multiple threads access a format concurrently, it must be synchronized
36.335 + * externally.
36.336 + *
36.337 + * @see java.util.Locale
36.338 + * @see Format
36.339 + * @see NumberFormat
36.340 + * @see DecimalFormat
36.341 + * @see DecimalFormatSymbols
36.342 + * @see ChoiceFormat
36.343 + * @see DateFormat
36.344 + * @see SimpleDateFormat
36.345 + *
36.346 + * @author Mark Davis
36.347 + */
36.348 +
36.349 +public class MessageFormat extends Format {
36.350 +
36.351 + private static final long serialVersionUID = 6479157306784022952L;
36.352 +
36.353 + /**
36.354 + * Constructs a MessageFormat for the default locale and the
36.355 + * specified pattern.
36.356 + * The constructor first sets the locale, then parses the pattern and
36.357 + * creates a list of subformats for the format elements contained in it.
36.358 + * Patterns and their interpretation are specified in the
36.359 + * <a href="#patterns">class description</a>.
36.360 + *
36.361 + * @param pattern the pattern for this message format
36.362 + * @exception IllegalArgumentException if the pattern is invalid
36.363 + */
36.364 + public MessageFormat(String pattern) {
36.365 + this.locale = Locale.getDefault(Locale.Category.FORMAT);
36.366 + applyPattern(pattern);
36.367 + }
36.368 +
36.369 + /**
36.370 + * Constructs a MessageFormat for the specified locale and
36.371 + * pattern.
36.372 + * The constructor first sets the locale, then parses the pattern and
36.373 + * creates a list of subformats for the format elements contained in it.
36.374 + * Patterns and their interpretation are specified in the
36.375 + * <a href="#patterns">class description</a>.
36.376 + *
36.377 + * @param pattern the pattern for this message format
36.378 + * @param locale the locale for this message format
36.379 + * @exception IllegalArgumentException if the pattern is invalid
36.380 + * @since 1.4
36.381 + */
36.382 + public MessageFormat(String pattern, Locale locale) {
36.383 + this.locale = locale;
36.384 + applyPattern(pattern);
36.385 + }
36.386 +
36.387 + /**
36.388 + * Sets the locale to be used when creating or comparing subformats.
36.389 + * This affects subsequent calls
36.390 + * <ul>
36.391 + * <li>to the {@link #applyPattern applyPattern}
36.392 + * and {@link #toPattern toPattern} methods if format elements specify
36.393 + * a format type and therefore have the subformats created in the
36.394 + * <code>applyPattern</code> method, as well as
36.395 + * <li>to the <code>format</code> and
36.396 + * {@link #formatToCharacterIterator formatToCharacterIterator} methods
36.397 + * if format elements do not specify a format type and therefore have
36.398 + * the subformats created in the formatting methods.
36.399 + * </ul>
36.400 + * Subformats that have already been created are not affected.
36.401 + *
36.402 + * @param locale the locale to be used when creating or comparing subformats
36.403 + */
36.404 + public void setLocale(Locale locale) {
36.405 + this.locale = locale;
36.406 + }
36.407 +
36.408 + /**
36.409 + * Gets the locale that's used when creating or comparing subformats.
36.410 + *
36.411 + * @return the locale used when creating or comparing subformats
36.412 + */
36.413 + public Locale getLocale() {
36.414 + return locale;
36.415 + }
36.416 +
36.417 +
36.418 + /**
36.419 + * Sets the pattern used by this message format.
36.420 + * The method parses the pattern and creates a list of subformats
36.421 + * for the format elements contained in it.
36.422 + * Patterns and their interpretation are specified in the
36.423 + * <a href="#patterns">class description</a>.
36.424 + *
36.425 + * @param pattern the pattern for this message format
36.426 + * @exception IllegalArgumentException if the pattern is invalid
36.427 + */
36.428 + public void applyPattern(String pattern) {
36.429 + StringBuilder[] segments = new StringBuilder[4];
36.430 + // Allocate only segments[SEG_RAW] here. The rest are
36.431 + // allocated on demand.
36.432 + segments[SEG_RAW] = new StringBuilder();
36.433 +
36.434 + int part = SEG_RAW;
36.435 + int formatNumber = 0;
36.436 + boolean inQuote = false;
36.437 + int braceStack = 0;
36.438 + maxOffset = -1;
36.439 + for (int i = 0; i < pattern.length(); ++i) {
36.440 + char ch = pattern.charAt(i);
36.441 + if (part == SEG_RAW) {
36.442 + if (ch == '\'') {
36.443 + if (i + 1 < pattern.length()
36.444 + && pattern.charAt(i+1) == '\'') {
36.445 + segments[part].append(ch); // handle doubles
36.446 + ++i;
36.447 + } else {
36.448 + inQuote = !inQuote;
36.449 + }
36.450 + } else if (ch == '{' && !inQuote) {
36.451 + part = SEG_INDEX;
36.452 + if (segments[SEG_INDEX] == null) {
36.453 + segments[SEG_INDEX] = new StringBuilder();
36.454 + }
36.455 + } else {
36.456 + segments[part].append(ch);
36.457 + }
36.458 + } else {
36.459 + if (inQuote) { // just copy quotes in parts
36.460 + segments[part].append(ch);
36.461 + if (ch == '\'') {
36.462 + inQuote = false;
36.463 + }
36.464 + } else {
36.465 + switch (ch) {
36.466 + case ',':
36.467 + if (part < SEG_MODIFIER) {
36.468 + if (segments[++part] == null) {
36.469 + segments[part] = new StringBuilder();
36.470 + }
36.471 + } else {
36.472 + segments[part].append(ch);
36.473 + }
36.474 + break;
36.475 + case '{':
36.476 + ++braceStack;
36.477 + segments[part].append(ch);
36.478 + break;
36.479 + case '}':
36.480 + if (braceStack == 0) {
36.481 + part = SEG_RAW;
36.482 + makeFormat(i, formatNumber, segments);
36.483 + formatNumber++;
36.484 + // throw away other segments
36.485 + segments[SEG_INDEX] = null;
36.486 + segments[SEG_TYPE] = null;
36.487 + segments[SEG_MODIFIER] = null;
36.488 + } else {
36.489 + --braceStack;
36.490 + segments[part].append(ch);
36.491 + }
36.492 + break;
36.493 + case ' ':
36.494 + // Skip any leading space chars for SEG_TYPE.
36.495 + if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
36.496 + segments[part].append(ch);
36.497 + }
36.498 + break;
36.499 + case '\'':
36.500 + inQuote = true;
36.501 + // fall through, so we keep quotes in other parts
36.502 + default:
36.503 + segments[part].append(ch);
36.504 + break;
36.505 + }
36.506 + }
36.507 + }
36.508 + }
36.509 + if (braceStack == 0 && part != 0) {
36.510 + maxOffset = -1;
36.511 + throw new IllegalArgumentException("Unmatched braces in the pattern.");
36.512 + }
36.513 + this.pattern = segments[0].toString();
36.514 + }
36.515 +
36.516 +
36.517 + /**
36.518 + * Returns a pattern representing the current state of the message format.
36.519 + * The string is constructed from internal information and therefore
36.520 + * does not necessarily equal the previously applied pattern.
36.521 + *
36.522 + * @return a pattern representing the current state of the message format
36.523 + */
36.524 + public String toPattern() {
36.525 + // later, make this more extensible
36.526 + int lastOffset = 0;
36.527 + StringBuilder result = new StringBuilder();
36.528 + for (int i = 0; i <= maxOffset; ++i) {
36.529 + copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
36.530 + lastOffset = offsets[i];
36.531 + result.append('{').append(argumentNumbers[i]);
36.532 + Format fmt = formats[i];
36.533 + if (fmt == null) {
36.534 + // do nothing, string format
36.535 + } else if (fmt instanceof NumberFormat) {
36.536 + if (fmt.equals(NumberFormat.getInstance(locale))) {
36.537 + result.append(",number");
36.538 + } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
36.539 + result.append(",number,currency");
36.540 + } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
36.541 + result.append(",number,percent");
36.542 + } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
36.543 + result.append(",number,integer");
36.544 + } else {
36.545 + if (fmt instanceof DecimalFormat) {
36.546 + result.append(",number,").append(((DecimalFormat)fmt).toPattern());
36.547 + } else if (fmt instanceof ChoiceFormat) {
36.548 + result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
36.549 + } else {
36.550 + // UNKNOWN
36.551 + }
36.552 + }
36.553 + } else if (fmt instanceof DateFormat) {
36.554 + int index;
36.555 + for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
36.556 + DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
36.557 + locale);
36.558 + if (fmt.equals(df)) {
36.559 + result.append(",date");
36.560 + break;
36.561 + }
36.562 + df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
36.563 + locale);
36.564 + if (fmt.equals(df)) {
36.565 + result.append(",time");
36.566 + break;
36.567 + }
36.568 + }
36.569 + if (index >= DATE_TIME_MODIFIERS.length) {
36.570 + if (fmt instanceof SimpleDateFormat) {
36.571 + result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
36.572 + } else {
36.573 + // UNKNOWN
36.574 + }
36.575 + } else if (index != MODIFIER_DEFAULT) {
36.576 + result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
36.577 + }
36.578 + } else {
36.579 + //result.append(", unknown");
36.580 + }
36.581 + result.append('}');
36.582 + }
36.583 + copyAndFixQuotes(pattern, lastOffset, pattern.length(), result);
36.584 + return result.toString();
36.585 + }
36.586 +
36.587 + /**
36.588 + * Sets the formats to use for the values passed into
36.589 + * <code>format</code> methods or returned from <code>parse</code>
36.590 + * methods. The indices of elements in <code>newFormats</code>
36.591 + * correspond to the argument indices used in the previously set
36.592 + * pattern string.
36.593 + * The order of formats in <code>newFormats</code> thus corresponds to
36.594 + * the order of elements in the <code>arguments</code> array passed
36.595 + * to the <code>format</code> methods or the result array returned
36.596 + * by the <code>parse</code> methods.
36.597 + * <p>
36.598 + * If an argument index is used for more than one format element
36.599 + * in the pattern string, then the corresponding new format is used
36.600 + * for all such format elements. If an argument index is not used
36.601 + * for any format element in the pattern string, then the
36.602 + * corresponding new format is ignored. If fewer formats are provided
36.603 + * than needed, then only the formats for argument indices less
36.604 + * than <code>newFormats.length</code> are replaced.
36.605 + *
36.606 + * @param newFormats the new formats to use
36.607 + * @exception NullPointerException if <code>newFormats</code> is null
36.608 + * @since 1.4
36.609 + */
36.610 + public void setFormatsByArgumentIndex(Format[] newFormats) {
36.611 + for (int i = 0; i <= maxOffset; i++) {
36.612 + int j = argumentNumbers[i];
36.613 + if (j < newFormats.length) {
36.614 + formats[i] = newFormats[j];
36.615 + }
36.616 + }
36.617 + }
36.618 +
36.619 + /**
36.620 + * Sets the formats to use for the format elements in the
36.621 + * previously set pattern string.
36.622 + * The order of formats in <code>newFormats</code> corresponds to
36.623 + * the order of format elements in the pattern string.
36.624 + * <p>
36.625 + * If more formats are provided than needed by the pattern string,
36.626 + * the remaining ones are ignored. If fewer formats are provided
36.627 + * than needed, then only the first <code>newFormats.length</code>
36.628 + * formats are replaced.
36.629 + * <p>
36.630 + * Since the order of format elements in a pattern string often
36.631 + * changes during localization, it is generally better to use the
36.632 + * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
36.633 + * method, which assumes an order of formats corresponding to the
36.634 + * order of elements in the <code>arguments</code> array passed to
36.635 + * the <code>format</code> methods or the result array returned by
36.636 + * the <code>parse</code> methods.
36.637 + *
36.638 + * @param newFormats the new formats to use
36.639 + * @exception NullPointerException if <code>newFormats</code> is null
36.640 + */
36.641 + public void setFormats(Format[] newFormats) {
36.642 + int runsToCopy = newFormats.length;
36.643 + if (runsToCopy > maxOffset + 1) {
36.644 + runsToCopy = maxOffset + 1;
36.645 + }
36.646 + for (int i = 0; i < runsToCopy; i++) {
36.647 + formats[i] = newFormats[i];
36.648 + }
36.649 + }
36.650 +
36.651 + /**
36.652 + * Sets the format to use for the format elements within the
36.653 + * previously set pattern string that use the given argument
36.654 + * index.
36.655 + * The argument index is part of the format element definition and
36.656 + * represents an index into the <code>arguments</code> array passed
36.657 + * to the <code>format</code> methods or the result array returned
36.658 + * by the <code>parse</code> methods.
36.659 + * <p>
36.660 + * If the argument index is used for more than one format element
36.661 + * in the pattern string, then the new format is used for all such
36.662 + * format elements. If the argument index is not used for any format
36.663 + * element in the pattern string, then the new format is ignored.
36.664 + *
36.665 + * @param argumentIndex the argument index for which to use the new format
36.666 + * @param newFormat the new format to use
36.667 + * @since 1.4
36.668 + */
36.669 + public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
36.670 + for (int j = 0; j <= maxOffset; j++) {
36.671 + if (argumentNumbers[j] == argumentIndex) {
36.672 + formats[j] = newFormat;
36.673 + }
36.674 + }
36.675 + }
36.676 +
36.677 + /**
36.678 + * Sets the format to use for the format element with the given
36.679 + * format element index within the previously set pattern string.
36.680 + * The format element index is the zero-based number of the format
36.681 + * element counting from the start of the pattern string.
36.682 + * <p>
36.683 + * Since the order of format elements in a pattern string often
36.684 + * changes during localization, it is generally better to use the
36.685 + * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
36.686 + * method, which accesses format elements based on the argument
36.687 + * index they specify.
36.688 + *
36.689 + * @param formatElementIndex the index of a format element within the pattern
36.690 + * @param newFormat the format to use for the specified format element
36.691 + * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
36.692 + * larger than the number of format elements in the pattern string
36.693 + */
36.694 + public void setFormat(int formatElementIndex, Format newFormat) {
36.695 + formats[formatElementIndex] = newFormat;
36.696 + }
36.697 +
36.698 + /**
36.699 + * Gets the formats used for the values passed into
36.700 + * <code>format</code> methods or returned from <code>parse</code>
36.701 + * methods. The indices of elements in the returned array
36.702 + * correspond to the argument indices used in the previously set
36.703 + * pattern string.
36.704 + * The order of formats in the returned array thus corresponds to
36.705 + * the order of elements in the <code>arguments</code> array passed
36.706 + * to the <code>format</code> methods or the result array returned
36.707 + * by the <code>parse</code> methods.
36.708 + * <p>
36.709 + * If an argument index is used for more than one format element
36.710 + * in the pattern string, then the format used for the last such
36.711 + * format element is returned in the array. If an argument index
36.712 + * is not used for any format element in the pattern string, then
36.713 + * null is returned in the array.
36.714 + *
36.715 + * @return the formats used for the arguments within the pattern
36.716 + * @since 1.4
36.717 + */
36.718 + public Format[] getFormatsByArgumentIndex() {
36.719 + int maximumArgumentNumber = -1;
36.720 + for (int i = 0; i <= maxOffset; i++) {
36.721 + if (argumentNumbers[i] > maximumArgumentNumber) {
36.722 + maximumArgumentNumber = argumentNumbers[i];
36.723 + }
36.724 + }
36.725 + Format[] resultArray = new Format[maximumArgumentNumber + 1];
36.726 + for (int i = 0; i <= maxOffset; i++) {
36.727 + resultArray[argumentNumbers[i]] = formats[i];
36.728 + }
36.729 + return resultArray;
36.730 + }
36.731 +
36.732 + /**
36.733 + * Gets the formats used for the format elements in the
36.734 + * previously set pattern string.
36.735 + * The order of formats in the returned array corresponds to
36.736 + * the order of format elements in the pattern string.
36.737 + * <p>
36.738 + * Since the order of format elements in a pattern string often
36.739 + * changes during localization, it's generally better to use the
36.740 + * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
36.741 + * method, which assumes an order of formats corresponding to the
36.742 + * order of elements in the <code>arguments</code> array passed to
36.743 + * the <code>format</code> methods or the result array returned by
36.744 + * the <code>parse</code> methods.
36.745 + *
36.746 + * @return the formats used for the format elements in the pattern
36.747 + */
36.748 + public Format[] getFormats() {
36.749 + Format[] resultArray = new Format[maxOffset + 1];
36.750 + System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1);
36.751 + return resultArray;
36.752 + }
36.753 +
36.754 + /**
36.755 + * Formats an array of objects and appends the <code>MessageFormat</code>'s
36.756 + * pattern, with format elements replaced by the formatted objects, to the
36.757 + * provided <code>StringBuffer</code>.
36.758 + * <p>
36.759 + * The text substituted for the individual format elements is derived from
36.760 + * the current subformat of the format element and the
36.761 + * <code>arguments</code> element at the format element's argument index
36.762 + * as indicated by the first matching line of the following table. An
36.763 + * argument is <i>unavailable</i> if <code>arguments</code> is
36.764 + * <code>null</code> or has fewer than argumentIndex+1 elements.
36.765 + * <p>
36.766 + * <table border=1 summary="Examples of subformat,argument,and formatted text">
36.767 + * <tr>
36.768 + * <th>Subformat
36.769 + * <th>Argument
36.770 + * <th>Formatted Text
36.771 + * <tr>
36.772 + * <td><i>any</i>
36.773 + * <td><i>unavailable</i>
36.774 + * <td><code>"{" + argumentIndex + "}"</code>
36.775 + * <tr>
36.776 + * <td><i>any</i>
36.777 + * <td><code>null</code>
36.778 + * <td><code>"null"</code>
36.779 + * <tr>
36.780 + * <td><code>instanceof ChoiceFormat</code>
36.781 + * <td><i>any</i>
36.782 + * <td><code>subformat.format(argument).indexOf('{') >= 0 ?<br>
36.783 + * (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
36.784 + * subformat.format(argument)</code>
36.785 + * <tr>
36.786 + * <td><code>!= null</code>
36.787 + * <td><i>any</i>
36.788 + * <td><code>subformat.format(argument)</code>
36.789 + * <tr>
36.790 + * <td><code>null</code>
36.791 + * <td><code>instanceof Number</code>
36.792 + * <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
36.793 + * <tr>
36.794 + * <td><code>null</code>
36.795 + * <td><code>instanceof Date</code>
36.796 + * <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
36.797 + * <tr>
36.798 + * <td><code>null</code>
36.799 + * <td><code>instanceof String</code>
36.800 + * <td><code>argument</code>
36.801 + * <tr>
36.802 + * <td><code>null</code>
36.803 + * <td><i>any</i>
36.804 + * <td><code>argument.toString()</code>
36.805 + * </table>
36.806 + * <p>
36.807 + * If <code>pos</code> is non-null, and refers to
36.808 + * <code>Field.ARGUMENT</code>, the location of the first formatted
36.809 + * string will be returned.
36.810 + *
36.811 + * @param arguments an array of objects to be formatted and substituted.
36.812 + * @param result where text is appended.
36.813 + * @param pos On input: an alignment field, if desired.
36.814 + * On output: the offsets of the alignment field.
36.815 + * @exception IllegalArgumentException if an argument in the
36.816 + * <code>arguments</code> array is not of the type
36.817 + * expected by the format element(s) that use it.
36.818 + */
36.819 + public final StringBuffer format(Object[] arguments, StringBuffer result,
36.820 + FieldPosition pos)
36.821 + {
36.822 + return subformat(arguments, result, pos, null);
36.823 + }
36.824 +
36.825 + /**
36.826 + * Creates a MessageFormat with the given pattern and uses it
36.827 + * to format the given arguments. This is equivalent to
36.828 + * <blockquote>
36.829 + * <code>(new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
36.830 + * </blockquote>
36.831 + *
36.832 + * @exception IllegalArgumentException if the pattern is invalid,
36.833 + * or if an argument in the <code>arguments</code> array
36.834 + * is not of the type expected by the format element(s)
36.835 + * that use it.
36.836 + */
36.837 + public static String format(String pattern, Object ... arguments) {
36.838 + MessageFormat temp = new MessageFormat(pattern);
36.839 + return temp.format(arguments);
36.840 + }
36.841 +
36.842 + // Overrides
36.843 + /**
36.844 + * Formats an array of objects and appends the <code>MessageFormat</code>'s
36.845 + * pattern, with format elements replaced by the formatted objects, to the
36.846 + * provided <code>StringBuffer</code>.
36.847 + * This is equivalent to
36.848 + * <blockquote>
36.849 + * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
36.850 + * </blockquote>
36.851 + *
36.852 + * @param arguments an array of objects to be formatted and substituted.
36.853 + * @param result where text is appended.
36.854 + * @param pos On input: an alignment field, if desired.
36.855 + * On output: the offsets of the alignment field.
36.856 + * @exception IllegalArgumentException if an argument in the
36.857 + * <code>arguments</code> array is not of the type
36.858 + * expected by the format element(s) that use it.
36.859 + */
36.860 + public final StringBuffer format(Object arguments, StringBuffer result,
36.861 + FieldPosition pos)
36.862 + {
36.863 + return subformat((Object[]) arguments, result, pos, null);
36.864 + }
36.865 +
36.866 + /**
36.867 + * Formats an array of objects and inserts them into the
36.868 + * <code>MessageFormat</code>'s pattern, producing an
36.869 + * <code>AttributedCharacterIterator</code>.
36.870 + * You can use the returned <code>AttributedCharacterIterator</code>
36.871 + * to build the resulting String, as well as to determine information
36.872 + * about the resulting String.
36.873 + * <p>
36.874 + * The text of the returned <code>AttributedCharacterIterator</code> is
36.875 + * the same that would be returned by
36.876 + * <blockquote>
36.877 + * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
36.878 + * </blockquote>
36.879 + * <p>
36.880 + * In addition, the <code>AttributedCharacterIterator</code> contains at
36.881 + * least attributes indicating where text was generated from an
36.882 + * argument in the <code>arguments</code> array. The keys of these attributes are of
36.883 + * type <code>MessageFormat.Field</code>, their values are
36.884 + * <code>Integer</code> objects indicating the index in the <code>arguments</code>
36.885 + * array of the argument from which the text was generated.
36.886 + * <p>
36.887 + * The attributes/value from the underlying <code>Format</code>
36.888 + * instances that <code>MessageFormat</code> uses will also be
36.889 + * placed in the resulting <code>AttributedCharacterIterator</code>.
36.890 + * This allows you to not only find where an argument is placed in the
36.891 + * resulting String, but also which fields it contains in turn.
36.892 + *
36.893 + * @param arguments an array of objects to be formatted and substituted.
36.894 + * @return AttributedCharacterIterator describing the formatted value.
36.895 + * @exception NullPointerException if <code>arguments</code> is null.
36.896 + * @exception IllegalArgumentException if an argument in the
36.897 + * <code>arguments</code> array is not of the type
36.898 + * expected by the format element(s) that use it.
36.899 + * @since 1.4
36.900 + */
36.901 + public AttributedCharacterIterator formatToCharacterIterator(Object arguments) {
36.902 + StringBuffer result = new StringBuffer();
36.903 + ArrayList iterators = new ArrayList();
36.904 +
36.905 + if (arguments == null) {
36.906 + throw new NullPointerException(
36.907 + "formatToCharacterIterator must be passed non-null object");
36.908 + }
36.909 + subformat((Object[]) arguments, result, null, iterators);
36.910 + if (iterators.size() == 0) {
36.911 + return createAttributedCharacterIterator("");
36.912 + }
36.913 + return createAttributedCharacterIterator(
36.914 + (AttributedCharacterIterator[])iterators.toArray(
36.915 + new AttributedCharacterIterator[iterators.size()]));
36.916 + }
36.917 +
36.918 + /**
36.919 + * Parses the string.
36.920 + *
36.921 + * <p>Caveats: The parse may fail in a number of circumstances.
36.922 + * For example:
36.923 + * <ul>
36.924 + * <li>If one of the arguments does not occur in the pattern.
36.925 + * <li>If the format of an argument loses information, such as
36.926 + * with a choice format where a large number formats to "many".
36.927 + * <li>Does not yet handle recursion (where
36.928 + * the substituted strings contain {n} references.)
36.929 + * <li>Will not always find a match (or the correct match)
36.930 + * if some part of the parse is ambiguous.
36.931 + * For example, if the pattern "{1},{2}" is used with the
36.932 + * string arguments {"a,b", "c"}, it will format as "a,b,c".
36.933 + * When the result is parsed, it will return {"a", "b,c"}.
36.934 + * <li>If a single argument is parsed more than once in the string,
36.935 + * then the later parse wins.
36.936 + * </ul>
36.937 + * When the parse fails, use ParsePosition.getErrorIndex() to find out
36.938 + * where in the string the parsing failed. The returned error
36.939 + * index is the starting offset of the sub-patterns that the string
36.940 + * is comparing with. For example, if the parsing string "AAA {0} BBB"
36.941 + * is comparing against the pattern "AAD {0} BBB", the error index is
36.942 + * 0. When an error occurs, the call to this method will return null.
36.943 + * If the source is null, return an empty array.
36.944 + */
36.945 + public Object[] parse(String source, ParsePosition pos) {
36.946 + if (source == null) {
36.947 + Object[] empty = {};
36.948 + return empty;
36.949 + }
36.950 +
36.951 + int maximumArgumentNumber = -1;
36.952 + for (int i = 0; i <= maxOffset; i++) {
36.953 + if (argumentNumbers[i] > maximumArgumentNumber) {
36.954 + maximumArgumentNumber = argumentNumbers[i];
36.955 + }
36.956 + }
36.957 + Object[] resultArray = new Object[maximumArgumentNumber + 1];
36.958 +
36.959 + int patternOffset = 0;
36.960 + int sourceOffset = pos.index;
36.961 + ParsePosition tempStatus = new ParsePosition(0);
36.962 + for (int i = 0; i <= maxOffset; ++i) {
36.963 + // match up to format
36.964 + int len = offsets[i] - patternOffset;
36.965 + if (len == 0 || pattern.regionMatches(patternOffset,
36.966 + source, sourceOffset, len)) {
36.967 + sourceOffset += len;
36.968 + patternOffset += len;
36.969 + } else {
36.970 + pos.errorIndex = sourceOffset;
36.971 + return null; // leave index as is to signal error
36.972 + }
36.973 +
36.974 + // now use format
36.975 + if (formats[i] == null) { // string format
36.976 + // if at end, use longest possible match
36.977 + // otherwise uses first match to intervening string
36.978 + // does NOT recursively try all possibilities
36.979 + int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length();
36.980 +
36.981 + int next;
36.982 + if (patternOffset >= tempLength) {
36.983 + next = source.length();
36.984 + }else{
36.985 + next = source.indexOf(pattern.substring(patternOffset, tempLength),
36.986 + sourceOffset);
36.987 + }
36.988 +
36.989 + if (next < 0) {
36.990 + pos.errorIndex = sourceOffset;
36.991 + return null; // leave index as is to signal error
36.992 + } else {
36.993 + String strValue= source.substring(sourceOffset,next);
36.994 + if (!strValue.equals("{"+argumentNumbers[i]+"}"))
36.995 + resultArray[argumentNumbers[i]]
36.996 + = source.substring(sourceOffset,next);
36.997 + sourceOffset = next;
36.998 + }
36.999 + } else {
36.1000 + tempStatus.index = sourceOffset;
36.1001 + resultArray[argumentNumbers[i]]
36.1002 + = formats[i].parseObject(source,tempStatus);
36.1003 + if (tempStatus.index == sourceOffset) {
36.1004 + pos.errorIndex = sourceOffset;
36.1005 + return null; // leave index as is to signal error
36.1006 + }
36.1007 + sourceOffset = tempStatus.index; // update
36.1008 + }
36.1009 + }
36.1010 + int len = pattern.length() - patternOffset;
36.1011 + if (len == 0 || pattern.regionMatches(patternOffset,
36.1012 + source, sourceOffset, len)) {
36.1013 + pos.index = sourceOffset + len;
36.1014 + } else {
36.1015 + pos.errorIndex = sourceOffset;
36.1016 + return null; // leave index as is to signal error
36.1017 + }
36.1018 + return resultArray;
36.1019 + }
36.1020 +
36.1021 + /**
36.1022 + * Parses text from the beginning of the given string to produce an object
36.1023 + * array.
36.1024 + * The method may not use the entire text of the given string.
36.1025 + * <p>
36.1026 + * See the {@link #parse(String, ParsePosition)} method for more information
36.1027 + * on message parsing.
36.1028 + *
36.1029 + * @param source A <code>String</code> whose beginning should be parsed.
36.1030 + * @return An <code>Object</code> array parsed from the string.
36.1031 + * @exception ParseException if the beginning of the specified string
36.1032 + * cannot be parsed.
36.1033 + */
36.1034 + public Object[] parse(String source) throws ParseException {
36.1035 + ParsePosition pos = new ParsePosition(0);
36.1036 + Object[] result = parse(source, pos);
36.1037 + if (pos.index == 0) // unchanged, returned object is null
36.1038 + throw new ParseException("MessageFormat parse error!", pos.errorIndex);
36.1039 +
36.1040 + return result;
36.1041 + }
36.1042 +
36.1043 + /**
36.1044 + * Parses text from a string to produce an object array.
36.1045 + * <p>
36.1046 + * The method attempts to parse text starting at the index given by
36.1047 + * <code>pos</code>.
36.1048 + * If parsing succeeds, then the index of <code>pos</code> is updated
36.1049 + * to the index after the last character used (parsing does not necessarily
36.1050 + * use all characters up to the end of the string), and the parsed
36.1051 + * object array is returned. The updated <code>pos</code> can be used to
36.1052 + * indicate the starting point for the next call to this method.
36.1053 + * If an error occurs, then the index of <code>pos</code> is not
36.1054 + * changed, the error index of <code>pos</code> is set to the index of
36.1055 + * the character where the error occurred, and null is returned.
36.1056 + * <p>
36.1057 + * See the {@link #parse(String, ParsePosition)} method for more information
36.1058 + * on message parsing.
36.1059 + *
36.1060 + * @param source A <code>String</code>, part of which should be parsed.
36.1061 + * @param pos A <code>ParsePosition</code> object with index and error
36.1062 + * index information as described above.
36.1063 + * @return An <code>Object</code> array parsed from the string. In case of
36.1064 + * error, returns null.
36.1065 + * @exception NullPointerException if <code>pos</code> is null.
36.1066 + */
36.1067 + public Object parseObject(String source, ParsePosition pos) {
36.1068 + return parse(source, pos);
36.1069 + }
36.1070 +
36.1071 + /**
36.1072 + * Creates and returns a copy of this object.
36.1073 + *
36.1074 + * @return a clone of this instance.
36.1075 + */
36.1076 + public Object clone() {
36.1077 + MessageFormat other = (MessageFormat) super.clone();
36.1078 +
36.1079 + // clone arrays. Can't do with utility because of bug in Cloneable
36.1080 + other.formats = (Format[]) formats.clone(); // shallow clone
36.1081 + for (int i = 0; i < formats.length; ++i) {
36.1082 + if (formats[i] != null)
36.1083 + other.formats[i] = (Format)formats[i].clone();
36.1084 + }
36.1085 + // for primitives or immutables, shallow clone is enough
36.1086 + other.offsets = (int[]) offsets.clone();
36.1087 + other.argumentNumbers = (int[]) argumentNumbers.clone();
36.1088 +
36.1089 + return other;
36.1090 + }
36.1091 +
36.1092 + /**
36.1093 + * Equality comparison between two message format objects
36.1094 + */
36.1095 + public boolean equals(Object obj) {
36.1096 + if (this == obj) // quick check
36.1097 + return true;
36.1098 + if (obj == null || getClass() != obj.getClass())
36.1099 + return false;
36.1100 + MessageFormat other = (MessageFormat) obj;
36.1101 + return (maxOffset == other.maxOffset
36.1102 + && pattern.equals(other.pattern)
36.1103 + && ((locale != null && locale.equals(other.locale))
36.1104 + || (locale == null && other.locale == null))
36.1105 + && Arrays.equals(offsets,other.offsets)
36.1106 + && Arrays.equals(argumentNumbers,other.argumentNumbers)
36.1107 + && Arrays.equals(formats,other.formats));
36.1108 + }
36.1109 +
36.1110 + /**
36.1111 + * Generates a hash code for the message format object.
36.1112 + */
36.1113 + public int hashCode() {
36.1114 + return pattern.hashCode(); // enough for reasonable distribution
36.1115 + }
36.1116 +
36.1117 +
36.1118 + /**
36.1119 + * Defines constants that are used as attribute keys in the
36.1120 + * <code>AttributedCharacterIterator</code> returned
36.1121 + * from <code>MessageFormat.formatToCharacterIterator</code>.
36.1122 + *
36.1123 + * @since 1.4
36.1124 + */
36.1125 + public static class Field extends Format.Field {
36.1126 +
36.1127 + // Proclaim serial compatibility with 1.4 FCS
36.1128 + private static final long serialVersionUID = 7899943957617360810L;
36.1129 +
36.1130 + /**
36.1131 + * Creates a Field with the specified name.
36.1132 + *
36.1133 + * @param name Name of the attribute
36.1134 + */
36.1135 + protected Field(String name) {
36.1136 + super(name);
36.1137 + }
36.1138 +
36.1139 + /**
36.1140 + * Resolves instances being deserialized to the predefined constants.
36.1141 + *
36.1142 + * @throws InvalidObjectException if the constant could not be
36.1143 + * resolved.
36.1144 + * @return resolved MessageFormat.Field constant
36.1145 + */
36.1146 + protected Object readResolve() throws InvalidObjectException {
36.1147 + if (this.getClass() != MessageFormat.Field.class) {
36.1148 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
36.1149 + }
36.1150 +
36.1151 + return ARGUMENT;
36.1152 + }
36.1153 +
36.1154 + //
36.1155 + // The constants
36.1156 + //
36.1157 +
36.1158 + /**
36.1159 + * Constant identifying a portion of a message that was generated
36.1160 + * from an argument passed into <code>formatToCharacterIterator</code>.
36.1161 + * The value associated with the key will be an <code>Integer</code>
36.1162 + * indicating the index in the <code>arguments</code> array of the
36.1163 + * argument from which the text was generated.
36.1164 + */
36.1165 + public final static Field ARGUMENT =
36.1166 + new Field("message argument field");
36.1167 + }
36.1168 +
36.1169 + // ===========================privates============================
36.1170 +
36.1171 + /**
36.1172 + * The locale to use for formatting numbers and dates.
36.1173 + * @serial
36.1174 + */
36.1175 + private Locale locale;
36.1176 +
36.1177 + /**
36.1178 + * The string that the formatted values are to be plugged into. In other words, this
36.1179 + * is the pattern supplied on construction with all of the {} expressions taken out.
36.1180 + * @serial
36.1181 + */
36.1182 + private String pattern = "";
36.1183 +
36.1184 + /** The initially expected number of subformats in the format */
36.1185 + private static final int INITIAL_FORMATS = 10;
36.1186 +
36.1187 + /**
36.1188 + * An array of formatters, which are used to format the arguments.
36.1189 + * @serial
36.1190 + */
36.1191 + private Format[] formats = new Format[INITIAL_FORMATS];
36.1192 +
36.1193 + /**
36.1194 + * The positions where the results of formatting each argument are to be inserted
36.1195 + * into the pattern.
36.1196 + * @serial
36.1197 + */
36.1198 + private int[] offsets = new int[INITIAL_FORMATS];
36.1199 +
36.1200 + /**
36.1201 + * The argument numbers corresponding to each formatter. (The formatters are stored
36.1202 + * in the order they occur in the pattern, not in the order in which the arguments
36.1203 + * are specified.)
36.1204 + * @serial
36.1205 + */
36.1206 + private int[] argumentNumbers = new int[INITIAL_FORMATS];
36.1207 +
36.1208 + /**
36.1209 + * One less than the number of entries in <code>offsets</code>. Can also be thought of
36.1210 + * as the index of the highest-numbered element in <code>offsets</code> that is being used.
36.1211 + * All of these arrays should have the same number of elements being used as <code>offsets</code>
36.1212 + * does, and so this variable suffices to tell us how many entries are in all of them.
36.1213 + * @serial
36.1214 + */
36.1215 + private int maxOffset = -1;
36.1216 +
36.1217 + /**
36.1218 + * Internal routine used by format. If <code>characterIterators</code> is
36.1219 + * non-null, AttributedCharacterIterator will be created from the
36.1220 + * subformats as necessary. If <code>characterIterators</code> is null
36.1221 + * and <code>fp</code> is non-null and identifies
36.1222 + * <code>Field.MESSAGE_ARGUMENT</code>, the location of
36.1223 + * the first replaced argument will be set in it.
36.1224 + *
36.1225 + * @exception IllegalArgumentException if an argument in the
36.1226 + * <code>arguments</code> array is not of the type
36.1227 + * expected by the format element(s) that use it.
36.1228 + */
36.1229 + private StringBuffer subformat(Object[] arguments, StringBuffer result,
36.1230 + FieldPosition fp, List characterIterators) {
36.1231 + // note: this implementation assumes a fast substring & index.
36.1232 + // if this is not true, would be better to append chars one by one.
36.1233 + int lastOffset = 0;
36.1234 + int last = result.length();
36.1235 + for (int i = 0; i <= maxOffset; ++i) {
36.1236 + result.append(pattern.substring(lastOffset, offsets[i]));
36.1237 + lastOffset = offsets[i];
36.1238 + int argumentNumber = argumentNumbers[i];
36.1239 + if (arguments == null || argumentNumber >= arguments.length) {
36.1240 + result.append('{').append(argumentNumber).append('}');
36.1241 + continue;
36.1242 + }
36.1243 + // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
36.1244 + if (false) { // if (argRecursion == 3){
36.1245 + // prevent loop!!!
36.1246 + result.append('\uFFFD');
36.1247 + } else {
36.1248 + Object obj = arguments[argumentNumber];
36.1249 + String arg = null;
36.1250 + Format subFormatter = null;
36.1251 + if (obj == null) {
36.1252 + arg = "null";
36.1253 + } else if (formats[i] != null) {
36.1254 + subFormatter = formats[i];
36.1255 + if (subFormatter instanceof ChoiceFormat) {
36.1256 + arg = formats[i].format(obj);
36.1257 + if (arg.indexOf('{') >= 0) {
36.1258 + subFormatter = new MessageFormat(arg, locale);
36.1259 + obj = arguments;
36.1260 + arg = null;
36.1261 + }
36.1262 + }
36.1263 + } else if (obj instanceof Number) {
36.1264 + // format number if can
36.1265 + subFormatter = NumberFormat.getInstance(locale);
36.1266 + } else if (obj instanceof Date) {
36.1267 + // format a Date if can
36.1268 + subFormatter = DateFormat.getDateTimeInstance(
36.1269 + DateFormat.SHORT, DateFormat.SHORT, locale);//fix
36.1270 + } else if (obj instanceof String) {
36.1271 + arg = (String) obj;
36.1272 +
36.1273 + } else {
36.1274 + arg = obj.toString();
36.1275 + if (arg == null) arg = "null";
36.1276 + }
36.1277 +
36.1278 + // At this point we are in two states, either subFormatter
36.1279 + // is non-null indicating we should format obj using it,
36.1280 + // or arg is non-null and we should use it as the value.
36.1281 +
36.1282 + if (characterIterators != null) {
36.1283 + // If characterIterators is non-null, it indicates we need
36.1284 + // to get the CharacterIterator from the child formatter.
36.1285 + if (last != result.length()) {
36.1286 + characterIterators.add(
36.1287 + createAttributedCharacterIterator(result.substring
36.1288 + (last)));
36.1289 + last = result.length();
36.1290 + }
36.1291 + if (subFormatter != null) {
36.1292 + AttributedCharacterIterator subIterator =
36.1293 + subFormatter.formatToCharacterIterator(obj);
36.1294 +
36.1295 + append(result, subIterator);
36.1296 + if (last != result.length()) {
36.1297 + characterIterators.add(
36.1298 + createAttributedCharacterIterator(
36.1299 + subIterator, Field.ARGUMENT,
36.1300 + Integer.valueOf(argumentNumber)));
36.1301 + last = result.length();
36.1302 + }
36.1303 + arg = null;
36.1304 + }
36.1305 + if (arg != null && arg.length() > 0) {
36.1306 + result.append(arg);
36.1307 + characterIterators.add(
36.1308 + createAttributedCharacterIterator(
36.1309 + arg, Field.ARGUMENT,
36.1310 + Integer.valueOf(argumentNumber)));
36.1311 + last = result.length();
36.1312 + }
36.1313 + }
36.1314 + else {
36.1315 + if (subFormatter != null) {
36.1316 + arg = subFormatter.format(obj);
36.1317 + }
36.1318 + last = result.length();
36.1319 + result.append(arg);
36.1320 + if (i == 0 && fp != null && Field.ARGUMENT.equals(
36.1321 + fp.getFieldAttribute())) {
36.1322 + fp.setBeginIndex(last);
36.1323 + fp.setEndIndex(result.length());
36.1324 + }
36.1325 + last = result.length();
36.1326 + }
36.1327 + }
36.1328 + }
36.1329 + result.append(pattern.substring(lastOffset, pattern.length()));
36.1330 + if (characterIterators != null && last != result.length()) {
36.1331 + characterIterators.add(createAttributedCharacterIterator(
36.1332 + result.substring(last)));
36.1333 + }
36.1334 + return result;
36.1335 + }
36.1336 +
36.1337 + /**
36.1338 + * Convenience method to append all the characters in
36.1339 + * <code>iterator</code> to the StringBuffer <code>result</code>.
36.1340 + */
36.1341 + private void append(StringBuffer result, CharacterIterator iterator) {
36.1342 + if (iterator.first() != CharacterIterator.DONE) {
36.1343 + char aChar;
36.1344 +
36.1345 + result.append(iterator.first());
36.1346 + while ((aChar = iterator.next()) != CharacterIterator.DONE) {
36.1347 + result.append(aChar);
36.1348 + }
36.1349 + }
36.1350 + }
36.1351 +
36.1352 + // Indices for segments
36.1353 + private static final int SEG_RAW = 0;
36.1354 + private static final int SEG_INDEX = 1;
36.1355 + private static final int SEG_TYPE = 2;
36.1356 + private static final int SEG_MODIFIER = 3; // modifier or subformat
36.1357 +
36.1358 + // Indices for type keywords
36.1359 + private static final int TYPE_NULL = 0;
36.1360 + private static final int TYPE_NUMBER = 1;
36.1361 + private static final int TYPE_DATE = 2;
36.1362 + private static final int TYPE_TIME = 3;
36.1363 + private static final int TYPE_CHOICE = 4;
36.1364 +
36.1365 + private static final String[] TYPE_KEYWORDS = {
36.1366 + "",
36.1367 + "number",
36.1368 + "date",
36.1369 + "time",
36.1370 + "choice"
36.1371 + };
36.1372 +
36.1373 + // Indices for number modifiers
36.1374 + private static final int MODIFIER_DEFAULT = 0; // common in number and date-time
36.1375 + private static final int MODIFIER_CURRENCY = 1;
36.1376 + private static final int MODIFIER_PERCENT = 2;
36.1377 + private static final int MODIFIER_INTEGER = 3;
36.1378 +
36.1379 + private static final String[] NUMBER_MODIFIER_KEYWORDS = {
36.1380 + "",
36.1381 + "currency",
36.1382 + "percent",
36.1383 + "integer"
36.1384 + };
36.1385 +
36.1386 + // Indices for date-time modifiers
36.1387 + private static final int MODIFIER_SHORT = 1;
36.1388 + private static final int MODIFIER_MEDIUM = 2;
36.1389 + private static final int MODIFIER_LONG = 3;
36.1390 + private static final int MODIFIER_FULL = 4;
36.1391 +
36.1392 + private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
36.1393 + "",
36.1394 + "short",
36.1395 + "medium",
36.1396 + "long",
36.1397 + "full"
36.1398 + };
36.1399 +
36.1400 + // Date-time style values corresponding to the date-time modifiers.
36.1401 + private static final int[] DATE_TIME_MODIFIERS = {
36.1402 + DateFormat.DEFAULT,
36.1403 + DateFormat.SHORT,
36.1404 + DateFormat.MEDIUM,
36.1405 + DateFormat.LONG,
36.1406 + DateFormat.FULL,
36.1407 + };
36.1408 +
36.1409 + private void makeFormat(int position, int offsetNumber,
36.1410 + StringBuilder[] textSegments)
36.1411 + {
36.1412 + String[] segments = new String[textSegments.length];
36.1413 + for (int i = 0; i < textSegments.length; i++) {
36.1414 + StringBuilder oneseg = textSegments[i];
36.1415 + segments[i] = (oneseg != null) ? oneseg.toString() : "";
36.1416 + }
36.1417 +
36.1418 + // get the argument number
36.1419 + int argumentNumber;
36.1420 + try {
36.1421 + argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
36.1422 + } catch (NumberFormatException e) {
36.1423 + throw new IllegalArgumentException("can't parse argument number: "
36.1424 + + segments[SEG_INDEX], e);
36.1425 + }
36.1426 + if (argumentNumber < 0) {
36.1427 + throw new IllegalArgumentException("negative argument number: "
36.1428 + + argumentNumber);
36.1429 + }
36.1430 +
36.1431 + // resize format information arrays if necessary
36.1432 + if (offsetNumber >= formats.length) {
36.1433 + int newLength = formats.length * 2;
36.1434 + Format[] newFormats = new Format[newLength];
36.1435 + int[] newOffsets = new int[newLength];
36.1436 + int[] newArgumentNumbers = new int[newLength];
36.1437 + System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1);
36.1438 + System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1);
36.1439 + System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1);
36.1440 + formats = newFormats;
36.1441 + offsets = newOffsets;
36.1442 + argumentNumbers = newArgumentNumbers;
36.1443 + }
36.1444 + int oldMaxOffset = maxOffset;
36.1445 + maxOffset = offsetNumber;
36.1446 + offsets[offsetNumber] = segments[SEG_RAW].length();
36.1447 + argumentNumbers[offsetNumber] = argumentNumber;
36.1448 +
36.1449 + // now get the format
36.1450 + Format newFormat = null;
36.1451 + if (segments[SEG_TYPE].length() != 0) {
36.1452 + int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
36.1453 + switch (type) {
36.1454 + case TYPE_NULL:
36.1455 + // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
36.1456 + // are treated as "{0}".
36.1457 + break;
36.1458 +
36.1459 + case TYPE_NUMBER:
36.1460 + switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
36.1461 + case MODIFIER_DEFAULT:
36.1462 + newFormat = NumberFormat.getInstance(locale);
36.1463 + break;
36.1464 + case MODIFIER_CURRENCY:
36.1465 + newFormat = NumberFormat.getCurrencyInstance(locale);
36.1466 + break;
36.1467 + case MODIFIER_PERCENT:
36.1468 + newFormat = NumberFormat.getPercentInstance(locale);
36.1469 + break;
36.1470 + case MODIFIER_INTEGER:
36.1471 + newFormat = NumberFormat.getIntegerInstance(locale);
36.1472 + break;
36.1473 + default: // DecimalFormat pattern
36.1474 + try {
36.1475 + newFormat = new DecimalFormat(segments[SEG_MODIFIER],
36.1476 + DecimalFormatSymbols.getInstance(locale));
36.1477 + } catch (IllegalArgumentException e) {
36.1478 + maxOffset = oldMaxOffset;
36.1479 + throw e;
36.1480 + }
36.1481 + break;
36.1482 + }
36.1483 + break;
36.1484 +
36.1485 + case TYPE_DATE:
36.1486 + case TYPE_TIME:
36.1487 + int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
36.1488 + if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
36.1489 + if (type == TYPE_DATE) {
36.1490 + newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
36.1491 + locale);
36.1492 + } else {
36.1493 + newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
36.1494 + locale);
36.1495 + }
36.1496 + } else {
36.1497 + // SimpleDateFormat pattern
36.1498 + try {
36.1499 + newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
36.1500 + } catch (IllegalArgumentException e) {
36.1501 + maxOffset = oldMaxOffset;
36.1502 + throw e;
36.1503 + }
36.1504 + }
36.1505 + break;
36.1506 +
36.1507 + case TYPE_CHOICE:
36.1508 + try {
36.1509 + // ChoiceFormat pattern
36.1510 + newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
36.1511 + } catch (Exception e) {
36.1512 + maxOffset = oldMaxOffset;
36.1513 + throw new IllegalArgumentException("Choice Pattern incorrect: "
36.1514 + + segments[SEG_MODIFIER], e);
36.1515 + }
36.1516 + break;
36.1517 +
36.1518 + default:
36.1519 + maxOffset = oldMaxOffset;
36.1520 + throw new IllegalArgumentException("unknown format type: " +
36.1521 + segments[SEG_TYPE]);
36.1522 + }
36.1523 + }
36.1524 + formats[offsetNumber] = newFormat;
36.1525 + }
36.1526 +
36.1527 + private static final int findKeyword(String s, String[] list) {
36.1528 + for (int i = 0; i < list.length; ++i) {
36.1529 + if (s.equals(list[i]))
36.1530 + return i;
36.1531 + }
36.1532 +
36.1533 + // Try trimmed lowercase.
36.1534 + String ls = s.trim().toLowerCase(Locale.ROOT);
36.1535 + if (ls != s) {
36.1536 + for (int i = 0; i < list.length; ++i) {
36.1537 + if (ls.equals(list[i]))
36.1538 + return i;
36.1539 + }
36.1540 + }
36.1541 + return -1;
36.1542 + }
36.1543 +
36.1544 + private static final void copyAndFixQuotes(String source, int start, int end,
36.1545 + StringBuilder target) {
36.1546 + boolean quoted = false;
36.1547 +
36.1548 + for (int i = start; i < end; ++i) {
36.1549 + char ch = source.charAt(i);
36.1550 + if (ch == '{') {
36.1551 + if (!quoted) {
36.1552 + target.append('\'');
36.1553 + quoted = true;
36.1554 + }
36.1555 + target.append(ch);
36.1556 + } else if (ch == '\'') {
36.1557 + target.append("''");
36.1558 + } else {
36.1559 + if (quoted) {
36.1560 + target.append('\'');
36.1561 + quoted = false;
36.1562 + }
36.1563 + target.append(ch);
36.1564 + }
36.1565 + }
36.1566 + if (quoted) {
36.1567 + target.append('\'');
36.1568 + }
36.1569 + }
36.1570 +
36.1571 + /**
36.1572 + * After reading an object from the input stream, do a simple verification
36.1573 + * to maintain class invariants.
36.1574 + * @throws InvalidObjectException if the objects read from the stream is invalid.
36.1575 + */
36.1576 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
36.1577 + in.defaultReadObject();
36.1578 + boolean isValid = maxOffset >= -1
36.1579 + && formats.length > maxOffset
36.1580 + && offsets.length > maxOffset
36.1581 + && argumentNumbers.length > maxOffset;
36.1582 + if (isValid) {
36.1583 + int lastOffset = pattern.length() + 1;
36.1584 + for (int i = maxOffset; i >= 0; --i) {
36.1585 + if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
36.1586 + isValid = false;
36.1587 + break;
36.1588 + } else {
36.1589 + lastOffset = offsets[i];
36.1590 + }
36.1591 + }
36.1592 + }
36.1593 + if (!isValid) {
36.1594 + throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
36.1595 + }
36.1596 + }
36.1597 +}
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/rt/emul/compact/src/main/java/java/text/NumberFormat.java Thu Oct 03 15:43:10 2013 +0200
37.3 @@ -0,0 +1,1162 @@
37.4 +/*
37.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
37.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
37.7 + *
37.8 + * This code is free software; you can redistribute it and/or modify it
37.9 + * under the terms of the GNU General Public License version 2 only, as
37.10 + * published by the Free Software Foundation. Oracle designates this
37.11 + * particular file as subject to the "Classpath" exception as provided
37.12 + * by Oracle in the LICENSE file that accompanied this code.
37.13 + *
37.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
37.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
37.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37.17 + * version 2 for more details (a copy is included in the LICENSE file that
37.18 + * accompanied this code).
37.19 + *
37.20 + * You should have received a copy of the GNU General Public License version
37.21 + * 2 along with this work; if not, write to the Free Software Foundation,
37.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
37.23 + *
37.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
37.25 + * or visit www.oracle.com if you need additional information or have any
37.26 + * questions.
37.27 + */
37.28 +
37.29 +/*
37.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
37.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
37.32 + *
37.33 + * The original version of this source code and documentation is copyrighted
37.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
37.35 + * materials are provided under terms of a License Agreement between Taligent
37.36 + * and Sun. This technology is protected by multiple US and International
37.37 + * patents. This notice and attribution to Taligent may not be removed.
37.38 + * Taligent is a registered trademark of Taligent, Inc.
37.39 + *
37.40 + */
37.41 +
37.42 +package java.text;
37.43 +
37.44 +import java.io.InvalidObjectException;
37.45 +import java.io.IOException;
37.46 +import java.io.ObjectInputStream;
37.47 +import java.io.ObjectOutputStream;
37.48 +import java.math.BigInteger;
37.49 +import java.math.RoundingMode;
37.50 +import java.text.spi.NumberFormatProvider;
37.51 +import java.util.Currency;
37.52 +import java.util.HashMap;
37.53 +import java.util.Hashtable;
37.54 +import java.util.Locale;
37.55 +import java.util.Map;
37.56 +import java.util.ResourceBundle;
37.57 +import java.util.concurrent.atomic.AtomicInteger;
37.58 +import java.util.concurrent.atomic.AtomicLong;
37.59 +import java.util.spi.LocaleServiceProvider;
37.60 +import sun.util.LocaleServiceProviderPool;
37.61 +import sun.util.resources.LocaleData;
37.62 +
37.63 +/**
37.64 + * <code>NumberFormat</code> is the abstract base class for all number
37.65 + * formats. This class provides the interface for formatting and parsing
37.66 + * numbers. <code>NumberFormat</code> also provides methods for determining
37.67 + * which locales have number formats, and what their names are.
37.68 + *
37.69 + * <p>
37.70 + * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
37.71 + * Your code can be completely independent of the locale conventions for
37.72 + * decimal points, thousands-separators, or even the particular decimal
37.73 + * digits used, or whether the number format is even decimal.
37.74 + *
37.75 + * <p>
37.76 + * To format a number for the current Locale, use one of the factory
37.77 + * class methods:
37.78 + * <blockquote>
37.79 + * <pre>
37.80 + * myString = NumberFormat.getInstance().format(myNumber);
37.81 + * </pre>
37.82 + * </blockquote>
37.83 + * If you are formatting multiple numbers, it is
37.84 + * more efficient to get the format and use it multiple times so that
37.85 + * the system doesn't have to fetch the information about the local
37.86 + * language and country conventions multiple times.
37.87 + * <blockquote>
37.88 + * <pre>
37.89 + * NumberFormat nf = NumberFormat.getInstance();
37.90 + * for (int i = 0; i < myNumber.length; ++i) {
37.91 + * output.println(nf.format(myNumber[i]) + "; ");
37.92 + * }
37.93 + * </pre>
37.94 + * </blockquote>
37.95 + * To format a number for a different Locale, specify it in the
37.96 + * call to <code>getInstance</code>.
37.97 + * <blockquote>
37.98 + * <pre>
37.99 + * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
37.100 + * </pre>
37.101 + * </blockquote>
37.102 + * You can also use a <code>NumberFormat</code> to parse numbers:
37.103 + * <blockquote>
37.104 + * <pre>
37.105 + * myNumber = nf.parse(myString);
37.106 + * </pre>
37.107 + * </blockquote>
37.108 + * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
37.109 + * normal number format. Use <code>getIntegerInstance</code> to get an
37.110 + * integer number format. Use <code>getCurrencyInstance</code> to get the
37.111 + * currency number format. And use <code>getPercentInstance</code> to get a
37.112 + * format for displaying percentages. With this format, a fraction like
37.113 + * 0.53 is displayed as 53%.
37.114 + *
37.115 + * <p>
37.116 + * You can also control the display of numbers with such methods as
37.117 + * <code>setMinimumFractionDigits</code>.
37.118 + * If you want even more control over the format or parsing,
37.119 + * or want to give your users more control,
37.120 + * you can try casting the <code>NumberFormat</code> you get from the factory methods
37.121 + * to a <code>DecimalFormat</code>. This will work for the vast majority
37.122 + * of locales; just remember to put it in a <code>try</code> block in case you
37.123 + * encounter an unusual one.
37.124 + *
37.125 + * <p>
37.126 + * NumberFormat and DecimalFormat are designed such that some controls
37.127 + * work for formatting and others work for parsing. The following is
37.128 + * the detailed description for each these control methods,
37.129 + * <p>
37.130 + * setParseIntegerOnly : only affects parsing, e.g.
37.131 + * if true, "3456.78" -> 3456 (and leaves the parse position just after index 6)
37.132 + * if false, "3456.78" -> 3456.78 (and leaves the parse position just after index 8)
37.133 + * This is independent of formatting. If you want to not show a decimal point
37.134 + * where there might be no digits after the decimal point, use
37.135 + * setDecimalSeparatorAlwaysShown.
37.136 + * <p>
37.137 + * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
37.138 + * there might be no digits after the decimal point, such as with a pattern
37.139 + * like "#,##0.##", e.g.,
37.140 + * if true, 3456.00 -> "3,456."
37.141 + * if false, 3456.00 -> "3456"
37.142 + * This is independent of parsing. If you want parsing to stop at the decimal
37.143 + * point, use setParseIntegerOnly.
37.144 + *
37.145 + * <p>
37.146 + * You can also use forms of the <code>parse</code> and <code>format</code>
37.147 + * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
37.148 + * allow you to:
37.149 + * <ul>
37.150 + * <li> progressively parse through pieces of a string
37.151 + * <li> align the decimal point and other areas
37.152 + * </ul>
37.153 + * For example, you can align numbers in two ways:
37.154 + * <ol>
37.155 + * <li> If you are using a monospaced font with spacing for alignment,
37.156 + * you can pass the <code>FieldPosition</code> in your format call, with
37.157 + * <code>field</code> = <code>INTEGER_FIELD</code>. On output,
37.158 + * <code>getEndIndex</code> will be set to the offset between the
37.159 + * last character of the integer and the decimal. Add
37.160 + * (desiredSpaceCount - getEndIndex) spaces at the front of the string.
37.161 + *
37.162 + * <li> If you are using proportional fonts,
37.163 + * instead of padding with spaces, measure the width
37.164 + * of the string in pixels from the start to <code>getEndIndex</code>.
37.165 + * Then move the pen by
37.166 + * (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
37.167 + * It also works where there is no decimal, but possibly additional
37.168 + * characters at the end, e.g., with parentheses in negative
37.169 + * numbers: "(12)" for -12.
37.170 + * </ol>
37.171 + *
37.172 + * <h4><a name="synchronization">Synchronization</a></h4>
37.173 + *
37.174 + * <p>
37.175 + * Number formats are generally not synchronized.
37.176 + * It is recommended to create separate format instances for each thread.
37.177 + * If multiple threads access a format concurrently, it must be synchronized
37.178 + * externally.
37.179 + *
37.180 + * @see DecimalFormat
37.181 + * @see ChoiceFormat
37.182 + * @author Mark Davis
37.183 + * @author Helena Shih
37.184 + */
37.185 +public abstract class NumberFormat extends Format {
37.186 +
37.187 + /**
37.188 + * Field constant used to construct a FieldPosition object. Signifies that
37.189 + * the position of the integer part of a formatted number should be returned.
37.190 + * @see java.text.FieldPosition
37.191 + */
37.192 + public static final int INTEGER_FIELD = 0;
37.193 +
37.194 + /**
37.195 + * Field constant used to construct a FieldPosition object. Signifies that
37.196 + * the position of the fraction part of a formatted number should be returned.
37.197 + * @see java.text.FieldPosition
37.198 + */
37.199 + public static final int FRACTION_FIELD = 1;
37.200 +
37.201 + /**
37.202 + * Sole constructor. (For invocation by subclass constructors, typically
37.203 + * implicit.)
37.204 + */
37.205 + protected NumberFormat() {
37.206 + }
37.207 +
37.208 + /**
37.209 + * Formats a number and appends the resulting text to the given string
37.210 + * buffer.
37.211 + * The number can be of any subclass of {@link java.lang.Number}.
37.212 + * <p>
37.213 + * This implementation extracts the number's value using
37.214 + * {@link java.lang.Number#longValue()} for all integral type values that
37.215 + * can be converted to <code>long</code> without loss of information,
37.216 + * including <code>BigInteger</code> values with a
37.217 + * {@link java.math.BigInteger#bitLength() bit length} of less than 64,
37.218 + * and {@link java.lang.Number#doubleValue()} for all other types. It
37.219 + * then calls
37.220 + * {@link #format(long,java.lang.StringBuffer,java.text.FieldPosition)}
37.221 + * or {@link #format(double,java.lang.StringBuffer,java.text.FieldPosition)}.
37.222 + * This may result in loss of magnitude information and precision for
37.223 + * <code>BigInteger</code> and <code>BigDecimal</code> values.
37.224 + * @param number the number to format
37.225 + * @param toAppendTo the <code>StringBuffer</code> to which the formatted
37.226 + * text is to be appended
37.227 + * @param pos On input: an alignment field, if desired.
37.228 + * On output: the offsets of the alignment field.
37.229 + * @return the value passed in as <code>toAppendTo</code>
37.230 + * @exception IllegalArgumentException if <code>number</code> is
37.231 + * null or not an instance of <code>Number</code>.
37.232 + * @exception NullPointerException if <code>toAppendTo</code> or
37.233 + * <code>pos</code> is null
37.234 + * @exception ArithmeticException if rounding is needed with rounding
37.235 + * mode being set to RoundingMode.UNNECESSARY
37.236 + * @see java.text.FieldPosition
37.237 + */
37.238 + public StringBuffer format(Object number,
37.239 + StringBuffer toAppendTo,
37.240 + FieldPosition pos) {
37.241 + if (number instanceof Long || number instanceof Integer ||
37.242 + number instanceof Short || number instanceof Byte ||
37.243 + number instanceof AtomicInteger || number instanceof AtomicLong ||
37.244 + (number instanceof BigInteger &&
37.245 + ((BigInteger)number).bitLength() < 64)) {
37.246 + return format(((Number)number).longValue(), toAppendTo, pos);
37.247 + } else if (number instanceof Number) {
37.248 + return format(((Number)number).doubleValue(), toAppendTo, pos);
37.249 + } else {
37.250 + throw new IllegalArgumentException("Cannot format given Object as a Number");
37.251 + }
37.252 + }
37.253 +
37.254 + /**
37.255 + * Parses text from a string to produce a <code>Number</code>.
37.256 + * <p>
37.257 + * The method attempts to parse text starting at the index given by
37.258 + * <code>pos</code>.
37.259 + * If parsing succeeds, then the index of <code>pos</code> is updated
37.260 + * to the index after the last character used (parsing does not necessarily
37.261 + * use all characters up to the end of the string), and the parsed
37.262 + * number is returned. The updated <code>pos</code> can be used to
37.263 + * indicate the starting point for the next call to this method.
37.264 + * If an error occurs, then the index of <code>pos</code> is not
37.265 + * changed, the error index of <code>pos</code> is set to the index of
37.266 + * the character where the error occurred, and null is returned.
37.267 + * <p>
37.268 + * See the {@link #parse(String, ParsePosition)} method for more information
37.269 + * on number parsing.
37.270 + *
37.271 + * @param source A <code>String</code>, part of which should be parsed.
37.272 + * @param pos A <code>ParsePosition</code> object with index and error
37.273 + * index information as described above.
37.274 + * @return A <code>Number</code> parsed from the string. In case of
37.275 + * error, returns null.
37.276 + * @exception NullPointerException if <code>pos</code> is null.
37.277 + */
37.278 + public final Object parseObject(String source, ParsePosition pos) {
37.279 + return parse(source, pos);
37.280 + }
37.281 +
37.282 + /**
37.283 + * Specialization of format.
37.284 + * @exception ArithmeticException if rounding is needed with rounding
37.285 + * mode being set to RoundingMode.UNNECESSARY
37.286 + * @see java.text.Format#format
37.287 + */
37.288 + public final String format(double number) {
37.289 + return format(number, new StringBuffer(),
37.290 + DontCareFieldPosition.INSTANCE).toString();
37.291 + }
37.292 +
37.293 + /**
37.294 + * Specialization of format.
37.295 + * @exception ArithmeticException if rounding is needed with rounding
37.296 + * mode being set to RoundingMode.UNNECESSARY
37.297 + * @see java.text.Format#format
37.298 + */
37.299 + public final String format(long number) {
37.300 + return format(number, new StringBuffer(),
37.301 + DontCareFieldPosition.INSTANCE).toString();
37.302 + }
37.303 +
37.304 + /**
37.305 + * Specialization of format.
37.306 + * @exception ArithmeticException if rounding is needed with rounding
37.307 + * mode being set to RoundingMode.UNNECESSARY
37.308 + * @see java.text.Format#format
37.309 + */
37.310 + public abstract StringBuffer format(double number,
37.311 + StringBuffer toAppendTo,
37.312 + FieldPosition pos);
37.313 +
37.314 + /**
37.315 + * Specialization of format.
37.316 + * @exception ArithmeticException if rounding is needed with rounding
37.317 + * mode being set to RoundingMode.UNNECESSARY
37.318 + * @see java.text.Format#format
37.319 + */
37.320 + public abstract StringBuffer format(long number,
37.321 + StringBuffer toAppendTo,
37.322 + FieldPosition pos);
37.323 +
37.324 + /**
37.325 + * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
37.326 + * Long.MAX_VALUE] and with no decimals), otherwise a Double.
37.327 + * If IntegerOnly is set, will stop at a decimal
37.328 + * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
37.329 + * after the 1).
37.330 + * Does not throw an exception; if no object can be parsed, index is
37.331 + * unchanged!
37.332 + * @see java.text.NumberFormat#isParseIntegerOnly
37.333 + * @see java.text.Format#parseObject
37.334 + */
37.335 + public abstract Number parse(String source, ParsePosition parsePosition);
37.336 +
37.337 + /**
37.338 + * Parses text from the beginning of the given string to produce a number.
37.339 + * The method may not use the entire text of the given string.
37.340 + * <p>
37.341 + * See the {@link #parse(String, ParsePosition)} method for more information
37.342 + * on number parsing.
37.343 + *
37.344 + * @param source A <code>String</code> whose beginning should be parsed.
37.345 + * @return A <code>Number</code> parsed from the string.
37.346 + * @exception ParseException if the beginning of the specified string
37.347 + * cannot be parsed.
37.348 + */
37.349 + public Number parse(String source) throws ParseException {
37.350 + ParsePosition parsePosition = new ParsePosition(0);
37.351 + Number result = parse(source, parsePosition);
37.352 + if (parsePosition.index == 0) {
37.353 + throw new ParseException("Unparseable number: \"" + source + "\"",
37.354 + parsePosition.errorIndex);
37.355 + }
37.356 + return result;
37.357 + }
37.358 +
37.359 + /**
37.360 + * Returns true if this format will parse numbers as integers only.
37.361 + * For example in the English locale, with ParseIntegerOnly true, the
37.362 + * string "1234." would be parsed as the integer value 1234 and parsing
37.363 + * would stop at the "." character. Of course, the exact format accepted
37.364 + * by the parse operation is locale dependant and determined by sub-classes
37.365 + * of NumberFormat.
37.366 + */
37.367 + public boolean isParseIntegerOnly() {
37.368 + return parseIntegerOnly;
37.369 + }
37.370 +
37.371 + /**
37.372 + * Sets whether or not numbers should be parsed as integers only.
37.373 + * @see #isParseIntegerOnly
37.374 + */
37.375 + public void setParseIntegerOnly(boolean value) {
37.376 + parseIntegerOnly = value;
37.377 + }
37.378 +
37.379 + //============== Locale Stuff =====================
37.380 +
37.381 + /**
37.382 + * Returns a general-purpose number format for the current default locale.
37.383 + * This is the same as calling
37.384 + * {@link #getNumberInstance() getNumberInstance()}.
37.385 + */
37.386 + public final static NumberFormat getInstance() {
37.387 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
37.388 + }
37.389 +
37.390 + /**
37.391 + * Returns a general-purpose number format for the specified locale.
37.392 + * This is the same as calling
37.393 + * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}.
37.394 + */
37.395 + public static NumberFormat getInstance(Locale inLocale) {
37.396 + return getInstance(inLocale, NUMBERSTYLE);
37.397 + }
37.398 +
37.399 + /**
37.400 + * Returns a general-purpose number format for the current default locale.
37.401 + */
37.402 + public final static NumberFormat getNumberInstance() {
37.403 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
37.404 + }
37.405 +
37.406 + /**
37.407 + * Returns a general-purpose number format for the specified locale.
37.408 + */
37.409 + public static NumberFormat getNumberInstance(Locale inLocale) {
37.410 + return getInstance(inLocale, NUMBERSTYLE);
37.411 + }
37.412 +
37.413 + /**
37.414 + * Returns an integer number format for the current default locale. The
37.415 + * returned number format is configured to round floating point numbers
37.416 + * to the nearest integer using half-even rounding (see {@link
37.417 + * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
37.418 + * and to parse only the integer part of an input string (see {@link
37.419 + * #isParseIntegerOnly isParseIntegerOnly}).
37.420 + *
37.421 + * @see #getRoundingMode()
37.422 + * @return a number format for integer values
37.423 + * @since 1.4
37.424 + */
37.425 + public final static NumberFormat getIntegerInstance() {
37.426 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
37.427 + }
37.428 +
37.429 + /**
37.430 + * Returns an integer number format for the specified locale. The
37.431 + * returned number format is configured to round floating point numbers
37.432 + * to the nearest integer using half-even rounding (see {@link
37.433 + * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
37.434 + * and to parse only the integer part of an input string (see {@link
37.435 + * #isParseIntegerOnly isParseIntegerOnly}).
37.436 + *
37.437 + * @see #getRoundingMode()
37.438 + * @return a number format for integer values
37.439 + * @since 1.4
37.440 + */
37.441 + public static NumberFormat getIntegerInstance(Locale inLocale) {
37.442 + return getInstance(inLocale, INTEGERSTYLE);
37.443 + }
37.444 +
37.445 + /**
37.446 + * Returns a currency format for the current default locale.
37.447 + */
37.448 + public final static NumberFormat getCurrencyInstance() {
37.449 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
37.450 + }
37.451 +
37.452 + /**
37.453 + * Returns a currency format for the specified locale.
37.454 + */
37.455 + public static NumberFormat getCurrencyInstance(Locale inLocale) {
37.456 + return getInstance(inLocale, CURRENCYSTYLE);
37.457 + }
37.458 +
37.459 + /**
37.460 + * Returns a percentage format for the current default locale.
37.461 + */
37.462 + public final static NumberFormat getPercentInstance() {
37.463 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
37.464 + }
37.465 +
37.466 + /**
37.467 + * Returns a percentage format for the specified locale.
37.468 + */
37.469 + public static NumberFormat getPercentInstance(Locale inLocale) {
37.470 + return getInstance(inLocale, PERCENTSTYLE);
37.471 + }
37.472 +
37.473 + /**
37.474 + * Returns a scientific format for the current default locale.
37.475 + */
37.476 + /*public*/ final static NumberFormat getScientificInstance() {
37.477 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE);
37.478 + }
37.479 +
37.480 + /**
37.481 + * Returns a scientific format for the specified locale.
37.482 + */
37.483 + /*public*/ static NumberFormat getScientificInstance(Locale inLocale) {
37.484 + return getInstance(inLocale, SCIENTIFICSTYLE);
37.485 + }
37.486 +
37.487 + /**
37.488 + * Returns an array of all locales for which the
37.489 + * <code>get*Instance</code> methods of this class can return
37.490 + * localized instances.
37.491 + * The returned array represents the union of locales supported by the Java
37.492 + * runtime and by installed
37.493 + * {@link java.text.spi.NumberFormatProvider NumberFormatProvider} implementations.
37.494 + * It must contain at least a <code>Locale</code> instance equal to
37.495 + * {@link java.util.Locale#US Locale.US}.
37.496 + *
37.497 + * @return An array of locales for which localized
37.498 + * <code>NumberFormat</code> instances are available.
37.499 + */
37.500 + public static Locale[] getAvailableLocales() {
37.501 + LocaleServiceProviderPool pool =
37.502 + LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
37.503 + return pool.getAvailableLocales();
37.504 + }
37.505 +
37.506 + /**
37.507 + * Overrides hashCode
37.508 + */
37.509 + public int hashCode() {
37.510 + return maximumIntegerDigits * 37 + maxFractionDigits;
37.511 + // just enough fields for a reasonable distribution
37.512 + }
37.513 +
37.514 + /**
37.515 + * Overrides equals
37.516 + */
37.517 + public boolean equals(Object obj) {
37.518 + if (obj == null) {
37.519 + return false;
37.520 + }
37.521 + if (this == obj) {
37.522 + return true;
37.523 + }
37.524 + if (getClass() != obj.getClass()) {
37.525 + return false;
37.526 + }
37.527 + NumberFormat other = (NumberFormat) obj;
37.528 + return (maximumIntegerDigits == other.maximumIntegerDigits
37.529 + && minimumIntegerDigits == other.minimumIntegerDigits
37.530 + && maximumFractionDigits == other.maximumFractionDigits
37.531 + && minimumFractionDigits == other.minimumFractionDigits
37.532 + && groupingUsed == other.groupingUsed
37.533 + && parseIntegerOnly == other.parseIntegerOnly);
37.534 + }
37.535 +
37.536 + /**
37.537 + * Overrides Cloneable
37.538 + */
37.539 + public Object clone() {
37.540 + NumberFormat other = (NumberFormat) super.clone();
37.541 + return other;
37.542 + }
37.543 +
37.544 + /**
37.545 + * Returns true if grouping is used in this format. For example, in the
37.546 + * English locale, with grouping on, the number 1234567 might be formatted
37.547 + * as "1,234,567". The grouping separator as well as the size of each group
37.548 + * is locale dependant and is determined by sub-classes of NumberFormat.
37.549 + * @see #setGroupingUsed
37.550 + */
37.551 + public boolean isGroupingUsed() {
37.552 + return groupingUsed;
37.553 + }
37.554 +
37.555 + /**
37.556 + * Set whether or not grouping will be used in this format.
37.557 + * @see #isGroupingUsed
37.558 + */
37.559 + public void setGroupingUsed(boolean newValue) {
37.560 + groupingUsed = newValue;
37.561 + }
37.562 +
37.563 + /**
37.564 + * Returns the maximum number of digits allowed in the integer portion of a
37.565 + * number.
37.566 + * @see #setMaximumIntegerDigits
37.567 + */
37.568 + public int getMaximumIntegerDigits() {
37.569 + return maximumIntegerDigits;
37.570 + }
37.571 +
37.572 + /**
37.573 + * Sets the maximum number of digits allowed in the integer portion of a
37.574 + * number. maximumIntegerDigits must be >= minimumIntegerDigits. If the
37.575 + * new value for maximumIntegerDigits is less than the current value
37.576 + * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
37.577 + * the new value.
37.578 + * @param newValue the maximum number of integer digits to be shown; if
37.579 + * less than zero, then zero is used. The concrete subclass may enforce an
37.580 + * upper limit to this value appropriate to the numeric type being formatted.
37.581 + * @see #getMaximumIntegerDigits
37.582 + */
37.583 + public void setMaximumIntegerDigits(int newValue) {
37.584 + maximumIntegerDigits = Math.max(0,newValue);
37.585 + if (minimumIntegerDigits > maximumIntegerDigits) {
37.586 + minimumIntegerDigits = maximumIntegerDigits;
37.587 + }
37.588 + }
37.589 +
37.590 + /**
37.591 + * Returns the minimum number of digits allowed in the integer portion of a
37.592 + * number.
37.593 + * @see #setMinimumIntegerDigits
37.594 + */
37.595 + public int getMinimumIntegerDigits() {
37.596 + return minimumIntegerDigits;
37.597 + }
37.598 +
37.599 + /**
37.600 + * Sets the minimum number of digits allowed in the integer portion of a
37.601 + * number. minimumIntegerDigits must be <= maximumIntegerDigits. If the
37.602 + * new value for minimumIntegerDigits exceeds the current value
37.603 + * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
37.604 + * the new value
37.605 + * @param newValue the minimum number of integer digits to be shown; if
37.606 + * less than zero, then zero is used. The concrete subclass may enforce an
37.607 + * upper limit to this value appropriate to the numeric type being formatted.
37.608 + * @see #getMinimumIntegerDigits
37.609 + */
37.610 + public void setMinimumIntegerDigits(int newValue) {
37.611 + minimumIntegerDigits = Math.max(0,newValue);
37.612 + if (minimumIntegerDigits > maximumIntegerDigits) {
37.613 + maximumIntegerDigits = minimumIntegerDigits;
37.614 + }
37.615 + }
37.616 +
37.617 + /**
37.618 + * Returns the maximum number of digits allowed in the fraction portion of a
37.619 + * number.
37.620 + * @see #setMaximumFractionDigits
37.621 + */
37.622 + public int getMaximumFractionDigits() {
37.623 + return maximumFractionDigits;
37.624 + }
37.625 +
37.626 + /**
37.627 + * Sets the maximum number of digits allowed in the fraction portion of a
37.628 + * number. maximumFractionDigits must be >= minimumFractionDigits. If the
37.629 + * new value for maximumFractionDigits is less than the current value
37.630 + * of minimumFractionDigits, then minimumFractionDigits will also be set to
37.631 + * the new value.
37.632 + * @param newValue the maximum number of fraction digits to be shown; if
37.633 + * less than zero, then zero is used. The concrete subclass may enforce an
37.634 + * upper limit to this value appropriate to the numeric type being formatted.
37.635 + * @see #getMaximumFractionDigits
37.636 + */
37.637 + public void setMaximumFractionDigits(int newValue) {
37.638 + maximumFractionDigits = Math.max(0,newValue);
37.639 + if (maximumFractionDigits < minimumFractionDigits) {
37.640 + minimumFractionDigits = maximumFractionDigits;
37.641 + }
37.642 + }
37.643 +
37.644 + /**
37.645 + * Returns the minimum number of digits allowed in the fraction portion of a
37.646 + * number.
37.647 + * @see #setMinimumFractionDigits
37.648 + */
37.649 + public int getMinimumFractionDigits() {
37.650 + return minimumFractionDigits;
37.651 + }
37.652 +
37.653 + /**
37.654 + * Sets the minimum number of digits allowed in the fraction portion of a
37.655 + * number. minimumFractionDigits must be <= maximumFractionDigits. If the
37.656 + * new value for minimumFractionDigits exceeds the current value
37.657 + * of maximumFractionDigits, then maximumIntegerDigits will also be set to
37.658 + * the new value
37.659 + * @param newValue the minimum number of fraction digits to be shown; if
37.660 + * less than zero, then zero is used. The concrete subclass may enforce an
37.661 + * upper limit to this value appropriate to the numeric type being formatted.
37.662 + * @see #getMinimumFractionDigits
37.663 + */
37.664 + public void setMinimumFractionDigits(int newValue) {
37.665 + minimumFractionDigits = Math.max(0,newValue);
37.666 + if (maximumFractionDigits < minimumFractionDigits) {
37.667 + maximumFractionDigits = minimumFractionDigits;
37.668 + }
37.669 + }
37.670 +
37.671 + /**
37.672 + * Gets the currency used by this number format when formatting
37.673 + * currency values. The initial value is derived in a locale dependent
37.674 + * way. The returned value may be null if no valid
37.675 + * currency could be determined and no currency has been set using
37.676 + * {@link #setCurrency(java.util.Currency) setCurrency}.
37.677 + * <p>
37.678 + * The default implementation throws
37.679 + * <code>UnsupportedOperationException</code>.
37.680 + *
37.681 + * @return the currency used by this number format, or <code>null</code>
37.682 + * @exception UnsupportedOperationException if the number format class
37.683 + * doesn't implement currency formatting
37.684 + * @since 1.4
37.685 + */
37.686 + public Currency getCurrency() {
37.687 + throw new UnsupportedOperationException();
37.688 + }
37.689 +
37.690 + /**
37.691 + * Sets the currency used by this number format when formatting
37.692 + * currency values. This does not update the minimum or maximum
37.693 + * number of fraction digits used by the number format.
37.694 + * <p>
37.695 + * The default implementation throws
37.696 + * <code>UnsupportedOperationException</code>.
37.697 + *
37.698 + * @param currency the new currency to be used by this number format
37.699 + * @exception UnsupportedOperationException if the number format class
37.700 + * doesn't implement currency formatting
37.701 + * @exception NullPointerException if <code>currency</code> is null
37.702 + * @since 1.4
37.703 + */
37.704 + public void setCurrency(Currency currency) {
37.705 + throw new UnsupportedOperationException();
37.706 + }
37.707 +
37.708 + /**
37.709 + * Gets the {@link java.math.RoundingMode} used in this NumberFormat.
37.710 + * The default implementation of this method in NumberFormat
37.711 + * always throws {@link java.lang.UnsupportedOperationException}.
37.712 + * Subclasses which handle different rounding modes should override
37.713 + * this method.
37.714 + *
37.715 + * @exception UnsupportedOperationException The default implementation
37.716 + * always throws this exception
37.717 + * @return The <code>RoundingMode</code> used for this NumberFormat.
37.718 + * @see #setRoundingMode(RoundingMode)
37.719 + * @since 1.6
37.720 + */
37.721 + public RoundingMode getRoundingMode() {
37.722 + throw new UnsupportedOperationException();
37.723 + }
37.724 +
37.725 + /**
37.726 + * Sets the {@link java.math.RoundingMode} used in this NumberFormat.
37.727 + * The default implementation of this method in NumberFormat always
37.728 + * throws {@link java.lang.UnsupportedOperationException}.
37.729 + * Subclasses which handle different rounding modes should override
37.730 + * this method.
37.731 + *
37.732 + * @exception UnsupportedOperationException The default implementation
37.733 + * always throws this exception
37.734 + * @exception NullPointerException if <code>roundingMode</code> is null
37.735 + * @param roundingMode The <code>RoundingMode</code> to be used
37.736 + * @see #getRoundingMode()
37.737 + * @since 1.6
37.738 + */
37.739 + public void setRoundingMode(RoundingMode roundingMode) {
37.740 + throw new UnsupportedOperationException();
37.741 + }
37.742 +
37.743 + // =======================privates===============================
37.744 +
37.745 + private static NumberFormat getInstance(Locale desiredLocale,
37.746 + int choice) {
37.747 + // Check whether a provider can provide an implementation that's closer
37.748 + // to the requested locale than what the Java runtime itself can provide.
37.749 + LocaleServiceProviderPool pool =
37.750 + LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
37.751 + if (pool.hasProviders()) {
37.752 + NumberFormat providersInstance = pool.getLocalizedObject(
37.753 + NumberFormatGetter.INSTANCE,
37.754 + desiredLocale,
37.755 + choice);
37.756 + if (providersInstance != null) {
37.757 + return providersInstance;
37.758 + }
37.759 + }
37.760 +
37.761 + /* try the cache first */
37.762 + String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale);
37.763 + if (numberPatterns == null) { /* cache miss */
37.764 + ResourceBundle resource = LocaleData.getNumberFormatData(desiredLocale);
37.765 + numberPatterns = resource.getStringArray("NumberPatterns");
37.766 + /* update cache */
37.767 + cachedLocaleData.put(desiredLocale, numberPatterns);
37.768 + }
37.769 +
37.770 + DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
37.771 + int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
37.772 + DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
37.773 +
37.774 + if (choice == INTEGERSTYLE) {
37.775 + format.setMaximumFractionDigits(0);
37.776 + format.setDecimalSeparatorAlwaysShown(false);
37.777 + format.setParseIntegerOnly(true);
37.778 + } else if (choice == CURRENCYSTYLE) {
37.779 + format.adjustForCurrencyDefaultFractionDigits();
37.780 + }
37.781 +
37.782 + return format;
37.783 + }
37.784 +
37.785 + /**
37.786 + * First, read in the default serializable data.
37.787 + *
37.788 + * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
37.789 + * the stream was written by JDK 1.1,
37.790 + * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
37.791 + * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
37.792 + * since the <code>int</code> fields were not present in JDK 1.1.
37.793 + * Finally, set serialVersionOnStream back to the maximum allowed value so that
37.794 + * default serialization will work properly if this object is streamed out again.
37.795 + *
37.796 + * <p>If <code>minimumIntegerDigits</code> is greater than
37.797 + * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
37.798 + * is greater than <code>maximumFractionDigits</code>, then the stream data
37.799 + * is invalid and this method throws an <code>InvalidObjectException</code>.
37.800 + * In addition, if any of these values is negative, then this method throws
37.801 + * an <code>InvalidObjectException</code>.
37.802 + *
37.803 + * @since 1.2
37.804 + */
37.805 + private void readObject(ObjectInputStream stream)
37.806 + throws IOException, ClassNotFoundException
37.807 + {
37.808 + stream.defaultReadObject();
37.809 + if (serialVersionOnStream < 1) {
37.810 + // Didn't have additional int fields, reassign to use them.
37.811 + maximumIntegerDigits = maxIntegerDigits;
37.812 + minimumIntegerDigits = minIntegerDigits;
37.813 + maximumFractionDigits = maxFractionDigits;
37.814 + minimumFractionDigits = minFractionDigits;
37.815 + }
37.816 + if (minimumIntegerDigits > maximumIntegerDigits ||
37.817 + minimumFractionDigits > maximumFractionDigits ||
37.818 + minimumIntegerDigits < 0 || minimumFractionDigits < 0) {
37.819 + throw new InvalidObjectException("Digit count range invalid");
37.820 + }
37.821 + serialVersionOnStream = currentSerialVersion;
37.822 + }
37.823 +
37.824 + /**
37.825 + * Write out the default serializable data, after first setting
37.826 + * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
37.827 + * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
37.828 + * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
37.829 + * with the JDK 1.1 version of the stream format.
37.830 + *
37.831 + * @since 1.2
37.832 + */
37.833 + private void writeObject(ObjectOutputStream stream)
37.834 + throws IOException
37.835 + {
37.836 + maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ?
37.837 + Byte.MAX_VALUE : (byte)maximumIntegerDigits;
37.838 + minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ?
37.839 + Byte.MAX_VALUE : (byte)minimumIntegerDigits;
37.840 + maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ?
37.841 + Byte.MAX_VALUE : (byte)maximumFractionDigits;
37.842 + minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ?
37.843 + Byte.MAX_VALUE : (byte)minimumFractionDigits;
37.844 + stream.defaultWriteObject();
37.845 + }
37.846 +
37.847 + /**
37.848 + * Cache to hold the NumberPatterns of a Locale.
37.849 + */
37.850 + private static final Hashtable cachedLocaleData = new Hashtable(3);
37.851 +
37.852 + // Constants used by factory methods to specify a style of format.
37.853 + private static final int NUMBERSTYLE = 0;
37.854 + private static final int CURRENCYSTYLE = 1;
37.855 + private static final int PERCENTSTYLE = 2;
37.856 + private static final int SCIENTIFICSTYLE = 3;
37.857 + private static final int INTEGERSTYLE = 4;
37.858 +
37.859 + /**
37.860 + * True if the grouping (i.e. thousands) separator is used when
37.861 + * formatting and parsing numbers.
37.862 + *
37.863 + * @serial
37.864 + * @see #isGroupingUsed
37.865 + */
37.866 + private boolean groupingUsed = true;
37.867 +
37.868 + /**
37.869 + * The maximum number of digits allowed in the integer portion of a
37.870 + * number. <code>maxIntegerDigits</code> must be greater than or equal to
37.871 + * <code>minIntegerDigits</code>.
37.872 + * <p>
37.873 + * <strong>Note:</strong> This field exists only for serialization
37.874 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
37.875 + * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
37.876 + * When writing to a stream, <code>maxIntegerDigits</code> is set to
37.877 + * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
37.878 + * whichever is smaller. When reading from a stream, this field is used
37.879 + * only if <code>serialVersionOnStream</code> is less than 1.
37.880 + *
37.881 + * @serial
37.882 + * @see #getMaximumIntegerDigits
37.883 + */
37.884 + private byte maxIntegerDigits = 40;
37.885 +
37.886 + /**
37.887 + * The minimum number of digits allowed in the integer portion of a
37.888 + * number. <code>minimumIntegerDigits</code> must be less than or equal to
37.889 + * <code>maximumIntegerDigits</code>.
37.890 + * <p>
37.891 + * <strong>Note:</strong> This field exists only for serialization
37.892 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
37.893 + * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
37.894 + * When writing to a stream, <code>minIntegerDigits</code> is set to
37.895 + * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
37.896 + * whichever is smaller. When reading from a stream, this field is used
37.897 + * only if <code>serialVersionOnStream</code> is less than 1.
37.898 + *
37.899 + * @serial
37.900 + * @see #getMinimumIntegerDigits
37.901 + */
37.902 + private byte minIntegerDigits = 1;
37.903 +
37.904 + /**
37.905 + * The maximum number of digits allowed in the fractional portion of a
37.906 + * number. <code>maximumFractionDigits</code> must be greater than or equal to
37.907 + * <code>minimumFractionDigits</code>.
37.908 + * <p>
37.909 + * <strong>Note:</strong> This field exists only for serialization
37.910 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
37.911 + * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
37.912 + * When writing to a stream, <code>maxFractionDigits</code> is set to
37.913 + * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
37.914 + * whichever is smaller. When reading from a stream, this field is used
37.915 + * only if <code>serialVersionOnStream</code> is less than 1.
37.916 + *
37.917 + * @serial
37.918 + * @see #getMaximumFractionDigits
37.919 + */
37.920 + private byte maxFractionDigits = 3; // invariant, >= minFractionDigits
37.921 +
37.922 + /**
37.923 + * The minimum number of digits allowed in the fractional portion of a
37.924 + * number. <code>minimumFractionDigits</code> must be less than or equal to
37.925 + * <code>maximumFractionDigits</code>.
37.926 + * <p>
37.927 + * <strong>Note:</strong> This field exists only for serialization
37.928 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
37.929 + * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
37.930 + * When writing to a stream, <code>minFractionDigits</code> is set to
37.931 + * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
37.932 + * whichever is smaller. When reading from a stream, this field is used
37.933 + * only if <code>serialVersionOnStream</code> is less than 1.
37.934 + *
37.935 + * @serial
37.936 + * @see #getMinimumFractionDigits
37.937 + */
37.938 + private byte minFractionDigits = 0;
37.939 +
37.940 + /**
37.941 + * True if this format will parse numbers as integers only.
37.942 + *
37.943 + * @serial
37.944 + * @see #isParseIntegerOnly
37.945 + */
37.946 + private boolean parseIntegerOnly = false;
37.947 +
37.948 + // new fields for 1.2. byte is too small for integer digits.
37.949 +
37.950 + /**
37.951 + * The maximum number of digits allowed in the integer portion of a
37.952 + * number. <code>maximumIntegerDigits</code> must be greater than or equal to
37.953 + * <code>minimumIntegerDigits</code>.
37.954 + *
37.955 + * @serial
37.956 + * @since 1.2
37.957 + * @see #getMaximumIntegerDigits
37.958 + */
37.959 + private int maximumIntegerDigits = 40;
37.960 +
37.961 + /**
37.962 + * The minimum number of digits allowed in the integer portion of a
37.963 + * number. <code>minimumIntegerDigits</code> must be less than or equal to
37.964 + * <code>maximumIntegerDigits</code>.
37.965 + *
37.966 + * @serial
37.967 + * @since 1.2
37.968 + * @see #getMinimumIntegerDigits
37.969 + */
37.970 + private int minimumIntegerDigits = 1;
37.971 +
37.972 + /**
37.973 + * The maximum number of digits allowed in the fractional portion of a
37.974 + * number. <code>maximumFractionDigits</code> must be greater than or equal to
37.975 + * <code>minimumFractionDigits</code>.
37.976 + *
37.977 + * @serial
37.978 + * @since 1.2
37.979 + * @see #getMaximumFractionDigits
37.980 + */
37.981 + private int maximumFractionDigits = 3; // invariant, >= minFractionDigits
37.982 +
37.983 + /**
37.984 + * The minimum number of digits allowed in the fractional portion of a
37.985 + * number. <code>minimumFractionDigits</code> must be less than or equal to
37.986 + * <code>maximumFractionDigits</code>.
37.987 + *
37.988 + * @serial
37.989 + * @since 1.2
37.990 + * @see #getMinimumFractionDigits
37.991 + */
37.992 + private int minimumFractionDigits = 0;
37.993 +
37.994 + static final int currentSerialVersion = 1;
37.995 +
37.996 + /**
37.997 + * Describes the version of <code>NumberFormat</code> present on the stream.
37.998 + * Possible values are:
37.999 + * <ul>
37.1000 + * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
37.1001 + * In this version, the <code>int</code> fields such as
37.1002 + * <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
37.1003 + * fields such as <code>maxIntegerDigits</code> are used instead.
37.1004 + *
37.1005 + * <li><b>1</b>: the 1.2 version of the stream format. The values of the
37.1006 + * <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
37.1007 + * and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
37.1008 + * are used instead.
37.1009 + * </ul>
37.1010 + * When streaming out a <code>NumberFormat</code>, the most recent format
37.1011 + * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
37.1012 + * is always written.
37.1013 + *
37.1014 + * @serial
37.1015 + * @since 1.2
37.1016 + */
37.1017 + private int serialVersionOnStream = currentSerialVersion;
37.1018 +
37.1019 + // Removed "implements Cloneable" clause. Needs to update serialization
37.1020 + // ID for backward compatibility.
37.1021 + static final long serialVersionUID = -2308460125733713944L;
37.1022 +
37.1023 +
37.1024 + //
37.1025 + // class for AttributedCharacterIterator attributes
37.1026 + //
37.1027 + /**
37.1028 + * Defines constants that are used as attribute keys in the
37.1029 + * <code>AttributedCharacterIterator</code> returned
37.1030 + * from <code>NumberFormat.formatToCharacterIterator</code> and as
37.1031 + * field identifiers in <code>FieldPosition</code>.
37.1032 + *
37.1033 + * @since 1.4
37.1034 + */
37.1035 + public static class Field extends Format.Field {
37.1036 +
37.1037 + // Proclaim serial compatibility with 1.4 FCS
37.1038 + private static final long serialVersionUID = 7494728892700160890L;
37.1039 +
37.1040 + // table of all instances in this class, used by readResolve
37.1041 + private static final Map instanceMap = new HashMap(11);
37.1042 +
37.1043 + /**
37.1044 + * Creates a Field instance with the specified
37.1045 + * name.
37.1046 + *
37.1047 + * @param name Name of the attribute
37.1048 + */
37.1049 + protected Field(String name) {
37.1050 + super(name);
37.1051 + if (this.getClass() == NumberFormat.Field.class) {
37.1052 + instanceMap.put(name, this);
37.1053 + }
37.1054 + }
37.1055 +
37.1056 + /**
37.1057 + * Resolves instances being deserialized to the predefined constants.
37.1058 + *
37.1059 + * @throws InvalidObjectException if the constant could not be resolved.
37.1060 + * @return resolved NumberFormat.Field constant
37.1061 + */
37.1062 + protected Object readResolve() throws InvalidObjectException {
37.1063 + if (this.getClass() != NumberFormat.Field.class) {
37.1064 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
37.1065 + }
37.1066 +
37.1067 + Object instance = instanceMap.get(getName());
37.1068 + if (instance != null) {
37.1069 + return instance;
37.1070 + } else {
37.1071 + throw new InvalidObjectException("unknown attribute name");
37.1072 + }
37.1073 + }
37.1074 +
37.1075 + /**
37.1076 + * Constant identifying the integer field.
37.1077 + */
37.1078 + public static final Field INTEGER = new Field("integer");
37.1079 +
37.1080 + /**
37.1081 + * Constant identifying the fraction field.
37.1082 + */
37.1083 + public static final Field FRACTION = new Field("fraction");
37.1084 +
37.1085 + /**
37.1086 + * Constant identifying the exponent field.
37.1087 + */
37.1088 + public static final Field EXPONENT = new Field("exponent");
37.1089 +
37.1090 + /**
37.1091 + * Constant identifying the decimal separator field.
37.1092 + */
37.1093 + public static final Field DECIMAL_SEPARATOR =
37.1094 + new Field("decimal separator");
37.1095 +
37.1096 + /**
37.1097 + * Constant identifying the sign field.
37.1098 + */
37.1099 + public static final Field SIGN = new Field("sign");
37.1100 +
37.1101 + /**
37.1102 + * Constant identifying the grouping separator field.
37.1103 + */
37.1104 + public static final Field GROUPING_SEPARATOR =
37.1105 + new Field("grouping separator");
37.1106 +
37.1107 + /**
37.1108 + * Constant identifying the exponent symbol field.
37.1109 + */
37.1110 + public static final Field EXPONENT_SYMBOL = new
37.1111 + Field("exponent symbol");
37.1112 +
37.1113 + /**
37.1114 + * Constant identifying the percent field.
37.1115 + */
37.1116 + public static final Field PERCENT = new Field("percent");
37.1117 +
37.1118 + /**
37.1119 + * Constant identifying the permille field.
37.1120 + */
37.1121 + public static final Field PERMILLE = new Field("per mille");
37.1122 +
37.1123 + /**
37.1124 + * Constant identifying the currency field.
37.1125 + */
37.1126 + public static final Field CURRENCY = new Field("currency");
37.1127 +
37.1128 + /**
37.1129 + * Constant identifying the exponent sign field.
37.1130 + */
37.1131 + public static final Field EXPONENT_SIGN = new Field("exponent sign");
37.1132 + }
37.1133 +
37.1134 + /**
37.1135 + * Obtains a NumberFormat instance from a NumberFormatProvider implementation.
37.1136 + */
37.1137 + private static class NumberFormatGetter
37.1138 + implements LocaleServiceProviderPool.LocalizedObjectGetter<NumberFormatProvider,
37.1139 + NumberFormat> {
37.1140 + private static final NumberFormatGetter INSTANCE = new NumberFormatGetter();
37.1141 +
37.1142 + public NumberFormat getObject(NumberFormatProvider numberFormatProvider,
37.1143 + Locale locale,
37.1144 + String key,
37.1145 + Object... params) {
37.1146 + assert params.length == 1;
37.1147 + int choice = (Integer)params[0];
37.1148 +
37.1149 + switch (choice) {
37.1150 + case NUMBERSTYLE:
37.1151 + return numberFormatProvider.getNumberInstance(locale);
37.1152 + case PERCENTSTYLE:
37.1153 + return numberFormatProvider.getPercentInstance(locale);
37.1154 + case CURRENCYSTYLE:
37.1155 + return numberFormatProvider.getCurrencyInstance(locale);
37.1156 + case INTEGERSTYLE:
37.1157 + return numberFormatProvider.getIntegerInstance(locale);
37.1158 + default:
37.1159 + assert false : choice;
37.1160 + }
37.1161 +
37.1162 + return null;
37.1163 + }
37.1164 + }
37.1165 +}
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/rt/emul/compact/src/main/java/java/text/ParseException.java Thu Oct 03 15:43:10 2013 +0200
38.3 @@ -0,0 +1,78 @@
38.4 +/*
38.5 + * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
38.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
38.7 + *
38.8 + * This code is free software; you can redistribute it and/or modify it
38.9 + * under the terms of the GNU General Public License version 2 only, as
38.10 + * published by the Free Software Foundation. Oracle designates this
38.11 + * particular file as subject to the "Classpath" exception as provided
38.12 + * by Oracle in the LICENSE file that accompanied this code.
38.13 + *
38.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
38.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
38.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
38.17 + * version 2 for more details (a copy is included in the LICENSE file that
38.18 + * accompanied this code).
38.19 + *
38.20 + * You should have received a copy of the GNU General Public License version
38.21 + * 2 along with this work; if not, write to the Free Software Foundation,
38.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
38.23 + *
38.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
38.25 + * or visit www.oracle.com if you need additional information or have any
38.26 + * questions.
38.27 + */
38.28 +
38.29 +/*
38.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
38.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
38.32 + *
38.33 + * The original version of this source code and documentation is copyrighted
38.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
38.35 + * materials are provided under terms of a License Agreement between Taligent
38.36 + * and Sun. This technology is protected by multiple US and International
38.37 + * patents. This notice and attribution to Taligent may not be removed.
38.38 + * Taligent is a registered trademark of Taligent, Inc.
38.39 + *
38.40 + */
38.41 +
38.42 +package java.text;
38.43 +
38.44 +/**
38.45 + * Signals that an error has been reached unexpectedly
38.46 + * while parsing.
38.47 + * @see java.lang.Exception
38.48 + * @see java.text.Format
38.49 + * @see java.text.FieldPosition
38.50 + * @author Mark Davis
38.51 + */
38.52 +public
38.53 +class ParseException extends Exception {
38.54 +
38.55 + /**
38.56 + * Constructs a ParseException with the specified detail message and
38.57 + * offset.
38.58 + * A detail message is a String that describes this particular exception.
38.59 + * @param s the detail message
38.60 + * @param errorOffset the position where the error is found while parsing.
38.61 + */
38.62 + public ParseException(String s, int errorOffset) {
38.63 + super(s);
38.64 + this.errorOffset = errorOffset;
38.65 + }
38.66 +
38.67 + /**
38.68 + * Returns the position where the error was found.
38.69 + */
38.70 + public int getErrorOffset () {
38.71 + return errorOffset;
38.72 + }
38.73 +
38.74 + //============ privates ============
38.75 + /**
38.76 + * The zero-based character offset into the string being parsed at which
38.77 + * the error was found during parsing.
38.78 + * @serial
38.79 + */
38.80 + private int errorOffset;
38.81 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/rt/emul/compact/src/main/java/java/text/ParsePosition.java Thu Oct 03 15:43:10 2013 +0200
39.3 @@ -0,0 +1,139 @@
39.4 +/*
39.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
39.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
39.7 + *
39.8 + * This code is free software; you can redistribute it and/or modify it
39.9 + * under the terms of the GNU General Public License version 2 only, as
39.10 + * published by the Free Software Foundation. Oracle designates this
39.11 + * particular file as subject to the "Classpath" exception as provided
39.12 + * by Oracle in the LICENSE file that accompanied this code.
39.13 + *
39.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
39.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
39.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
39.17 + * version 2 for more details (a copy is included in the LICENSE file that
39.18 + * accompanied this code).
39.19 + *
39.20 + * You should have received a copy of the GNU General Public License version
39.21 + * 2 along with this work; if not, write to the Free Software Foundation,
39.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
39.23 + *
39.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
39.25 + * or visit www.oracle.com if you need additional information or have any
39.26 + * questions.
39.27 + */
39.28 +
39.29 +/*
39.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
39.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
39.32 + *
39.33 + * The original version of this source code and documentation is copyrighted
39.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
39.35 + * materials are provided under terms of a License Agreement between Taligent
39.36 + * and Sun. This technology is protected by multiple US and International
39.37 + * patents. This notice and attribution to Taligent may not be removed.
39.38 + * Taligent is a registered trademark of Taligent, Inc.
39.39 + *
39.40 + */
39.41 +
39.42 +package java.text;
39.43 +
39.44 +
39.45 +/**
39.46 + * <code>ParsePosition</code> is a simple class used by <code>Format</code>
39.47 + * and its subclasses to keep track of the current position during parsing.
39.48 + * The <code>parseObject</code> method in the various <code>Format</code>
39.49 + * classes requires a <code>ParsePosition</code> object as an argument.
39.50 + *
39.51 + * <p>
39.52 + * By design, as you parse through a string with different formats,
39.53 + * you can use the same <code>ParsePosition</code>, since the index parameter
39.54 + * records the current position.
39.55 + *
39.56 + * @author Mark Davis
39.57 + * @see java.text.Format
39.58 + */
39.59 +
39.60 +public class ParsePosition {
39.61 +
39.62 + /**
39.63 + * Input: the place you start parsing.
39.64 + * <br>Output: position where the parse stopped.
39.65 + * This is designed to be used serially,
39.66 + * with each call setting index up for the next one.
39.67 + */
39.68 + int index = 0;
39.69 + int errorIndex = -1;
39.70 +
39.71 + /**
39.72 + * Retrieve the current parse position. On input to a parse method, this
39.73 + * is the index of the character at which parsing will begin; on output, it
39.74 + * is the index of the character following the last character parsed.
39.75 + */
39.76 + public int getIndex() {
39.77 + return index;
39.78 + }
39.79 +
39.80 + /**
39.81 + * Set the current parse position.
39.82 + */
39.83 + public void setIndex(int index) {
39.84 + this.index = index;
39.85 + }
39.86 +
39.87 + /**
39.88 + * Create a new ParsePosition with the given initial index.
39.89 + */
39.90 + public ParsePosition(int index) {
39.91 + this.index = index;
39.92 + }
39.93 + /**
39.94 + * Set the index at which a parse error occurred. Formatters
39.95 + * should set this before returning an error code from their
39.96 + * parseObject method. The default value is -1 if this is not set.
39.97 + * @since 1.2
39.98 + */
39.99 + public void setErrorIndex(int ei)
39.100 + {
39.101 + errorIndex = ei;
39.102 + }
39.103 +
39.104 + /**
39.105 + * Retrieve the index at which an error occurred, or -1 if the
39.106 + * error index has not been set.
39.107 + * @since 1.2
39.108 + */
39.109 + public int getErrorIndex()
39.110 + {
39.111 + return errorIndex;
39.112 + }
39.113 + /**
39.114 + * Overrides equals
39.115 + */
39.116 + public boolean equals(Object obj)
39.117 + {
39.118 + if (obj == null) return false;
39.119 + if (!(obj instanceof ParsePosition))
39.120 + return false;
39.121 + ParsePosition other = (ParsePosition) obj;
39.122 + return (index == other.index && errorIndex == other.errorIndex);
39.123 + }
39.124 +
39.125 + /**
39.126 + * Returns a hash code for this ParsePosition.
39.127 + * @return a hash code value for this object
39.128 + */
39.129 + public int hashCode() {
39.130 + return (errorIndex << 16) | index;
39.131 + }
39.132 +
39.133 + /**
39.134 + * Return a string representation of this ParsePosition.
39.135 + * @return a string representation of this object
39.136 + */
39.137 + public String toString() {
39.138 + return getClass().getName() +
39.139 + "[index=" + index +
39.140 + ",errorIndex=" + errorIndex + ']';
39.141 + }
39.142 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/rt/emul/compact/src/main/java/java/text/SimpleDateFormat.java Thu Oct 03 15:43:10 2013 +0200
40.3 @@ -0,0 +1,2350 @@
40.4 +/*
40.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
40.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
40.7 + *
40.8 + * This code is free software; you can redistribute it and/or modify it
40.9 + * under the terms of the GNU General Public License version 2 only, as
40.10 + * published by the Free Software Foundation. Oracle designates this
40.11 + * particular file as subject to the "Classpath" exception as provided
40.12 + * by Oracle in the LICENSE file that accompanied this code.
40.13 + *
40.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
40.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
40.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
40.17 + * version 2 for more details (a copy is included in the LICENSE file that
40.18 + * accompanied this code).
40.19 + *
40.20 + * You should have received a copy of the GNU General Public License version
40.21 + * 2 along with this work; if not, write to the Free Software Foundation,
40.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
40.23 + *
40.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
40.25 + * or visit www.oracle.com if you need additional information or have any
40.26 + * questions.
40.27 + */
40.28 +
40.29 +/*
40.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
40.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
40.32 + *
40.33 + * The original version of this source code and documentation is copyrighted
40.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
40.35 + * materials are provided under terms of a License Agreement between Taligent
40.36 + * and Sun. This technology is protected by multiple US and International
40.37 + * patents. This notice and attribution to Taligent may not be removed.
40.38 + * Taligent is a registered trademark of Taligent, Inc.
40.39 + *
40.40 + */
40.41 +
40.42 +package java.text;
40.43 +
40.44 +import java.io.IOException;
40.45 +import java.io.InvalidObjectException;
40.46 +import java.io.ObjectInputStream;
40.47 +import java.util.Calendar;
40.48 +import java.util.Date;
40.49 +import java.util.GregorianCalendar;
40.50 +import java.util.Locale;
40.51 +import java.util.Map;
40.52 +import java.util.MissingResourceException;
40.53 +import java.util.ResourceBundle;
40.54 +import java.util.SimpleTimeZone;
40.55 +import java.util.TimeZone;
40.56 +import java.util.concurrent.ConcurrentHashMap;
40.57 +import java.util.concurrent.ConcurrentMap;
40.58 +import sun.util.calendar.CalendarUtils;
40.59 +import sun.util.calendar.ZoneInfoFile;
40.60 +import sun.util.resources.LocaleData;
40.61 +
40.62 +import static java.text.DateFormatSymbols.*;
40.63 +
40.64 +/**
40.65 + * <code>SimpleDateFormat</code> is a concrete class for formatting and
40.66 + * parsing dates in a locale-sensitive manner. It allows for formatting
40.67 + * (date -> text), parsing (text -> date), and normalization.
40.68 + *
40.69 + * <p>
40.70 + * <code>SimpleDateFormat</code> allows you to start by choosing
40.71 + * any user-defined patterns for date-time formatting. However, you
40.72 + * are encouraged to create a date-time formatter with either
40.73 + * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
40.74 + * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
40.75 + * of these class methods can return a date/time formatter initialized
40.76 + * with a default format pattern. You may modify the format pattern
40.77 + * using the <code>applyPattern</code> methods as desired.
40.78 + * For more information on using these methods, see
40.79 + * {@link DateFormat}.
40.80 + *
40.81 + * <h4>Date and Time Patterns</h4>
40.82 + * <p>
40.83 + * Date and time formats are specified by <em>date and time pattern</em>
40.84 + * strings.
40.85 + * Within date and time pattern strings, unquoted letters from
40.86 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
40.87 + * <code>'z'</code> are interpreted as pattern letters representing the
40.88 + * components of a date or time string.
40.89 + * Text can be quoted using single quotes (<code>'</code>) to avoid
40.90 + * interpretation.
40.91 + * <code>"''"</code> represents a single quote.
40.92 + * All other characters are not interpreted; they're simply copied into the
40.93 + * output string during formatting or matched against the input string
40.94 + * during parsing.
40.95 + * <p>
40.96 + * The following pattern letters are defined (all other characters from
40.97 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
40.98 + * <code>'z'</code> are reserved):
40.99 + * <blockquote>
40.100 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart shows pattern letters, date/time component, presentation, and examples.">
40.101 + * <tr bgcolor="#ccccff">
40.102 + * <th align=left>Letter
40.103 + * <th align=left>Date or Time Component
40.104 + * <th align=left>Presentation
40.105 + * <th align=left>Examples
40.106 + * <tr>
40.107 + * <td><code>G</code>
40.108 + * <td>Era designator
40.109 + * <td><a href="#text">Text</a>
40.110 + * <td><code>AD</code>
40.111 + * <tr bgcolor="#eeeeff">
40.112 + * <td><code>y</code>
40.113 + * <td>Year
40.114 + * <td><a href="#year">Year</a>
40.115 + * <td><code>1996</code>; <code>96</code>
40.116 + * <tr>
40.117 + * <td><code>Y</code>
40.118 + * <td>Week year
40.119 + * <td><a href="#year">Year</a>
40.120 + * <td><code>2009</code>; <code>09</code>
40.121 + * <tr bgcolor="#eeeeff">
40.122 + * <td><code>M</code>
40.123 + * <td>Month in year
40.124 + * <td><a href="#month">Month</a>
40.125 + * <td><code>July</code>; <code>Jul</code>; <code>07</code>
40.126 + * <tr>
40.127 + * <td><code>w</code>
40.128 + * <td>Week in year
40.129 + * <td><a href="#number">Number</a>
40.130 + * <td><code>27</code>
40.131 + * <tr bgcolor="#eeeeff">
40.132 + * <td><code>W</code>
40.133 + * <td>Week in month
40.134 + * <td><a href="#number">Number</a>
40.135 + * <td><code>2</code>
40.136 + * <tr>
40.137 + * <td><code>D</code>
40.138 + * <td>Day in year
40.139 + * <td><a href="#number">Number</a>
40.140 + * <td><code>189</code>
40.141 + * <tr bgcolor="#eeeeff">
40.142 + * <td><code>d</code>
40.143 + * <td>Day in month
40.144 + * <td><a href="#number">Number</a>
40.145 + * <td><code>10</code>
40.146 + * <tr>
40.147 + * <td><code>F</code>
40.148 + * <td>Day of week in month
40.149 + * <td><a href="#number">Number</a>
40.150 + * <td><code>2</code>
40.151 + * <tr bgcolor="#eeeeff">
40.152 + * <td><code>E</code>
40.153 + * <td>Day name in week
40.154 + * <td><a href="#text">Text</a>
40.155 + * <td><code>Tuesday</code>; <code>Tue</code>
40.156 + * <tr>
40.157 + * <td><code>u</code>
40.158 + * <td>Day number of week (1 = Monday, ..., 7 = Sunday)
40.159 + * <td><a href="#number">Number</a>
40.160 + * <td><code>1</code>
40.161 + * <tr bgcolor="#eeeeff">
40.162 + * <td><code>a</code>
40.163 + * <td>Am/pm marker
40.164 + * <td><a href="#text">Text</a>
40.165 + * <td><code>PM</code>
40.166 + * <tr>
40.167 + * <td><code>H</code>
40.168 + * <td>Hour in day (0-23)
40.169 + * <td><a href="#number">Number</a>
40.170 + * <td><code>0</code>
40.171 + * <tr bgcolor="#eeeeff">
40.172 + * <td><code>k</code>
40.173 + * <td>Hour in day (1-24)
40.174 + * <td><a href="#number">Number</a>
40.175 + * <td><code>24</code>
40.176 + * <tr>
40.177 + * <td><code>K</code>
40.178 + * <td>Hour in am/pm (0-11)
40.179 + * <td><a href="#number">Number</a>
40.180 + * <td><code>0</code>
40.181 + * <tr bgcolor="#eeeeff">
40.182 + * <td><code>h</code>
40.183 + * <td>Hour in am/pm (1-12)
40.184 + * <td><a href="#number">Number</a>
40.185 + * <td><code>12</code>
40.186 + * <tr>
40.187 + * <td><code>m</code>
40.188 + * <td>Minute in hour
40.189 + * <td><a href="#number">Number</a>
40.190 + * <td><code>30</code>
40.191 + * <tr bgcolor="#eeeeff">
40.192 + * <td><code>s</code>
40.193 + * <td>Second in minute
40.194 + * <td><a href="#number">Number</a>
40.195 + * <td><code>55</code>
40.196 + * <tr>
40.197 + * <td><code>S</code>
40.198 + * <td>Millisecond
40.199 + * <td><a href="#number">Number</a>
40.200 + * <td><code>978</code>
40.201 + * <tr bgcolor="#eeeeff">
40.202 + * <td><code>z</code>
40.203 + * <td>Time zone
40.204 + * <td><a href="#timezone">General time zone</a>
40.205 + * <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
40.206 + * <tr>
40.207 + * <td><code>Z</code>
40.208 + * <td>Time zone
40.209 + * <td><a href="#rfc822timezone">RFC 822 time zone</a>
40.210 + * <td><code>-0800</code>
40.211 + * <tr bgcolor="#eeeeff">
40.212 + * <td><code>X</code>
40.213 + * <td>Time zone
40.214 + * <td><a href="#iso8601timezone">ISO 8601 time zone</a>
40.215 + * <td><code>-08</code>; <code>-0800</code>; <code>-08:00</code>
40.216 + * </table>
40.217 + * </blockquote>
40.218 + * Pattern letters are usually repeated, as their number determines the
40.219 + * exact presentation:
40.220 + * <ul>
40.221 + * <li><strong><a name="text">Text:</a></strong>
40.222 + * For formatting, if the number of pattern letters is 4 or more,
40.223 + * the full form is used; otherwise a short or abbreviated form
40.224 + * is used if available.
40.225 + * For parsing, both forms are accepted, independent of the number
40.226 + * of pattern letters.<br><br></li>
40.227 + * <li><strong><a name="number">Number:</a></strong>
40.228 + * For formatting, the number of pattern letters is the minimum
40.229 + * number of digits, and shorter numbers are zero-padded to this amount.
40.230 + * For parsing, the number of pattern letters is ignored unless
40.231 + * it's needed to separate two adjacent fields.<br><br></li>
40.232 + * <li><strong><a name="year">Year:</a></strong>
40.233 + * If the formatter's {@link #getCalendar() Calendar} is the Gregorian
40.234 + * calendar, the following rules are applied.<br>
40.235 + * <ul>
40.236 + * <li>For formatting, if the number of pattern letters is 2, the year
40.237 + * is truncated to 2 digits; otherwise it is interpreted as a
40.238 + * <a href="#number">number</a>.
40.239 + * <li>For parsing, if the number of pattern letters is more than 2,
40.240 + * the year is interpreted literally, regardless of the number of
40.241 + * digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to
40.242 + * Jan 11, 12 A.D.
40.243 + * <li>For parsing with the abbreviated year pattern ("y" or "yy"),
40.244 + * <code>SimpleDateFormat</code> must interpret the abbreviated year
40.245 + * relative to some century. It does this by adjusting dates to be
40.246 + * within 80 years before and 20 years after the time the <code>SimpleDateFormat</code>
40.247 + * instance is created. For example, using a pattern of "MM/dd/yy" and a
40.248 + * <code>SimpleDateFormat</code> instance created on Jan 1, 1997, the string
40.249 + * "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
40.250 + * would be interpreted as May 4, 1964.
40.251 + * During parsing, only strings consisting of exactly two digits, as defined by
40.252 + * {@link Character#isDigit(char)}, will be parsed into the default century.
40.253 + * Any other numeric string, such as a one digit string, a three or more digit
40.254 + * string, or a two digit string that isn't all digits (for example, "-1"), is
40.255 + * interpreted literally. So "01/02/3" or "01/02/003" are parsed, using the
40.256 + * same pattern, as Jan 2, 3 AD. Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
40.257 + * </ul>
40.258 + * Otherwise, calendar system specific forms are applied.
40.259 + * For both formatting and parsing, if the number of pattern
40.260 + * letters is 4 or more, a calendar specific {@linkplain
40.261 + * Calendar#LONG long form} is used. Otherwise, a calendar
40.262 + * specific {@linkplain Calendar#SHORT short or abbreviated form}
40.263 + * is used.<br>
40.264 + * <br>
40.265 + * If week year {@code 'Y'} is specified and the {@linkplain
40.266 + * #getCalendar() calendar} doesn't support any <a
40.267 + * href="../util/GregorianCalendar.html#week_year"> week
40.268 + * years</a>, the calendar year ({@code 'y'}) is used instead. The
40.269 + * support of week years can be tested with a call to {@link
40.270 + * DateFormat#getCalendar() getCalendar()}.{@link
40.271 + * java.util.Calendar#isWeekDateSupported()
40.272 + * isWeekDateSupported()}.<br><br></li>
40.273 + * <li><strong><a name="month">Month:</a></strong>
40.274 + * If the number of pattern letters is 3 or more, the month is
40.275 + * interpreted as <a href="#text">text</a>; otherwise,
40.276 + * it is interpreted as a <a href="#number">number</a>.<br><br></li>
40.277 + * <li><strong><a name="timezone">General time zone:</a></strong>
40.278 + * Time zones are interpreted as <a href="#text">text</a> if they have
40.279 + * names. For time zones representing a GMT offset value, the
40.280 + * following syntax is used:
40.281 + * <pre>
40.282 + * <a name="GMTOffsetTimeZone"><i>GMTOffsetTimeZone:</i></a>
40.283 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
40.284 + * <i>Sign:</i> one of
40.285 + * <code>+ -</code>
40.286 + * <i>Hours:</i>
40.287 + * <i>Digit</i>
40.288 + * <i>Digit</i> <i>Digit</i>
40.289 + * <i>Minutes:</i>
40.290 + * <i>Digit</i> <i>Digit</i>
40.291 + * <i>Digit:</i> one of
40.292 + * <code>0 1 2 3 4 5 6 7 8 9</code></pre>
40.293 + * <i>Hours</i> must be between 0 and 23, and <i>Minutes</i> must be between
40.294 + * 00 and 59. The format is locale independent and digits must be taken
40.295 + * from the Basic Latin block of the Unicode standard.
40.296 + * <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
40.297 + * accepted.<br><br></li>
40.298 + * <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
40.299 + * For formatting, the RFC 822 4-digit time zone format is used:
40.300 + *
40.301 + * <pre>
40.302 + * <i>RFC822TimeZone:</i>
40.303 + * <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
40.304 + * <i>TwoDigitHours:</i>
40.305 + * <i>Digit Digit</i></pre>
40.306 + * <i>TwoDigitHours</i> must be between 00 and 23. Other definitions
40.307 + * are as for <a href="#timezone">general time zones</a>.
40.308 + *
40.309 + * <p>For parsing, <a href="#timezone">general time zones</a> are also
40.310 + * accepted.
40.311 + * <li><strong><a name="iso8601timezone">ISO 8601 Time zone:</a></strong>
40.312 + * The number of pattern letters designates the format for both formatting
40.313 + * and parsing as follows:
40.314 + * <pre>
40.315 + * <i>ISO8601TimeZone:</i>
40.316 + * <i>OneLetterISO8601TimeZone</i>
40.317 + * <i>TwoLetterISO8601TimeZone</i>
40.318 + * <i>ThreeLetterISO8601TimeZone</i>
40.319 + * <i>OneLetterISO8601TimeZone:</i>
40.320 + * <i>Sign</i> <i>TwoDigitHours</i>
40.321 + * {@code Z}
40.322 + * <i>TwoLetterISO8601TimeZone:</i>
40.323 + * <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
40.324 + * {@code Z}
40.325 + * <i>ThreeLetterISO8601TimeZone:</i>
40.326 + * <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
40.327 + * {@code Z}</pre>
40.328 + * Other definitions are as for <a href="#timezone">general time zones</a> or
40.329 + * <a href="#rfc822timezone">RFC 822 time zones</a>.
40.330 + *
40.331 + * <p>For formatting, if the offset value from GMT is 0, {@code "Z"} is
40.332 + * produced. If the number of pattern letters is 1, any fraction of an hour
40.333 + * is ignored. For example, if the pattern is {@code "X"} and the time zone is
40.334 + * {@code "GMT+05:30"}, {@code "+05"} is produced.
40.335 + *
40.336 + * <p>For parsing, {@code "Z"} is parsed as the UTC time zone designator.
40.337 + * <a href="#timezone">General time zones</a> are <em>not</em> accepted.
40.338 + *
40.339 + * <p>If the number of pattern letters is 4 or more, {@link
40.340 + * IllegalArgumentException} is thrown when constructing a {@code
40.341 + * SimpleDateFormat} or {@linkplain #applyPattern(String) applying a
40.342 + * pattern}.
40.343 + * </ul>
40.344 + * <code>SimpleDateFormat</code> also supports <em>localized date and time
40.345 + * pattern</em> strings. In these strings, the pattern letters described above
40.346 + * may be replaced with other, locale dependent, pattern letters.
40.347 + * <code>SimpleDateFormat</code> does not deal with the localization of text
40.348 + * other than the pattern letters; that's up to the client of the class.
40.349 + * <p>
40.350 + *
40.351 + * <h4>Examples</h4>
40.352 + *
40.353 + * The following examples show how date and time patterns are interpreted in
40.354 + * the U.S. locale. The given date and time are 2001-07-04 12:08:56 local time
40.355 + * in the U.S. Pacific Time time zone.
40.356 + * <blockquote>
40.357 + * <table border=0 cellspacing=3 cellpadding=0 summary="Examples of date and time patterns interpreted in the U.S. locale">
40.358 + * <tr bgcolor="#ccccff">
40.359 + * <th align=left>Date and Time Pattern
40.360 + * <th align=left>Result
40.361 + * <tr>
40.362 + * <td><code>"yyyy.MM.dd G 'at' HH:mm:ss z"</code>
40.363 + * <td><code>2001.07.04 AD at 12:08:56 PDT</code>
40.364 + * <tr bgcolor="#eeeeff">
40.365 + * <td><code>"EEE, MMM d, ''yy"</code>
40.366 + * <td><code>Wed, Jul 4, '01</code>
40.367 + * <tr>
40.368 + * <td><code>"h:mm a"</code>
40.369 + * <td><code>12:08 PM</code>
40.370 + * <tr bgcolor="#eeeeff">
40.371 + * <td><code>"hh 'o''clock' a, zzzz"</code>
40.372 + * <td><code>12 o'clock PM, Pacific Daylight Time</code>
40.373 + * <tr>
40.374 + * <td><code>"K:mm a, z"</code>
40.375 + * <td><code>0:08 PM, PDT</code>
40.376 + * <tr bgcolor="#eeeeff">
40.377 + * <td><code>"yyyyy.MMMMM.dd GGG hh:mm aaa"</code>
40.378 + * <td><code>02001.July.04 AD 12:08 PM</code>
40.379 + * <tr>
40.380 + * <td><code>"EEE, d MMM yyyy HH:mm:ss Z"</code>
40.381 + * <td><code>Wed, 4 Jul 2001 12:08:56 -0700</code>
40.382 + * <tr bgcolor="#eeeeff">
40.383 + * <td><code>"yyMMddHHmmssZ"</code>
40.384 + * <td><code>010704120856-0700</code>
40.385 + * <tr>
40.386 + * <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
40.387 + * <td><code>2001-07-04T12:08:56.235-0700</code>
40.388 + * <tr bgcolor="#eeeeff">
40.389 + * <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</code>
40.390 + * <td><code>2001-07-04T12:08:56.235-07:00</code>
40.391 + * <tr>
40.392 + * <td><code>"YYYY-'W'ww-u"</code>
40.393 + * <td><code>2001-W27-3</code>
40.394 + * </table>
40.395 + * </blockquote>
40.396 + *
40.397 + * <h4><a name="synchronization">Synchronization</a></h4>
40.398 + *
40.399 + * <p>
40.400 + * Date formats are not synchronized.
40.401 + * It is recommended to create separate format instances for each thread.
40.402 + * If multiple threads access a format concurrently, it must be synchronized
40.403 + * externally.
40.404 + *
40.405 + * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a>
40.406 + * @see java.util.Calendar
40.407 + * @see java.util.TimeZone
40.408 + * @see DateFormat
40.409 + * @see DateFormatSymbols
40.410 + * @author Mark Davis, Chen-Lieh Huang, Alan Liu
40.411 + */
40.412 +public class SimpleDateFormat extends DateFormat {
40.413 +
40.414 + // the official serial version ID which says cryptically
40.415 + // which version we're compatible with
40.416 + static final long serialVersionUID = 4774881970558875024L;
40.417 +
40.418 + // the internal serial version which says which version was written
40.419 + // - 0 (default) for version up to JDK 1.1.3
40.420 + // - 1 for version from JDK 1.1.4, which includes a new field
40.421 + static final int currentSerialVersion = 1;
40.422 +
40.423 + /**
40.424 + * The version of the serialized data on the stream. Possible values:
40.425 + * <ul>
40.426 + * <li><b>0</b> or not present on stream: JDK 1.1.3. This version
40.427 + * has no <code>defaultCenturyStart</code> on stream.
40.428 + * <li><b>1</b> JDK 1.1.4 or later. This version adds
40.429 + * <code>defaultCenturyStart</code>.
40.430 + * </ul>
40.431 + * When streaming out this class, the most recent format
40.432 + * and the highest allowable <code>serialVersionOnStream</code>
40.433 + * is written.
40.434 + * @serial
40.435 + * @since JDK1.1.4
40.436 + */
40.437 + private int serialVersionOnStream = currentSerialVersion;
40.438 +
40.439 + /**
40.440 + * The pattern string of this formatter. This is always a non-localized
40.441 + * pattern. May not be null. See class documentation for details.
40.442 + * @serial
40.443 + */
40.444 + private String pattern;
40.445 +
40.446 + /**
40.447 + * Saved numberFormat and pattern.
40.448 + * @see SimpleDateFormat#checkNegativeNumberExpression
40.449 + */
40.450 + transient private NumberFormat originalNumberFormat;
40.451 + transient private String originalNumberPattern;
40.452 +
40.453 + /**
40.454 + * The minus sign to be used with format and parse.
40.455 + */
40.456 + transient private char minusSign = '-';
40.457 +
40.458 + /**
40.459 + * True when a negative sign follows a number.
40.460 + * (True as default in Arabic.)
40.461 + */
40.462 + transient private boolean hasFollowingMinusSign = false;
40.463 +
40.464 + /**
40.465 + * The compiled pattern.
40.466 + */
40.467 + transient private char[] compiledPattern;
40.468 +
40.469 + /**
40.470 + * Tags for the compiled pattern.
40.471 + */
40.472 + private final static int TAG_QUOTE_ASCII_CHAR = 100;
40.473 + private final static int TAG_QUOTE_CHARS = 101;
40.474 +
40.475 + /**
40.476 + * Locale dependent digit zero.
40.477 + * @see #zeroPaddingNumber
40.478 + * @see java.text.DecimalFormatSymbols#getZeroDigit
40.479 + */
40.480 + transient private char zeroDigit;
40.481 +
40.482 + /**
40.483 + * The symbols used by this formatter for week names, month names,
40.484 + * etc. May not be null.
40.485 + * @serial
40.486 + * @see java.text.DateFormatSymbols
40.487 + */
40.488 + private DateFormatSymbols formatData;
40.489 +
40.490 + /**
40.491 + * We map dates with two-digit years into the century starting at
40.492 + * <code>defaultCenturyStart</code>, which may be any date. May
40.493 + * not be null.
40.494 + * @serial
40.495 + * @since JDK1.1.4
40.496 + */
40.497 + private Date defaultCenturyStart;
40.498 +
40.499 + transient private int defaultCenturyStartYear;
40.500 +
40.501 + private static final int MILLIS_PER_MINUTE = 60 * 1000;
40.502 +
40.503 + // For time zones that have no names, use strings GMT+minutes and
40.504 + // GMT-minutes. For instance, in France the time zone is GMT+60.
40.505 + private static final String GMT = "GMT";
40.506 +
40.507 + /**
40.508 + * Cache to hold the DateTimePatterns of a Locale.
40.509 + */
40.510 + private static final ConcurrentMap<Locale, String[]> cachedLocaleData
40.511 + = new ConcurrentHashMap<Locale, String[]>(3);
40.512 +
40.513 + /**
40.514 + * Cache NumberFormat instances with Locale key.
40.515 + */
40.516 + private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
40.517 + = new ConcurrentHashMap<Locale, NumberFormat>(3);
40.518 +
40.519 + /**
40.520 + * The Locale used to instantiate this
40.521 + * <code>SimpleDateFormat</code>. The value may be null if this object
40.522 + * has been created by an older <code>SimpleDateFormat</code> and
40.523 + * deserialized.
40.524 + *
40.525 + * @serial
40.526 + * @since 1.6
40.527 + */
40.528 + private Locale locale;
40.529 +
40.530 + /**
40.531 + * Indicates whether this <code>SimpleDateFormat</code> should use
40.532 + * the DateFormatSymbols. If true, the format and parse methods
40.533 + * use the DateFormatSymbols values. If false, the format and
40.534 + * parse methods call Calendar.getDisplayName or
40.535 + * Calendar.getDisplayNames.
40.536 + */
40.537 + transient boolean useDateFormatSymbols;
40.538 +
40.539 + /**
40.540 + * Constructs a <code>SimpleDateFormat</code> using the default pattern and
40.541 + * date format symbols for the default locale.
40.542 + * <b>Note:</b> This constructor may not support all locales.
40.543 + * For full coverage, use the factory methods in the {@link DateFormat}
40.544 + * class.
40.545 + */
40.546 + public SimpleDateFormat() {
40.547 + this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT));
40.548 + }
40.549 +
40.550 + /**
40.551 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
40.552 + * the default date format symbols for the default locale.
40.553 + * <b>Note:</b> This constructor may not support all locales.
40.554 + * For full coverage, use the factory methods in the {@link DateFormat}
40.555 + * class.
40.556 + *
40.557 + * @param pattern the pattern describing the date and time format
40.558 + * @exception NullPointerException if the given pattern is null
40.559 + * @exception IllegalArgumentException if the given pattern is invalid
40.560 + */
40.561 + public SimpleDateFormat(String pattern)
40.562 + {
40.563 + this(pattern, Locale.getDefault(Locale.Category.FORMAT));
40.564 + }
40.565 +
40.566 + /**
40.567 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
40.568 + * the default date format symbols for the given locale.
40.569 + * <b>Note:</b> This constructor may not support all locales.
40.570 + * For full coverage, use the factory methods in the {@link DateFormat}
40.571 + * class.
40.572 + *
40.573 + * @param pattern the pattern describing the date and time format
40.574 + * @param locale the locale whose date format symbols should be used
40.575 + * @exception NullPointerException if the given pattern or locale is null
40.576 + * @exception IllegalArgumentException if the given pattern is invalid
40.577 + */
40.578 + public SimpleDateFormat(String pattern, Locale locale)
40.579 + {
40.580 + if (pattern == null || locale == null) {
40.581 + throw new NullPointerException();
40.582 + }
40.583 +
40.584 + initializeCalendar(locale);
40.585 + this.pattern = pattern;
40.586 + this.formatData = DateFormatSymbols.getInstanceRef(locale);
40.587 + this.locale = locale;
40.588 + initialize(locale);
40.589 + }
40.590 +
40.591 + /**
40.592 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
40.593 + * date format symbols.
40.594 + *
40.595 + * @param pattern the pattern describing the date and time format
40.596 + * @param formatSymbols the date format symbols to be used for formatting
40.597 + * @exception NullPointerException if the given pattern or formatSymbols is null
40.598 + * @exception IllegalArgumentException if the given pattern is invalid
40.599 + */
40.600 + public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
40.601 + {
40.602 + if (pattern == null || formatSymbols == null) {
40.603 + throw new NullPointerException();
40.604 + }
40.605 +
40.606 + this.pattern = pattern;
40.607 + this.formatData = (DateFormatSymbols) formatSymbols.clone();
40.608 + this.locale = Locale.getDefault(Locale.Category.FORMAT);
40.609 + initializeCalendar(this.locale);
40.610 + initialize(this.locale);
40.611 + useDateFormatSymbols = true;
40.612 + }
40.613 +
40.614 + /* Package-private, called by DateFormat factory methods */
40.615 + SimpleDateFormat(int timeStyle, int dateStyle, Locale loc) {
40.616 + if (loc == null) {
40.617 + throw new NullPointerException();
40.618 + }
40.619 +
40.620 + this.locale = loc;
40.621 + // initialize calendar and related fields
40.622 + initializeCalendar(loc);
40.623 +
40.624 + /* try the cache first */
40.625 + String[] dateTimePatterns = cachedLocaleData.get(loc);
40.626 + if (dateTimePatterns == null) { /* cache miss */
40.627 + ResourceBundle r = LocaleData.getDateFormatData(loc);
40.628 + if (!isGregorianCalendar()) {
40.629 + try {
40.630 + dateTimePatterns = r.getStringArray(getCalendarName() + ".DateTimePatterns");
40.631 + } catch (MissingResourceException e) {
40.632 + }
40.633 + }
40.634 + if (dateTimePatterns == null) {
40.635 + dateTimePatterns = r.getStringArray("DateTimePatterns");
40.636 + }
40.637 + /* update cache */
40.638 + cachedLocaleData.putIfAbsent(loc, dateTimePatterns);
40.639 + }
40.640 + formatData = DateFormatSymbols.getInstanceRef(loc);
40.641 + if ((timeStyle >= 0) && (dateStyle >= 0)) {
40.642 + Object[] dateTimeArgs = {dateTimePatterns[timeStyle],
40.643 + dateTimePatterns[dateStyle + 4]};
40.644 + pattern = MessageFormat.format(dateTimePatterns[8], dateTimeArgs);
40.645 + }
40.646 + else if (timeStyle >= 0) {
40.647 + pattern = dateTimePatterns[timeStyle];
40.648 + }
40.649 + else if (dateStyle >= 0) {
40.650 + pattern = dateTimePatterns[dateStyle + 4];
40.651 + }
40.652 + else {
40.653 + throw new IllegalArgumentException("No date or time style specified");
40.654 + }
40.655 +
40.656 + initialize(loc);
40.657 + }
40.658 +
40.659 + /* Initialize compiledPattern and numberFormat fields */
40.660 + private void initialize(Locale loc) {
40.661 + // Verify and compile the given pattern.
40.662 + compiledPattern = compile(pattern);
40.663 +
40.664 + /* try the cache first */
40.665 + numberFormat = cachedNumberFormatData.get(loc);
40.666 + if (numberFormat == null) { /* cache miss */
40.667 + numberFormat = NumberFormat.getIntegerInstance(loc);
40.668 + numberFormat.setGroupingUsed(false);
40.669 +
40.670 + /* update cache */
40.671 + cachedNumberFormatData.putIfAbsent(loc, numberFormat);
40.672 + }
40.673 + numberFormat = (NumberFormat) numberFormat.clone();
40.674 +
40.675 + initializeDefaultCentury();
40.676 + }
40.677 +
40.678 + private void initializeCalendar(Locale loc) {
40.679 + if (calendar == null) {
40.680 + assert loc != null;
40.681 + // The format object must be constructed using the symbols for this zone.
40.682 + // However, the calendar should use the current default TimeZone.
40.683 + // If this is not contained in the locale zone strings, then the zone
40.684 + // will be formatted using generic GMT+/-H:MM nomenclature.
40.685 + calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
40.686 + }
40.687 + }
40.688 +
40.689 + /**
40.690 + * Returns the compiled form of the given pattern. The syntax of
40.691 + * the compiled pattern is:
40.692 + * <blockquote>
40.693 + * CompiledPattern:
40.694 + * EntryList
40.695 + * EntryList:
40.696 + * Entry
40.697 + * EntryList Entry
40.698 + * Entry:
40.699 + * TagField
40.700 + * TagField data
40.701 + * TagField:
40.702 + * Tag Length
40.703 + * TaggedData
40.704 + * Tag:
40.705 + * pattern_char_index
40.706 + * TAG_QUOTE_CHARS
40.707 + * Length:
40.708 + * short_length
40.709 + * long_length
40.710 + * TaggedData:
40.711 + * TAG_QUOTE_ASCII_CHAR ascii_char
40.712 + *
40.713 + * </blockquote>
40.714 + *
40.715 + * where `short_length' is an 8-bit unsigned integer between 0 and
40.716 + * 254. `long_length' is a sequence of an 8-bit integer 255 and a
40.717 + * 32-bit signed integer value which is split into upper and lower
40.718 + * 16-bit fields in two char's. `pattern_char_index' is an 8-bit
40.719 + * integer between 0 and 18. `ascii_char' is an 7-bit ASCII
40.720 + * character value. `data' depends on its Tag value.
40.721 + * <p>
40.722 + * If Length is short_length, Tag and short_length are packed in a
40.723 + * single char, as illustrated below.
40.724 + * <blockquote>
40.725 + * char[0] = (Tag << 8) | short_length;
40.726 + * </blockquote>
40.727 + *
40.728 + * If Length is long_length, Tag and 255 are packed in the first
40.729 + * char and a 32-bit integer, as illustrated below.
40.730 + * <blockquote>
40.731 + * char[0] = (Tag << 8) | 255;
40.732 + * char[1] = (char) (long_length >>> 16);
40.733 + * char[2] = (char) (long_length & 0xffff);
40.734 + * </blockquote>
40.735 + * <p>
40.736 + * If Tag is a pattern_char_index, its Length is the number of
40.737 + * pattern characters. For example, if the given pattern is
40.738 + * "yyyy", Tag is 1 and Length is 4, followed by no data.
40.739 + * <p>
40.740 + * If Tag is TAG_QUOTE_CHARS, its Length is the number of char's
40.741 + * following the TagField. For example, if the given pattern is
40.742 + * "'o''clock'", Length is 7 followed by a char sequence of
40.743 + * <code>o&nbs;'&nbs;c&nbs;l&nbs;o&nbs;c&nbs;k</code>.
40.744 + * <p>
40.745 + * TAG_QUOTE_ASCII_CHAR is a special tag and has an ASCII
40.746 + * character in place of Length. For example, if the given pattern
40.747 + * is "'o'", the TaggedData entry is
40.748 + * <code>((TAG_QUOTE_ASCII_CHAR&nbs;<<&nbs;8)&nbs;|&nbs;'o')</code>.
40.749 + *
40.750 + * @exception NullPointerException if the given pattern is null
40.751 + * @exception IllegalArgumentException if the given pattern is invalid
40.752 + */
40.753 + private char[] compile(String pattern) {
40.754 + int length = pattern.length();
40.755 + boolean inQuote = false;
40.756 + StringBuilder compiledPattern = new StringBuilder(length * 2);
40.757 + StringBuilder tmpBuffer = null;
40.758 + int count = 0;
40.759 + int lastTag = -1;
40.760 +
40.761 + for (int i = 0; i < length; i++) {
40.762 + char c = pattern.charAt(i);
40.763 +
40.764 + if (c == '\'') {
40.765 + // '' is treated as a single quote regardless of being
40.766 + // in a quoted section.
40.767 + if ((i + 1) < length) {
40.768 + c = pattern.charAt(i + 1);
40.769 + if (c == '\'') {
40.770 + i++;
40.771 + if (count != 0) {
40.772 + encode(lastTag, count, compiledPattern);
40.773 + lastTag = -1;
40.774 + count = 0;
40.775 + }
40.776 + if (inQuote) {
40.777 + tmpBuffer.append(c);
40.778 + } else {
40.779 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
40.780 + }
40.781 + continue;
40.782 + }
40.783 + }
40.784 + if (!inQuote) {
40.785 + if (count != 0) {
40.786 + encode(lastTag, count, compiledPattern);
40.787 + lastTag = -1;
40.788 + count = 0;
40.789 + }
40.790 + if (tmpBuffer == null) {
40.791 + tmpBuffer = new StringBuilder(length);
40.792 + } else {
40.793 + tmpBuffer.setLength(0);
40.794 + }
40.795 + inQuote = true;
40.796 + } else {
40.797 + int len = tmpBuffer.length();
40.798 + if (len == 1) {
40.799 + char ch = tmpBuffer.charAt(0);
40.800 + if (ch < 128) {
40.801 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch));
40.802 + } else {
40.803 + compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | 1));
40.804 + compiledPattern.append(ch);
40.805 + }
40.806 + } else {
40.807 + encode(TAG_QUOTE_CHARS, len, compiledPattern);
40.808 + compiledPattern.append(tmpBuffer);
40.809 + }
40.810 + inQuote = false;
40.811 + }
40.812 + continue;
40.813 + }
40.814 + if (inQuote) {
40.815 + tmpBuffer.append(c);
40.816 + continue;
40.817 + }
40.818 + if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
40.819 + if (count != 0) {
40.820 + encode(lastTag, count, compiledPattern);
40.821 + lastTag = -1;
40.822 + count = 0;
40.823 + }
40.824 + if (c < 128) {
40.825 + // In most cases, c would be a delimiter, such as ':'.
40.826 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
40.827 + } else {
40.828 + // Take any contiguous non-ASCII alphabet characters and
40.829 + // put them in a single TAG_QUOTE_CHARS.
40.830 + int j;
40.831 + for (j = i + 1; j < length; j++) {
40.832 + char d = pattern.charAt(j);
40.833 + if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) {
40.834 + break;
40.835 + }
40.836 + }
40.837 + compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | (j - i)));
40.838 + for (; i < j; i++) {
40.839 + compiledPattern.append(pattern.charAt(i));
40.840 + }
40.841 + i--;
40.842 + }
40.843 + continue;
40.844 + }
40.845 +
40.846 + int tag;
40.847 + if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
40.848 + throw new IllegalArgumentException("Illegal pattern character " +
40.849 + "'" + c + "'");
40.850 + }
40.851 + if (lastTag == -1 || lastTag == tag) {
40.852 + lastTag = tag;
40.853 + count++;
40.854 + continue;
40.855 + }
40.856 + encode(lastTag, count, compiledPattern);
40.857 + lastTag = tag;
40.858 + count = 1;
40.859 + }
40.860 +
40.861 + if (inQuote) {
40.862 + throw new IllegalArgumentException("Unterminated quote");
40.863 + }
40.864 +
40.865 + if (count != 0) {
40.866 + encode(lastTag, count, compiledPattern);
40.867 + }
40.868 +
40.869 + // Copy the compiled pattern to a char array
40.870 + int len = compiledPattern.length();
40.871 + char[] r = new char[len];
40.872 + compiledPattern.getChars(0, len, r, 0);
40.873 + return r;
40.874 + }
40.875 +
40.876 + /**
40.877 + * Encodes the given tag and length and puts encoded char(s) into buffer.
40.878 + */
40.879 + private static final void encode(int tag, int length, StringBuilder buffer) {
40.880 + if (tag == PATTERN_ISO_ZONE && length >= 4) {
40.881 + throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length);
40.882 + }
40.883 + if (length < 255) {
40.884 + buffer.append((char)(tag << 8 | length));
40.885 + } else {
40.886 + buffer.append((char)((tag << 8) | 0xff));
40.887 + buffer.append((char)(length >>> 16));
40.888 + buffer.append((char)(length & 0xffff));
40.889 + }
40.890 + }
40.891 +
40.892 + /* Initialize the fields we use to disambiguate ambiguous years. Separate
40.893 + * so we can call it from readObject().
40.894 + */
40.895 + private void initializeDefaultCentury() {
40.896 + calendar.setTimeInMillis(System.currentTimeMillis());
40.897 + calendar.add( Calendar.YEAR, -80 );
40.898 + parseAmbiguousDatesAsAfter(calendar.getTime());
40.899 + }
40.900 +
40.901 + /* Define one-century window into which to disambiguate dates using
40.902 + * two-digit years.
40.903 + */
40.904 + private void parseAmbiguousDatesAsAfter(Date startDate) {
40.905 + defaultCenturyStart = startDate;
40.906 + calendar.setTime(startDate);
40.907 + defaultCenturyStartYear = calendar.get(Calendar.YEAR);
40.908 + }
40.909 +
40.910 + /**
40.911 + * Sets the 100-year period 2-digit years will be interpreted as being in
40.912 + * to begin on the date the user specifies.
40.913 + *
40.914 + * @param startDate During parsing, two digit years will be placed in the range
40.915 + * <code>startDate</code> to <code>startDate + 100 years</code>.
40.916 + * @see #get2DigitYearStart
40.917 + * @since 1.2
40.918 + */
40.919 + public void set2DigitYearStart(Date startDate) {
40.920 + parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
40.921 + }
40.922 +
40.923 + /**
40.924 + * Returns the beginning date of the 100-year period 2-digit years are interpreted
40.925 + * as being within.
40.926 + *
40.927 + * @return the start of the 100-year period into which two digit years are
40.928 + * parsed
40.929 + * @see #set2DigitYearStart
40.930 + * @since 1.2
40.931 + */
40.932 + public Date get2DigitYearStart() {
40.933 + return (Date) defaultCenturyStart.clone();
40.934 + }
40.935 +
40.936 + /**
40.937 + * Formats the given <code>Date</code> into a date/time string and appends
40.938 + * the result to the given <code>StringBuffer</code>.
40.939 + *
40.940 + * @param date the date-time value to be formatted into a date-time string.
40.941 + * @param toAppendTo where the new date-time text is to be appended.
40.942 + * @param pos the formatting position. On input: an alignment field,
40.943 + * if desired. On output: the offsets of the alignment field.
40.944 + * @return the formatted date-time string.
40.945 + * @exception NullPointerException if the given {@code date} is {@code null}.
40.946 + */
40.947 + public StringBuffer format(Date date, StringBuffer toAppendTo,
40.948 + FieldPosition pos)
40.949 + {
40.950 + pos.beginIndex = pos.endIndex = 0;
40.951 + return format(date, toAppendTo, pos.getFieldDelegate());
40.952 + }
40.953 +
40.954 + // Called from Format after creating a FieldDelegate
40.955 + private StringBuffer format(Date date, StringBuffer toAppendTo,
40.956 + FieldDelegate delegate) {
40.957 + // Convert input date to time field list
40.958 + calendar.setTime(date);
40.959 +
40.960 + boolean useDateFormatSymbols = useDateFormatSymbols();
40.961 +
40.962 + for (int i = 0; i < compiledPattern.length; ) {
40.963 + int tag = compiledPattern[i] >>> 8;
40.964 + int count = compiledPattern[i++] & 0xff;
40.965 + if (count == 255) {
40.966 + count = compiledPattern[i++] << 16;
40.967 + count |= compiledPattern[i++];
40.968 + }
40.969 +
40.970 + switch (tag) {
40.971 + case TAG_QUOTE_ASCII_CHAR:
40.972 + toAppendTo.append((char)count);
40.973 + break;
40.974 +
40.975 + case TAG_QUOTE_CHARS:
40.976 + toAppendTo.append(compiledPattern, i, count);
40.977 + i += count;
40.978 + break;
40.979 +
40.980 + default:
40.981 + subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
40.982 + break;
40.983 + }
40.984 + }
40.985 + return toAppendTo;
40.986 + }
40.987 +
40.988 + /**
40.989 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
40.990 + * You can use the returned <code>AttributedCharacterIterator</code>
40.991 + * to build the resulting String, as well as to determine information
40.992 + * about the resulting String.
40.993 + * <p>
40.994 + * Each attribute key of the AttributedCharacterIterator will be of type
40.995 + * <code>DateFormat.Field</code>, with the corresponding attribute value
40.996 + * being the same as the attribute key.
40.997 + *
40.998 + * @exception NullPointerException if obj is null.
40.999 + * @exception IllegalArgumentException if the Format cannot format the
40.1000 + * given object, or if the Format's pattern string is invalid.
40.1001 + * @param obj The object to format
40.1002 + * @return AttributedCharacterIterator describing the formatted value.
40.1003 + * @since 1.4
40.1004 + */
40.1005 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
40.1006 + StringBuffer sb = new StringBuffer();
40.1007 + CharacterIteratorFieldDelegate delegate = new
40.1008 + CharacterIteratorFieldDelegate();
40.1009 +
40.1010 + if (obj instanceof Date) {
40.1011 + format((Date)obj, sb, delegate);
40.1012 + }
40.1013 + else if (obj instanceof Number) {
40.1014 + format(new Date(((Number)obj).longValue()), sb, delegate);
40.1015 + }
40.1016 + else if (obj == null) {
40.1017 + throw new NullPointerException(
40.1018 + "formatToCharacterIterator must be passed non-null object");
40.1019 + }
40.1020 + else {
40.1021 + throw new IllegalArgumentException(
40.1022 + "Cannot format given Object as a Date");
40.1023 + }
40.1024 + return delegate.getIterator(sb.toString());
40.1025 + }
40.1026 +
40.1027 + // Map index into pattern character string to Calendar field number
40.1028 + private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD =
40.1029 + {
40.1030 + Calendar.ERA, Calendar.YEAR, Calendar.MONTH, Calendar.DATE,
40.1031 + Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY, Calendar.MINUTE,
40.1032 + Calendar.SECOND, Calendar.MILLISECOND, Calendar.DAY_OF_WEEK,
40.1033 + Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
40.1034 + Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH,
40.1035 + Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
40.1036 + Calendar.ZONE_OFFSET,
40.1037 + // Pseudo Calendar fields
40.1038 + CalendarBuilder.WEEK_YEAR,
40.1039 + CalendarBuilder.ISO_DAY_OF_WEEK,
40.1040 + Calendar.ZONE_OFFSET
40.1041 + };
40.1042 +
40.1043 + // Map index into pattern character string to DateFormat field number
40.1044 + private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
40.1045 + DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD,
40.1046 + DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD,
40.1047 + DateFormat.HOUR_OF_DAY0_FIELD, DateFormat.MINUTE_FIELD,
40.1048 + DateFormat.SECOND_FIELD, DateFormat.MILLISECOND_FIELD,
40.1049 + DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD,
40.1050 + DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, DateFormat.WEEK_OF_YEAR_FIELD,
40.1051 + DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
40.1052 + DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD,
40.1053 + DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD,
40.1054 + DateFormat.YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD,
40.1055 + DateFormat.TIMEZONE_FIELD
40.1056 + };
40.1057 +
40.1058 + // Maps from DecimalFormatSymbols index to Field constant
40.1059 + private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = {
40.1060 + Field.ERA, Field.YEAR, Field.MONTH, Field.DAY_OF_MONTH,
40.1061 + Field.HOUR_OF_DAY1, Field.HOUR_OF_DAY0, Field.MINUTE,
40.1062 + Field.SECOND, Field.MILLISECOND, Field.DAY_OF_WEEK,
40.1063 + Field.DAY_OF_YEAR, Field.DAY_OF_WEEK_IN_MONTH,
40.1064 + Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH,
40.1065 + Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE,
40.1066 + Field.TIME_ZONE,
40.1067 + Field.YEAR, Field.DAY_OF_WEEK,
40.1068 + Field.TIME_ZONE
40.1069 + };
40.1070 +
40.1071 + /**
40.1072 + * Private member function that does the real date/time formatting.
40.1073 + */
40.1074 + private void subFormat(int patternCharIndex, int count,
40.1075 + FieldDelegate delegate, StringBuffer buffer,
40.1076 + boolean useDateFormatSymbols)
40.1077 + {
40.1078 + int maxIntCount = Integer.MAX_VALUE;
40.1079 + String current = null;
40.1080 + int beginOffset = buffer.length();
40.1081 +
40.1082 + int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
40.1083 + int value;
40.1084 + if (field == CalendarBuilder.WEEK_YEAR) {
40.1085 + if (calendar.isWeekDateSupported()) {
40.1086 + value = calendar.getWeekYear();
40.1087 + } else {
40.1088 + // use calendar year 'y' instead
40.1089 + patternCharIndex = PATTERN_YEAR;
40.1090 + field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
40.1091 + value = calendar.get(field);
40.1092 + }
40.1093 + } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
40.1094 + value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
40.1095 + } else {
40.1096 + value = calendar.get(field);
40.1097 + }
40.1098 +
40.1099 + int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
40.1100 + if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
40.1101 + current = calendar.getDisplayName(field, style, locale);
40.1102 + }
40.1103 +
40.1104 + // Note: zeroPaddingNumber() assumes that maxDigits is either
40.1105 + // 2 or maxIntCount. If we make any changes to this,
40.1106 + // zeroPaddingNumber() must be fixed.
40.1107 +
40.1108 + switch (patternCharIndex) {
40.1109 + case PATTERN_ERA: // 'G'
40.1110 + if (useDateFormatSymbols) {
40.1111 + String[] eras = formatData.getEras();
40.1112 + if (value < eras.length)
40.1113 + current = eras[value];
40.1114 + }
40.1115 + if (current == null)
40.1116 + current = "";
40.1117 + break;
40.1118 +
40.1119 + case PATTERN_WEEK_YEAR: // 'Y'
40.1120 + case PATTERN_YEAR: // 'y'
40.1121 + if (calendar instanceof GregorianCalendar) {
40.1122 + if (count != 2)
40.1123 + zeroPaddingNumber(value, count, maxIntCount, buffer);
40.1124 + else // count == 2
40.1125 + zeroPaddingNumber(value, 2, 2, buffer); // clip 1996 to 96
40.1126 + } else {
40.1127 + if (current == null) {
40.1128 + zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
40.1129 + maxIntCount, buffer);
40.1130 + }
40.1131 + }
40.1132 + break;
40.1133 +
40.1134 + case PATTERN_MONTH: // 'M'
40.1135 + if (useDateFormatSymbols) {
40.1136 + String[] months;
40.1137 + if (count >= 4) {
40.1138 + months = formatData.getMonths();
40.1139 + current = months[value];
40.1140 + } else if (count == 3) {
40.1141 + months = formatData.getShortMonths();
40.1142 + current = months[value];
40.1143 + }
40.1144 + } else {
40.1145 + if (count < 3) {
40.1146 + current = null;
40.1147 + }
40.1148 + }
40.1149 + if (current == null) {
40.1150 + zeroPaddingNumber(value+1, count, maxIntCount, buffer);
40.1151 + }
40.1152 + break;
40.1153 +
40.1154 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
40.1155 + if (current == null) {
40.1156 + if (value == 0)
40.1157 + zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1,
40.1158 + count, maxIntCount, buffer);
40.1159 + else
40.1160 + zeroPaddingNumber(value, count, maxIntCount, buffer);
40.1161 + }
40.1162 + break;
40.1163 +
40.1164 + case PATTERN_DAY_OF_WEEK: // 'E'
40.1165 + if (useDateFormatSymbols) {
40.1166 + String[] weekdays;
40.1167 + if (count >= 4) {
40.1168 + weekdays = formatData.getWeekdays();
40.1169 + current = weekdays[value];
40.1170 + } else { // count < 4, use abbreviated form if exists
40.1171 + weekdays = formatData.getShortWeekdays();
40.1172 + current = weekdays[value];
40.1173 + }
40.1174 + }
40.1175 + break;
40.1176 +
40.1177 + case PATTERN_AM_PM: // 'a'
40.1178 + if (useDateFormatSymbols) {
40.1179 + String[] ampm = formatData.getAmPmStrings();
40.1180 + current = ampm[value];
40.1181 + }
40.1182 + break;
40.1183 +
40.1184 + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
40.1185 + if (current == null) {
40.1186 + if (value == 0)
40.1187 + zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1,
40.1188 + count, maxIntCount, buffer);
40.1189 + else
40.1190 + zeroPaddingNumber(value, count, maxIntCount, buffer);
40.1191 + }
40.1192 + break;
40.1193 +
40.1194 + case PATTERN_ZONE_NAME: // 'z'
40.1195 + if (current == null) {
40.1196 + if (formatData.locale == null || formatData.isZoneStringsSet) {
40.1197 + int zoneIndex =
40.1198 + formatData.getZoneIndex(calendar.getTimeZone().getID());
40.1199 + if (zoneIndex == -1) {
40.1200 + value = calendar.get(Calendar.ZONE_OFFSET) +
40.1201 + calendar.get(Calendar.DST_OFFSET);
40.1202 + buffer.append(ZoneInfoFile.toCustomID(value));
40.1203 + } else {
40.1204 + int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3;
40.1205 + if (count < 4) {
40.1206 + // Use the short name
40.1207 + index++;
40.1208 + }
40.1209 + String[][] zoneStrings = formatData.getZoneStringsWrapper();
40.1210 + buffer.append(zoneStrings[zoneIndex][index]);
40.1211 + }
40.1212 + } else {
40.1213 + TimeZone tz = calendar.getTimeZone();
40.1214 + boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
40.1215 + int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
40.1216 + buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale));
40.1217 + }
40.1218 + }
40.1219 + break;
40.1220 +
40.1221 + case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
40.1222 + value = (calendar.get(Calendar.ZONE_OFFSET) +
40.1223 + calendar.get(Calendar.DST_OFFSET)) / 60000;
40.1224 +
40.1225 + int width = 4;
40.1226 + if (value >= 0) {
40.1227 + buffer.append('+');
40.1228 + } else {
40.1229 + width++;
40.1230 + }
40.1231 +
40.1232 + int num = (value / 60) * 100 + (value % 60);
40.1233 + CalendarUtils.sprintf0d(buffer, num, width);
40.1234 + break;
40.1235 +
40.1236 + case PATTERN_ISO_ZONE: // 'X'
40.1237 + value = calendar.get(Calendar.ZONE_OFFSET)
40.1238 + + calendar.get(Calendar.DST_OFFSET);
40.1239 +
40.1240 + if (value == 0) {
40.1241 + buffer.append('Z');
40.1242 + break;
40.1243 + }
40.1244 +
40.1245 + value /= 60000;
40.1246 + if (value >= 0) {
40.1247 + buffer.append('+');
40.1248 + } else {
40.1249 + buffer.append('-');
40.1250 + value = -value;
40.1251 + }
40.1252 +
40.1253 + CalendarUtils.sprintf0d(buffer, value / 60, 2);
40.1254 + if (count == 1) {
40.1255 + break;
40.1256 + }
40.1257 +
40.1258 + if (count == 3) {
40.1259 + buffer.append(':');
40.1260 + }
40.1261 + CalendarUtils.sprintf0d(buffer, value % 60, 2);
40.1262 + break;
40.1263 +
40.1264 + default:
40.1265 + // case PATTERN_DAY_OF_MONTH: // 'd'
40.1266 + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
40.1267 + // case PATTERN_MINUTE: // 'm'
40.1268 + // case PATTERN_SECOND: // 's'
40.1269 + // case PATTERN_MILLISECOND: // 'S'
40.1270 + // case PATTERN_DAY_OF_YEAR: // 'D'
40.1271 + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
40.1272 + // case PATTERN_WEEK_OF_YEAR: // 'w'
40.1273 + // case PATTERN_WEEK_OF_MONTH: // 'W'
40.1274 + // case PATTERN_HOUR0: // 'K' eg, 11PM + 1 hour =>> 0 AM
40.1275 + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' pseudo field, Monday = 1, ..., Sunday = 7
40.1276 + if (current == null) {
40.1277 + zeroPaddingNumber(value, count, maxIntCount, buffer);
40.1278 + }
40.1279 + break;
40.1280 + } // switch (patternCharIndex)
40.1281 +
40.1282 + if (current != null) {
40.1283 + buffer.append(current);
40.1284 + }
40.1285 +
40.1286 + int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex];
40.1287 + Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex];
40.1288 +
40.1289 + delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer);
40.1290 + }
40.1291 +
40.1292 + /**
40.1293 + * Formats a number with the specified minimum and maximum number of digits.
40.1294 + */
40.1295 + private final void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer)
40.1296 + {
40.1297 + // Optimization for 1, 2 and 4 digit numbers. This should
40.1298 + // cover most cases of formatting date/time related items.
40.1299 + // Note: This optimization code assumes that maxDigits is
40.1300 + // either 2 or Integer.MAX_VALUE (maxIntCount in format()).
40.1301 + try {
40.1302 + if (zeroDigit == 0) {
40.1303 + zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit();
40.1304 + }
40.1305 + if (value >= 0) {
40.1306 + if (value < 100 && minDigits >= 1 && minDigits <= 2) {
40.1307 + if (value < 10) {
40.1308 + if (minDigits == 2) {
40.1309 + buffer.append(zeroDigit);
40.1310 + }
40.1311 + buffer.append((char)(zeroDigit + value));
40.1312 + } else {
40.1313 + buffer.append((char)(zeroDigit + value / 10));
40.1314 + buffer.append((char)(zeroDigit + value % 10));
40.1315 + }
40.1316 + return;
40.1317 + } else if (value >= 1000 && value < 10000) {
40.1318 + if (minDigits == 4) {
40.1319 + buffer.append((char)(zeroDigit + value / 1000));
40.1320 + value %= 1000;
40.1321 + buffer.append((char)(zeroDigit + value / 100));
40.1322 + value %= 100;
40.1323 + buffer.append((char)(zeroDigit + value / 10));
40.1324 + buffer.append((char)(zeroDigit + value % 10));
40.1325 + return;
40.1326 + }
40.1327 + if (minDigits == 2 && maxDigits == 2) {
40.1328 + zeroPaddingNumber(value % 100, 2, 2, buffer);
40.1329 + return;
40.1330 + }
40.1331 + }
40.1332 + }
40.1333 + } catch (Exception e) {
40.1334 + }
40.1335 +
40.1336 + numberFormat.setMinimumIntegerDigits(minDigits);
40.1337 + numberFormat.setMaximumIntegerDigits(maxDigits);
40.1338 + numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE);
40.1339 + }
40.1340 +
40.1341 +
40.1342 + /**
40.1343 + * Parses text from a string to produce a <code>Date</code>.
40.1344 + * <p>
40.1345 + * The method attempts to parse text starting at the index given by
40.1346 + * <code>pos</code>.
40.1347 + * If parsing succeeds, then the index of <code>pos</code> is updated
40.1348 + * to the index after the last character used (parsing does not necessarily
40.1349 + * use all characters up to the end of the string), and the parsed
40.1350 + * date is returned. The updated <code>pos</code> can be used to
40.1351 + * indicate the starting point for the next call to this method.
40.1352 + * If an error occurs, then the index of <code>pos</code> is not
40.1353 + * changed, the error index of <code>pos</code> is set to the index of
40.1354 + * the character where the error occurred, and null is returned.
40.1355 + *
40.1356 + * <p>This parsing operation uses the {@link DateFormat#calendar
40.1357 + * calendar} to produce a {@code Date}. All of the {@code
40.1358 + * calendar}'s date-time fields are {@linkplain Calendar#clear()
40.1359 + * cleared} before parsing, and the {@code calendar}'s default
40.1360 + * values of the date-time fields are used for any missing
40.1361 + * date-time information. For example, the year value of the
40.1362 + * parsed {@code Date} is 1970 with {@link GregorianCalendar} if
40.1363 + * no year value is given from the parsing operation. The {@code
40.1364 + * TimeZone} value may be overwritten, depending on the given
40.1365 + * pattern and the time zone value in {@code text}. Any {@code
40.1366 + * TimeZone} value that has previously been set by a call to
40.1367 + * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
40.1368 + * to be restored for further operations.
40.1369 + *
40.1370 + * @param text A <code>String</code>, part of which should be parsed.
40.1371 + * @param pos A <code>ParsePosition</code> object with index and error
40.1372 + * index information as described above.
40.1373 + * @return A <code>Date</code> parsed from the string. In case of
40.1374 + * error, returns null.
40.1375 + * @exception NullPointerException if <code>text</code> or <code>pos</code> is null.
40.1376 + */
40.1377 + public Date parse(String text, ParsePosition pos)
40.1378 + {
40.1379 + checkNegativeNumberExpression();
40.1380 +
40.1381 + int start = pos.index;
40.1382 + int oldStart = start;
40.1383 + int textLength = text.length();
40.1384 +
40.1385 + boolean[] ambiguousYear = {false};
40.1386 +
40.1387 + CalendarBuilder calb = new CalendarBuilder();
40.1388 +
40.1389 + for (int i = 0; i < compiledPattern.length; ) {
40.1390 + int tag = compiledPattern[i] >>> 8;
40.1391 + int count = compiledPattern[i++] & 0xff;
40.1392 + if (count == 255) {
40.1393 + count = compiledPattern[i++] << 16;
40.1394 + count |= compiledPattern[i++];
40.1395 + }
40.1396 +
40.1397 + switch (tag) {
40.1398 + case TAG_QUOTE_ASCII_CHAR:
40.1399 + if (start >= textLength || text.charAt(start) != (char)count) {
40.1400 + pos.index = oldStart;
40.1401 + pos.errorIndex = start;
40.1402 + return null;
40.1403 + }
40.1404 + start++;
40.1405 + break;
40.1406 +
40.1407 + case TAG_QUOTE_CHARS:
40.1408 + while (count-- > 0) {
40.1409 + if (start >= textLength || text.charAt(start) != compiledPattern[i++]) {
40.1410 + pos.index = oldStart;
40.1411 + pos.errorIndex = start;
40.1412 + return null;
40.1413 + }
40.1414 + start++;
40.1415 + }
40.1416 + break;
40.1417 +
40.1418 + default:
40.1419 + // Peek the next pattern to determine if we need to
40.1420 + // obey the number of pattern letters for
40.1421 + // parsing. It's required when parsing contiguous
40.1422 + // digit text (e.g., "20010704") with a pattern which
40.1423 + // has no delimiters between fields, like "yyyyMMdd".
40.1424 + boolean obeyCount = false;
40.1425 +
40.1426 + // In Arabic, a minus sign for a negative number is put after
40.1427 + // the number. Even in another locale, a minus sign can be
40.1428 + // put after a number using DateFormat.setNumberFormat().
40.1429 + // If both the minus sign and the field-delimiter are '-',
40.1430 + // subParse() needs to determine whether a '-' after a number
40.1431 + // in the given text is a delimiter or is a minus sign for the
40.1432 + // preceding number. We give subParse() a clue based on the
40.1433 + // information in compiledPattern.
40.1434 + boolean useFollowingMinusSignAsDelimiter = false;
40.1435 +
40.1436 + if (i < compiledPattern.length) {
40.1437 + int nextTag = compiledPattern[i] >>> 8;
40.1438 + if (!(nextTag == TAG_QUOTE_ASCII_CHAR ||
40.1439 + nextTag == TAG_QUOTE_CHARS)) {
40.1440 + obeyCount = true;
40.1441 + }
40.1442 +
40.1443 + if (hasFollowingMinusSign &&
40.1444 + (nextTag == TAG_QUOTE_ASCII_CHAR ||
40.1445 + nextTag == TAG_QUOTE_CHARS)) {
40.1446 + int c;
40.1447 + if (nextTag == TAG_QUOTE_ASCII_CHAR) {
40.1448 + c = compiledPattern[i] & 0xff;
40.1449 + } else {
40.1450 + c = compiledPattern[i+1];
40.1451 + }
40.1452 +
40.1453 + if (c == minusSign) {
40.1454 + useFollowingMinusSignAsDelimiter = true;
40.1455 + }
40.1456 + }
40.1457 + }
40.1458 + start = subParse(text, start, tag, count, obeyCount,
40.1459 + ambiguousYear, pos,
40.1460 + useFollowingMinusSignAsDelimiter, calb);
40.1461 + if (start < 0) {
40.1462 + pos.index = oldStart;
40.1463 + return null;
40.1464 + }
40.1465 + }
40.1466 + }
40.1467 +
40.1468 + // At this point the fields of Calendar have been set. Calendar
40.1469 + // will fill in default values for missing fields when the time
40.1470 + // is computed.
40.1471 +
40.1472 + pos.index = start;
40.1473 +
40.1474 + Date parsedDate;
40.1475 + try {
40.1476 + parsedDate = calb.establish(calendar).getTime();
40.1477 + // If the year value is ambiguous,
40.1478 + // then the two-digit year == the default start year
40.1479 + if (ambiguousYear[0]) {
40.1480 + if (parsedDate.before(defaultCenturyStart)) {
40.1481 + parsedDate = calb.addYear(100).establish(calendar).getTime();
40.1482 + }
40.1483 + }
40.1484 + }
40.1485 + // An IllegalArgumentException will be thrown by Calendar.getTime()
40.1486 + // if any fields are out of range, e.g., MONTH == 17.
40.1487 + catch (IllegalArgumentException e) {
40.1488 + pos.errorIndex = start;
40.1489 + pos.index = oldStart;
40.1490 + return null;
40.1491 + }
40.1492 +
40.1493 + return parsedDate;
40.1494 + }
40.1495 +
40.1496 + /**
40.1497 + * Private code-size reduction function used by subParse.
40.1498 + * @param text the time text being parsed.
40.1499 + * @param start where to start parsing.
40.1500 + * @param field the date field being parsed.
40.1501 + * @param data the string array to parsed.
40.1502 + * @return the new start position if matching succeeded; a negative number
40.1503 + * indicating matching failure, otherwise.
40.1504 + */
40.1505 + private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
40.1506 + {
40.1507 + int i = 0;
40.1508 + int count = data.length;
40.1509 +
40.1510 + if (field == Calendar.DAY_OF_WEEK) i = 1;
40.1511 +
40.1512 + // There may be multiple strings in the data[] array which begin with
40.1513 + // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
40.1514 + // We keep track of the longest match, and return that. Note that this
40.1515 + // unfortunately requires us to test all array elements.
40.1516 + int bestMatchLength = 0, bestMatch = -1;
40.1517 + for (; i<count; ++i)
40.1518 + {
40.1519 + int length = data[i].length();
40.1520 + // Always compare if we have no match yet; otherwise only compare
40.1521 + // against potentially better matches (longer strings).
40.1522 + if (length > bestMatchLength &&
40.1523 + text.regionMatches(true, start, data[i], 0, length))
40.1524 + {
40.1525 + bestMatch = i;
40.1526 + bestMatchLength = length;
40.1527 + }
40.1528 + }
40.1529 + if (bestMatch >= 0)
40.1530 + {
40.1531 + calb.set(field, bestMatch);
40.1532 + return start + bestMatchLength;
40.1533 + }
40.1534 + return -start;
40.1535 + }
40.1536 +
40.1537 + /**
40.1538 + * Performs the same thing as matchString(String, int, int,
40.1539 + * String[]). This method takes a Map<String, Integer> instead of
40.1540 + * String[].
40.1541 + */
40.1542 + private int matchString(String text, int start, int field,
40.1543 + Map<String,Integer> data, CalendarBuilder calb) {
40.1544 + if (data != null) {
40.1545 + String bestMatch = null;
40.1546 +
40.1547 + for (String name : data.keySet()) {
40.1548 + int length = name.length();
40.1549 + if (bestMatch == null || length > bestMatch.length()) {
40.1550 + if (text.regionMatches(true, start, name, 0, length)) {
40.1551 + bestMatch = name;
40.1552 + }
40.1553 + }
40.1554 + }
40.1555 +
40.1556 + if (bestMatch != null) {
40.1557 + calb.set(field, data.get(bestMatch));
40.1558 + return start + bestMatch.length();
40.1559 + }
40.1560 + }
40.1561 + return -start;
40.1562 + }
40.1563 +
40.1564 + private int matchZoneString(String text, int start, String[] zoneNames) {
40.1565 + for (int i = 1; i <= 4; ++i) {
40.1566 + // Checking long and short zones [1 & 2],
40.1567 + // and long and short daylight [3 & 4].
40.1568 + String zoneName = zoneNames[i];
40.1569 + if (text.regionMatches(true, start,
40.1570 + zoneName, 0, zoneName.length())) {
40.1571 + return i;
40.1572 + }
40.1573 + }
40.1574 + return -1;
40.1575 + }
40.1576 +
40.1577 + private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
40.1578 + String[][] zoneStrings) {
40.1579 + int index = standardIndex + 2;
40.1580 + String zoneName = zoneStrings[zoneIndex][index];
40.1581 + if (text.regionMatches(true, start,
40.1582 + zoneName, 0, zoneName.length())) {
40.1583 + return true;
40.1584 + }
40.1585 + return false;
40.1586 + }
40.1587 +
40.1588 + /**
40.1589 + * find time zone 'text' matched zoneStrings and set to internal
40.1590 + * calendar.
40.1591 + */
40.1592 + private int subParseZoneString(String text, int start, CalendarBuilder calb) {
40.1593 + boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
40.1594 + TimeZone currentTimeZone = getTimeZone();
40.1595 +
40.1596 + // At this point, check for named time zones by looking through
40.1597 + // the locale data from the TimeZoneNames strings.
40.1598 + // Want to be able to parse both short and long forms.
40.1599 + int zoneIndex = formatData.getZoneIndex(currentTimeZone.getID());
40.1600 + TimeZone tz = null;
40.1601 + String[][] zoneStrings = formatData.getZoneStringsWrapper();
40.1602 + String[] zoneNames = null;
40.1603 + int nameIndex = 0;
40.1604 + if (zoneIndex != -1) {
40.1605 + zoneNames = zoneStrings[zoneIndex];
40.1606 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
40.1607 + if (nameIndex <= 2) {
40.1608 + // Check if the standard name (abbr) and the daylight name are the same.
40.1609 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
40.1610 + }
40.1611 + tz = TimeZone.getTimeZone(zoneNames[0]);
40.1612 + }
40.1613 + }
40.1614 + if (tz == null) {
40.1615 + zoneIndex = formatData.getZoneIndex(TimeZone.getDefault().getID());
40.1616 + if (zoneIndex != -1) {
40.1617 + zoneNames = zoneStrings[zoneIndex];
40.1618 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
40.1619 + if (nameIndex <= 2) {
40.1620 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
40.1621 + }
40.1622 + tz = TimeZone.getTimeZone(zoneNames[0]);
40.1623 + }
40.1624 + }
40.1625 + }
40.1626 +
40.1627 + if (tz == null) {
40.1628 + int len = zoneStrings.length;
40.1629 + for (int i = 0; i < len; i++) {
40.1630 + zoneNames = zoneStrings[i];
40.1631 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
40.1632 + if (nameIndex <= 2) {
40.1633 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
40.1634 + }
40.1635 + tz = TimeZone.getTimeZone(zoneNames[0]);
40.1636 + break;
40.1637 + }
40.1638 + }
40.1639 + }
40.1640 + if (tz != null) { // Matched any ?
40.1641 + if (!tz.equals(currentTimeZone)) {
40.1642 + setTimeZone(tz);
40.1643 + }
40.1644 + // If the time zone matched uses the same name
40.1645 + // (abbreviation) for both standard and daylight time,
40.1646 + // let the time zone in the Calendar decide which one.
40.1647 + //
40.1648 + // Also if tz.getDSTSaving() returns 0 for DST, use tz to
40.1649 + // determine the local time. (6645292)
40.1650 + int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
40.1651 + if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
40.1652 + calb.set(Calendar.ZONE_OFFSET, tz.getRawOffset())
40.1653 + .set(Calendar.DST_OFFSET, dstAmount);
40.1654 + }
40.1655 + return (start + zoneNames[nameIndex].length());
40.1656 + }
40.1657 + return 0;
40.1658 + }
40.1659 +
40.1660 + /**
40.1661 + * Parses numeric forms of time zone offset, such as "hh:mm", and
40.1662 + * sets calb to the parsed value.
40.1663 + *
40.1664 + * @param text the text to be parsed
40.1665 + * @param start the character position to start parsing
40.1666 + * @param sign 1: positive; -1: negative
40.1667 + * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
40.1668 + * @param colon true - colon required between hh and mm; false - no colon required
40.1669 + * @param calb a CalendarBuilder in which the parsed value is stored
40.1670 + * @return updated parsed position, or its negative value to indicate a parsing error
40.1671 + */
40.1672 + private int subParseNumericZone(String text, int start, int sign, int count,
40.1673 + boolean colon, CalendarBuilder calb) {
40.1674 + int index = start;
40.1675 +
40.1676 + parse:
40.1677 + try {
40.1678 + char c = text.charAt(index++);
40.1679 + // Parse hh
40.1680 + int hours;
40.1681 + if (!isDigit(c)) {
40.1682 + break parse;
40.1683 + }
40.1684 + hours = c - '0';
40.1685 + c = text.charAt(index++);
40.1686 + if (isDigit(c)) {
40.1687 + hours = hours * 10 + (c - '0');
40.1688 + } else {
40.1689 + // If no colon in RFC 822 or 'X' (ISO), two digits are
40.1690 + // required.
40.1691 + if (count > 0 || !colon) {
40.1692 + break parse;
40.1693 + }
40.1694 + --index;
40.1695 + }
40.1696 + if (hours > 23) {
40.1697 + break parse;
40.1698 + }
40.1699 + int minutes = 0;
40.1700 + if (count != 1) {
40.1701 + // Proceed with parsing mm
40.1702 + c = text.charAt(index++);
40.1703 + if (colon) {
40.1704 + if (c != ':') {
40.1705 + break parse;
40.1706 + }
40.1707 + c = text.charAt(index++);
40.1708 + }
40.1709 + if (!isDigit(c)) {
40.1710 + break parse;
40.1711 + }
40.1712 + minutes = c - '0';
40.1713 + c = text.charAt(index++);
40.1714 + if (!isDigit(c)) {
40.1715 + break parse;
40.1716 + }
40.1717 + minutes = minutes * 10 + (c - '0');
40.1718 + if (minutes > 59) {
40.1719 + break parse;
40.1720 + }
40.1721 + }
40.1722 + minutes += hours * 60;
40.1723 + calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
40.1724 + .set(Calendar.DST_OFFSET, 0);
40.1725 + return index;
40.1726 + } catch (IndexOutOfBoundsException e) {
40.1727 + }
40.1728 + return 1 - index; // -(index - 1)
40.1729 + }
40.1730 +
40.1731 + private boolean isDigit(char c) {
40.1732 + return c >= '0' && c <= '9';
40.1733 + }
40.1734 +
40.1735 + /**
40.1736 + * Private member function that converts the parsed date strings into
40.1737 + * timeFields. Returns -start (for ParsePosition) if failed.
40.1738 + * @param text the time text to be parsed.
40.1739 + * @param start where to start parsing.
40.1740 + * @param ch the pattern character for the date field text to be parsed.
40.1741 + * @param count the count of a pattern character.
40.1742 + * @param obeyCount if true, then the next field directly abuts this one,
40.1743 + * and we should use the count to know when to stop parsing.
40.1744 + * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
40.1745 + * is true, then a two-digit year was parsed and may need to be readjusted.
40.1746 + * @param origPos origPos.errorIndex is used to return an error index
40.1747 + * at which a parse error occurred, if matching failure occurs.
40.1748 + * @return the new start position if matching succeeded; -1 indicating
40.1749 + * matching failure, otherwise. In case matching failure occurred,
40.1750 + * an error index is set to origPos.errorIndex.
40.1751 + */
40.1752 + private int subParse(String text, int start, int patternCharIndex, int count,
40.1753 + boolean obeyCount, boolean[] ambiguousYear,
40.1754 + ParsePosition origPos,
40.1755 + boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
40.1756 + Number number = null;
40.1757 + int value = 0;
40.1758 + ParsePosition pos = new ParsePosition(0);
40.1759 + pos.index = start;
40.1760 + if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
40.1761 + // use calendar year 'y' instead
40.1762 + patternCharIndex = PATTERN_YEAR;
40.1763 + }
40.1764 + int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
40.1765 +
40.1766 + // If there are any spaces here, skip over them. If we hit the end
40.1767 + // of the string, then fail.
40.1768 + for (;;) {
40.1769 + if (pos.index >= text.length()) {
40.1770 + origPos.errorIndex = start;
40.1771 + return -1;
40.1772 + }
40.1773 + char c = text.charAt(pos.index);
40.1774 + if (c != ' ' && c != '\t') break;
40.1775 + ++pos.index;
40.1776 + }
40.1777 +
40.1778 + parsing:
40.1779 + {
40.1780 + // We handle a few special cases here where we need to parse
40.1781 + // a number value. We handle further, more generic cases below. We need
40.1782 + // to handle some of them here because some fields require extra processing on
40.1783 + // the parsed value.
40.1784 + if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
40.1785 + patternCharIndex == PATTERN_HOUR1 ||
40.1786 + (patternCharIndex == PATTERN_MONTH && count <= 2) ||
40.1787 + patternCharIndex == PATTERN_YEAR ||
40.1788 + patternCharIndex == PATTERN_WEEK_YEAR) {
40.1789 + // It would be good to unify this with the obeyCount logic below,
40.1790 + // but that's going to be difficult.
40.1791 + if (obeyCount) {
40.1792 + if ((start+count) > text.length()) {
40.1793 + break parsing;
40.1794 + }
40.1795 + number = numberFormat.parse(text.substring(0, start+count), pos);
40.1796 + } else {
40.1797 + number = numberFormat.parse(text, pos);
40.1798 + }
40.1799 + if (number == null) {
40.1800 + if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
40.1801 + break parsing;
40.1802 + }
40.1803 + } else {
40.1804 + value = number.intValue();
40.1805 +
40.1806 + if (useFollowingMinusSignAsDelimiter && (value < 0) &&
40.1807 + (((pos.index < text.length()) &&
40.1808 + (text.charAt(pos.index) != minusSign)) ||
40.1809 + ((pos.index == text.length()) &&
40.1810 + (text.charAt(pos.index-1) == minusSign)))) {
40.1811 + value = -value;
40.1812 + pos.index--;
40.1813 + }
40.1814 + }
40.1815 + }
40.1816 +
40.1817 + boolean useDateFormatSymbols = useDateFormatSymbols();
40.1818 +
40.1819 + int index;
40.1820 + switch (patternCharIndex) {
40.1821 + case PATTERN_ERA: // 'G'
40.1822 + if (useDateFormatSymbols) {
40.1823 + if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
40.1824 + return index;
40.1825 + }
40.1826 + } else {
40.1827 + Map<String, Integer> map = calendar.getDisplayNames(field,
40.1828 + Calendar.ALL_STYLES,
40.1829 + locale);
40.1830 + if ((index = matchString(text, start, field, map, calb)) > 0) {
40.1831 + return index;
40.1832 + }
40.1833 + }
40.1834 + break parsing;
40.1835 +
40.1836 + case PATTERN_WEEK_YEAR: // 'Y'
40.1837 + case PATTERN_YEAR: // 'y'
40.1838 + if (!(calendar instanceof GregorianCalendar)) {
40.1839 + // calendar might have text representations for year values,
40.1840 + // such as "\u5143" in JapaneseImperialCalendar.
40.1841 + int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
40.1842 + Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
40.1843 + if (map != null) {
40.1844 + if ((index = matchString(text, start, field, map, calb)) > 0) {
40.1845 + return index;
40.1846 + }
40.1847 + }
40.1848 + calb.set(field, value);
40.1849 + return pos.index;
40.1850 + }
40.1851 +
40.1852 + // If there are 3 or more YEAR pattern characters, this indicates
40.1853 + // that the year value is to be treated literally, without any
40.1854 + // two-digit year adjustments (e.g., from "01" to 2001). Otherwise
40.1855 + // we made adjustments to place the 2-digit year in the proper
40.1856 + // century, for parsed strings from "00" to "99". Any other string
40.1857 + // is treated literally: "2250", "-1", "1", "002".
40.1858 + if (count <= 2 && (pos.index - start) == 2
40.1859 + && Character.isDigit(text.charAt(start))
40.1860 + && Character.isDigit(text.charAt(start+1))) {
40.1861 + // Assume for example that the defaultCenturyStart is 6/18/1903.
40.1862 + // This means that two-digit years will be forced into the range
40.1863 + // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02
40.1864 + // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond
40.1865 + // to 1904, 1905, etc. If the year is 03, then it is 2003 if the
40.1866 + // other fields specify a date before 6/18, or 1903 if they specify a
40.1867 + // date afterwards. As a result, 03 is an ambiguous year. All other
40.1868 + // two-digit years are unambiguous.
40.1869 + int ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
40.1870 + ambiguousYear[0] = value == ambiguousTwoDigitYear;
40.1871 + value += (defaultCenturyStartYear/100)*100 +
40.1872 + (value < ambiguousTwoDigitYear ? 100 : 0);
40.1873 + }
40.1874 + calb.set(field, value);
40.1875 + return pos.index;
40.1876 +
40.1877 + case PATTERN_MONTH: // 'M'
40.1878 + if (count <= 2) // i.e., M or MM.
40.1879 + {
40.1880 + // Don't want to parse the month if it is a string
40.1881 + // while pattern uses numeric style: M or MM.
40.1882 + // [We computed 'value' above.]
40.1883 + calb.set(Calendar.MONTH, value - 1);
40.1884 + return pos.index;
40.1885 + }
40.1886 +
40.1887 + if (useDateFormatSymbols) {
40.1888 + // count >= 3 // i.e., MMM or MMMM
40.1889 + // Want to be able to parse both short and long forms.
40.1890 + // Try count == 4 first:
40.1891 + int newStart = 0;
40.1892 + if ((newStart = matchString(text, start, Calendar.MONTH,
40.1893 + formatData.getMonths(), calb)) > 0) {
40.1894 + return newStart;
40.1895 + }
40.1896 + // count == 4 failed, now try count == 3
40.1897 + if ((index = matchString(text, start, Calendar.MONTH,
40.1898 + formatData.getShortMonths(), calb)) > 0) {
40.1899 + return index;
40.1900 + }
40.1901 + } else {
40.1902 + Map<String, Integer> map = calendar.getDisplayNames(field,
40.1903 + Calendar.ALL_STYLES,
40.1904 + locale);
40.1905 + if ((index = matchString(text, start, field, map, calb)) > 0) {
40.1906 + return index;
40.1907 + }
40.1908 + }
40.1909 + break parsing;
40.1910 +
40.1911 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
40.1912 + if (!isLenient()) {
40.1913 + // Validate the hour value in non-lenient
40.1914 + if (value < 1 || value > 24) {
40.1915 + break parsing;
40.1916 + }
40.1917 + }
40.1918 + // [We computed 'value' above.]
40.1919 + if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1)
40.1920 + value = 0;
40.1921 + calb.set(Calendar.HOUR_OF_DAY, value);
40.1922 + return pos.index;
40.1923 +
40.1924 + case PATTERN_DAY_OF_WEEK: // 'E'
40.1925 + {
40.1926 + if (useDateFormatSymbols) {
40.1927 + // Want to be able to parse both short and long forms.
40.1928 + // Try count == 4 (DDDD) first:
40.1929 + int newStart = 0;
40.1930 + if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
40.1931 + formatData.getWeekdays(), calb)) > 0) {
40.1932 + return newStart;
40.1933 + }
40.1934 + // DDDD failed, now try DDD
40.1935 + if ((index = matchString(text, start, Calendar.DAY_OF_WEEK,
40.1936 + formatData.getShortWeekdays(), calb)) > 0) {
40.1937 + return index;
40.1938 + }
40.1939 + } else {
40.1940 + int[] styles = { Calendar.LONG, Calendar.SHORT };
40.1941 + for (int style : styles) {
40.1942 + Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
40.1943 + if ((index = matchString(text, start, field, map, calb)) > 0) {
40.1944 + return index;
40.1945 + }
40.1946 + }
40.1947 + }
40.1948 + }
40.1949 + break parsing;
40.1950 +
40.1951 + case PATTERN_AM_PM: // 'a'
40.1952 + if (useDateFormatSymbols) {
40.1953 + if ((index = matchString(text, start, Calendar.AM_PM,
40.1954 + formatData.getAmPmStrings(), calb)) > 0) {
40.1955 + return index;
40.1956 + }
40.1957 + } else {
40.1958 + Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
40.1959 + if ((index = matchString(text, start, field, map, calb)) > 0) {
40.1960 + return index;
40.1961 + }
40.1962 + }
40.1963 + break parsing;
40.1964 +
40.1965 + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
40.1966 + if (!isLenient()) {
40.1967 + // Validate the hour value in non-lenient
40.1968 + if (value < 1 || value > 12) {
40.1969 + break parsing;
40.1970 + }
40.1971 + }
40.1972 + // [We computed 'value' above.]
40.1973 + if (value == calendar.getLeastMaximum(Calendar.HOUR)+1)
40.1974 + value = 0;
40.1975 + calb.set(Calendar.HOUR, value);
40.1976 + return pos.index;
40.1977 +
40.1978 + case PATTERN_ZONE_NAME: // 'z'
40.1979 + case PATTERN_ZONE_VALUE: // 'Z'
40.1980 + {
40.1981 + int sign = 0;
40.1982 + try {
40.1983 + char c = text.charAt(pos.index);
40.1984 + if (c == '+') {
40.1985 + sign = 1;
40.1986 + } else if (c == '-') {
40.1987 + sign = -1;
40.1988 + }
40.1989 + if (sign == 0) {
40.1990 + // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
40.1991 + if ((c == 'G' || c == 'g')
40.1992 + && (text.length() - start) >= GMT.length()
40.1993 + && text.regionMatches(true, start, GMT, 0, GMT.length())) {
40.1994 + pos.index = start + GMT.length();
40.1995 +
40.1996 + if ((text.length() - pos.index) > 0) {
40.1997 + c = text.charAt(pos.index);
40.1998 + if (c == '+') {
40.1999 + sign = 1;
40.2000 + } else if (c == '-') {
40.2001 + sign = -1;
40.2002 + }
40.2003 + }
40.2004 +
40.2005 + if (sign == 0) { /* "GMT" without offset */
40.2006 + calb.set(Calendar.ZONE_OFFSET, 0)
40.2007 + .set(Calendar.DST_OFFSET, 0);
40.2008 + return pos.index;
40.2009 + }
40.2010 +
40.2011 + // Parse the rest as "hh:mm"
40.2012 + int i = subParseNumericZone(text, ++pos.index,
40.2013 + sign, 0, true, calb);
40.2014 + if (i > 0) {
40.2015 + return i;
40.2016 + }
40.2017 + pos.index = -i;
40.2018 + } else {
40.2019 + // Try parsing the text as a time zone
40.2020 + // name or abbreviation.
40.2021 + int i = subParseZoneString(text, pos.index, calb);
40.2022 + if (i > 0) {
40.2023 + return i;
40.2024 + }
40.2025 + pos.index = -i;
40.2026 + }
40.2027 + } else {
40.2028 + // Parse the rest as "hhmm" (RFC 822)
40.2029 + int i = subParseNumericZone(text, ++pos.index,
40.2030 + sign, 0, false, calb);
40.2031 + if (i > 0) {
40.2032 + return i;
40.2033 + }
40.2034 + pos.index = -i;
40.2035 + }
40.2036 + } catch (IndexOutOfBoundsException e) {
40.2037 + }
40.2038 + }
40.2039 + break parsing;
40.2040 +
40.2041 + case PATTERN_ISO_ZONE: // 'X'
40.2042 + {
40.2043 + if ((text.length() - pos.index) <= 0) {
40.2044 + break parsing;
40.2045 + }
40.2046 +
40.2047 + int sign = 0;
40.2048 + char c = text.charAt(pos.index);
40.2049 + if (c == 'Z') {
40.2050 + calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
40.2051 + return ++pos.index;
40.2052 + }
40.2053 +
40.2054 + // parse text as "+/-hh[[:]mm]" based on count
40.2055 + if (c == '+') {
40.2056 + sign = 1;
40.2057 + } else if (c == '-') {
40.2058 + sign = -1;
40.2059 + } else {
40.2060 + ++pos.index;
40.2061 + break parsing;
40.2062 + }
40.2063 + int i = subParseNumericZone(text, ++pos.index, sign, count,
40.2064 + count == 3, calb);
40.2065 + if (i > 0) {
40.2066 + return i;
40.2067 + }
40.2068 + pos.index = -i;
40.2069 + }
40.2070 + break parsing;
40.2071 +
40.2072 + default:
40.2073 + // case PATTERN_DAY_OF_MONTH: // 'd'
40.2074 + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
40.2075 + // case PATTERN_MINUTE: // 'm'
40.2076 + // case PATTERN_SECOND: // 's'
40.2077 + // case PATTERN_MILLISECOND: // 'S'
40.2078 + // case PATTERN_DAY_OF_YEAR: // 'D'
40.2079 + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
40.2080 + // case PATTERN_WEEK_OF_YEAR: // 'w'
40.2081 + // case PATTERN_WEEK_OF_MONTH: // 'W'
40.2082 + // case PATTERN_HOUR0: // 'K' 0-based. eg, 11PM + 1 hour =>> 0 AM
40.2083 + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' (pseudo field);
40.2084 +
40.2085 + // Handle "generic" fields
40.2086 + if (obeyCount) {
40.2087 + if ((start+count) > text.length()) {
40.2088 + break parsing;
40.2089 + }
40.2090 + number = numberFormat.parse(text.substring(0, start+count), pos);
40.2091 + } else {
40.2092 + number = numberFormat.parse(text, pos);
40.2093 + }
40.2094 + if (number != null) {
40.2095 + value = number.intValue();
40.2096 +
40.2097 + if (useFollowingMinusSignAsDelimiter && (value < 0) &&
40.2098 + (((pos.index < text.length()) &&
40.2099 + (text.charAt(pos.index) != minusSign)) ||
40.2100 + ((pos.index == text.length()) &&
40.2101 + (text.charAt(pos.index-1) == minusSign)))) {
40.2102 + value = -value;
40.2103 + pos.index--;
40.2104 + }
40.2105 +
40.2106 + calb.set(field, value);
40.2107 + return pos.index;
40.2108 + }
40.2109 + break parsing;
40.2110 + }
40.2111 + }
40.2112 +
40.2113 + // Parsing failed.
40.2114 + origPos.errorIndex = pos.index;
40.2115 + return -1;
40.2116 + }
40.2117 +
40.2118 + private final String getCalendarName() {
40.2119 + return calendar.getClass().getName();
40.2120 + }
40.2121 +
40.2122 + private boolean useDateFormatSymbols() {
40.2123 + if (useDateFormatSymbols) {
40.2124 + return true;
40.2125 + }
40.2126 + return isGregorianCalendar() || locale == null;
40.2127 + }
40.2128 +
40.2129 + private boolean isGregorianCalendar() {
40.2130 + return "java.util.GregorianCalendar".equals(getCalendarName());
40.2131 + }
40.2132 +
40.2133 + /**
40.2134 + * Translates a pattern, mapping each character in the from string to the
40.2135 + * corresponding character in the to string.
40.2136 + *
40.2137 + * @exception IllegalArgumentException if the given pattern is invalid
40.2138 + */
40.2139 + private String translatePattern(String pattern, String from, String to) {
40.2140 + StringBuilder result = new StringBuilder();
40.2141 + boolean inQuote = false;
40.2142 + for (int i = 0; i < pattern.length(); ++i) {
40.2143 + char c = pattern.charAt(i);
40.2144 + if (inQuote) {
40.2145 + if (c == '\'')
40.2146 + inQuote = false;
40.2147 + }
40.2148 + else {
40.2149 + if (c == '\'')
40.2150 + inQuote = true;
40.2151 + else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
40.2152 + int ci = from.indexOf(c);
40.2153 + if (ci >= 0) {
40.2154 + // patternChars is longer than localPatternChars due
40.2155 + // to serialization compatibility. The pattern letters
40.2156 + // unsupported by localPatternChars pass through.
40.2157 + if (ci < to.length()) {
40.2158 + c = to.charAt(ci);
40.2159 + }
40.2160 + } else {
40.2161 + throw new IllegalArgumentException("Illegal pattern " +
40.2162 + " character '" +
40.2163 + c + "'");
40.2164 + }
40.2165 + }
40.2166 + }
40.2167 + result.append(c);
40.2168 + }
40.2169 + if (inQuote)
40.2170 + throw new IllegalArgumentException("Unfinished quote in pattern");
40.2171 + return result.toString();
40.2172 + }
40.2173 +
40.2174 + /**
40.2175 + * Returns a pattern string describing this date format.
40.2176 + *
40.2177 + * @return a pattern string describing this date format.
40.2178 + */
40.2179 + public String toPattern() {
40.2180 + return pattern;
40.2181 + }
40.2182 +
40.2183 + /**
40.2184 + * Returns a localized pattern string describing this date format.
40.2185 + *
40.2186 + * @return a localized pattern string describing this date format.
40.2187 + */
40.2188 + public String toLocalizedPattern() {
40.2189 + return translatePattern(pattern,
40.2190 + DateFormatSymbols.patternChars,
40.2191 + formatData.getLocalPatternChars());
40.2192 + }
40.2193 +
40.2194 + /**
40.2195 + * Applies the given pattern string to this date format.
40.2196 + *
40.2197 + * @param pattern the new date and time pattern for this date format
40.2198 + * @exception NullPointerException if the given pattern is null
40.2199 + * @exception IllegalArgumentException if the given pattern is invalid
40.2200 + */
40.2201 + public void applyPattern(String pattern)
40.2202 + {
40.2203 + compiledPattern = compile(pattern);
40.2204 + this.pattern = pattern;
40.2205 + }
40.2206 +
40.2207 + /**
40.2208 + * Applies the given localized pattern string to this date format.
40.2209 + *
40.2210 + * @param pattern a String to be mapped to the new date and time format
40.2211 + * pattern for this format
40.2212 + * @exception NullPointerException if the given pattern is null
40.2213 + * @exception IllegalArgumentException if the given pattern is invalid
40.2214 + */
40.2215 + public void applyLocalizedPattern(String pattern) {
40.2216 + String p = translatePattern(pattern,
40.2217 + formatData.getLocalPatternChars(),
40.2218 + DateFormatSymbols.patternChars);
40.2219 + compiledPattern = compile(p);
40.2220 + this.pattern = p;
40.2221 + }
40.2222 +
40.2223 + /**
40.2224 + * Gets a copy of the date and time format symbols of this date format.
40.2225 + *
40.2226 + * @return the date and time format symbols of this date format
40.2227 + * @see #setDateFormatSymbols
40.2228 + */
40.2229 + public DateFormatSymbols getDateFormatSymbols()
40.2230 + {
40.2231 + return (DateFormatSymbols)formatData.clone();
40.2232 + }
40.2233 +
40.2234 + /**
40.2235 + * Sets the date and time format symbols of this date format.
40.2236 + *
40.2237 + * @param newFormatSymbols the new date and time format symbols
40.2238 + * @exception NullPointerException if the given newFormatSymbols is null
40.2239 + * @see #getDateFormatSymbols
40.2240 + */
40.2241 + public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
40.2242 + {
40.2243 + this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
40.2244 + useDateFormatSymbols = true;
40.2245 + }
40.2246 +
40.2247 + /**
40.2248 + * Creates a copy of this <code>SimpleDateFormat</code>. This also
40.2249 + * clones the format's date format symbols.
40.2250 + *
40.2251 + * @return a clone of this <code>SimpleDateFormat</code>
40.2252 + */
40.2253 + public Object clone() {
40.2254 + SimpleDateFormat other = (SimpleDateFormat) super.clone();
40.2255 + other.formatData = (DateFormatSymbols) formatData.clone();
40.2256 + return other;
40.2257 + }
40.2258 +
40.2259 + /**
40.2260 + * Returns the hash code value for this <code>SimpleDateFormat</code> object.
40.2261 + *
40.2262 + * @return the hash code value for this <code>SimpleDateFormat</code> object.
40.2263 + */
40.2264 + public int hashCode()
40.2265 + {
40.2266 + return pattern.hashCode();
40.2267 + // just enough fields for a reasonable distribution
40.2268 + }
40.2269 +
40.2270 + /**
40.2271 + * Compares the given object with this <code>SimpleDateFormat</code> for
40.2272 + * equality.
40.2273 + *
40.2274 + * @return true if the given object is equal to this
40.2275 + * <code>SimpleDateFormat</code>
40.2276 + */
40.2277 + public boolean equals(Object obj)
40.2278 + {
40.2279 + if (!super.equals(obj)) return false; // super does class check
40.2280 + SimpleDateFormat that = (SimpleDateFormat) obj;
40.2281 + return (pattern.equals(that.pattern)
40.2282 + && formatData.equals(that.formatData));
40.2283 + }
40.2284 +
40.2285 + /**
40.2286 + * After reading an object from the input stream, the format
40.2287 + * pattern in the object is verified.
40.2288 + * <p>
40.2289 + * @exception InvalidObjectException if the pattern is invalid
40.2290 + */
40.2291 + private void readObject(ObjectInputStream stream)
40.2292 + throws IOException, ClassNotFoundException {
40.2293 + stream.defaultReadObject();
40.2294 +
40.2295 + try {
40.2296 + compiledPattern = compile(pattern);
40.2297 + } catch (Exception e) {
40.2298 + throw new InvalidObjectException("invalid pattern");
40.2299 + }
40.2300 +
40.2301 + if (serialVersionOnStream < 1) {
40.2302 + // didn't have defaultCenturyStart field
40.2303 + initializeDefaultCentury();
40.2304 + }
40.2305 + else {
40.2306 + // fill in dependent transient field
40.2307 + parseAmbiguousDatesAsAfter(defaultCenturyStart);
40.2308 + }
40.2309 + serialVersionOnStream = currentSerialVersion;
40.2310 +
40.2311 + // If the deserialized object has a SimpleTimeZone, try
40.2312 + // to replace it with a ZoneInfo equivalent in order to
40.2313 + // be compatible with the SimpleTimeZone-based
40.2314 + // implementation as much as possible.
40.2315 + TimeZone tz = getTimeZone();
40.2316 + if (tz instanceof SimpleTimeZone) {
40.2317 + String id = tz.getID();
40.2318 + TimeZone zi = TimeZone.getTimeZone(id);
40.2319 + if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) {
40.2320 + setTimeZone(zi);
40.2321 + }
40.2322 + }
40.2323 + }
40.2324 +
40.2325 + /**
40.2326 + * Analyze the negative subpattern of DecimalFormat and set/update values
40.2327 + * as necessary.
40.2328 + */
40.2329 + private void checkNegativeNumberExpression() {
40.2330 + if ((numberFormat instanceof DecimalFormat) &&
40.2331 + !numberFormat.equals(originalNumberFormat)) {
40.2332 + String numberPattern = ((DecimalFormat)numberFormat).toPattern();
40.2333 + if (!numberPattern.equals(originalNumberPattern)) {
40.2334 + hasFollowingMinusSign = false;
40.2335 +
40.2336 + int separatorIndex = numberPattern.indexOf(';');
40.2337 + // If the negative subpattern is not absent, we have to analayze
40.2338 + // it in order to check if it has a following minus sign.
40.2339 + if (separatorIndex > -1) {
40.2340 + int minusIndex = numberPattern.indexOf('-', separatorIndex);
40.2341 + if ((minusIndex > numberPattern.lastIndexOf('0')) &&
40.2342 + (minusIndex > numberPattern.lastIndexOf('#'))) {
40.2343 + hasFollowingMinusSign = true;
40.2344 + minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign();
40.2345 + }
40.2346 + }
40.2347 + originalNumberPattern = numberPattern;
40.2348 + }
40.2349 + originalNumberFormat = numberFormat;
40.2350 + }
40.2351 + }
40.2352 +
40.2353 +}
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/rt/emul/compact/src/main/java/java/util/Calendar.java Thu Oct 03 15:43:10 2013 +0200
41.3 @@ -0,0 +1,2824 @@
41.4 +/*
41.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
41.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41.7 + *
41.8 + * This code is free software; you can redistribute it and/or modify it
41.9 + * under the terms of the GNU General Public License version 2 only, as
41.10 + * published by the Free Software Foundation. Oracle designates this
41.11 + * particular file as subject to the "Classpath" exception as provided
41.12 + * by Oracle in the LICENSE file that accompanied this code.
41.13 + *
41.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
41.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
41.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
41.17 + * version 2 for more details (a copy is included in the LICENSE file that
41.18 + * accompanied this code).
41.19 + *
41.20 + * You should have received a copy of the GNU General Public License version
41.21 + * 2 along with this work; if not, write to the Free Software Foundation,
41.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
41.23 + *
41.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
41.25 + * or visit www.oracle.com if you need additional information or have any
41.26 + * questions.
41.27 + */
41.28 +
41.29 +/*
41.30 + * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
41.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
41.32 + *
41.33 + * The original version of this source code and documentation is copyrighted
41.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
41.35 + * materials are provided under terms of a License Agreement between Taligent
41.36 + * and Sun. This technology is protected by multiple US and International
41.37 + * patents. This notice and attribution to Taligent may not be removed.
41.38 + * Taligent is a registered trademark of Taligent, Inc.
41.39 + *
41.40 + */
41.41 +
41.42 +package java.util;
41.43 +
41.44 +import java.io.IOException;
41.45 +import java.io.ObjectInputStream;
41.46 +import java.io.ObjectOutputStream;
41.47 +import java.io.OptionalDataException;
41.48 +import java.io.Serializable;
41.49 +import java.security.AccessControlContext;
41.50 +import java.security.AccessController;
41.51 +import java.security.PermissionCollection;
41.52 +import java.security.PrivilegedActionException;
41.53 +import java.security.PrivilegedExceptionAction;
41.54 +import java.security.ProtectionDomain;
41.55 +import java.text.DateFormat;
41.56 +import java.text.DateFormatSymbols;
41.57 +import java.util.concurrent.ConcurrentHashMap;
41.58 +import java.util.concurrent.ConcurrentMap;
41.59 +import sun.util.BuddhistCalendar;
41.60 +import sun.util.calendar.ZoneInfo;
41.61 +import sun.util.resources.LocaleData;
41.62 +
41.63 +/**
41.64 + * The <code>Calendar</code> class is an abstract class that provides methods
41.65 + * for converting between a specific instant in time and a set of {@link
41.66 + * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
41.67 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
41.68 + * manipulating the calendar fields, such as getting the date of the next
41.69 + * week. An instant in time can be represented by a millisecond value that is
41.70 + * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
41.71 + * 00:00:00.000 GMT (Gregorian).
41.72 + *
41.73 + * <p>The class also provides additional fields and methods for
41.74 + * implementing a concrete calendar system outside the package. Those
41.75 + * fields and methods are defined as <code>protected</code>.
41.76 + *
41.77 + * <p>
41.78 + * Like other locale-sensitive classes, <code>Calendar</code> provides a
41.79 + * class method, <code>getInstance</code>, for getting a generally useful
41.80 + * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
41.81 + * returns a <code>Calendar</code> object whose
41.82 + * calendar fields have been initialized with the current date and time:
41.83 + * <blockquote>
41.84 + * <pre>
41.85 + * Calendar rightNow = Calendar.getInstance();
41.86 + * </pre>
41.87 + * </blockquote>
41.88 + *
41.89 + * <p>A <code>Calendar</code> object can produce all the calendar field values
41.90 + * needed to implement the date-time formatting for a particular language and
41.91 + * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
41.92 + * <code>Calendar</code> defines the range of values returned by
41.93 + * certain calendar fields, as well as their meaning. For example,
41.94 + * the first month of the calendar system has value <code>MONTH ==
41.95 + * JANUARY</code> for all calendars. Other values are defined by the
41.96 + * concrete subclass, such as <code>ERA</code>. See individual field
41.97 + * documentation and subclass documentation for details.
41.98 + *
41.99 + * <h4>Getting and Setting Calendar Field Values</h4>
41.100 + *
41.101 + * <p>The calendar field values can be set by calling the <code>set</code>
41.102 + * methods. Any field values set in a <code>Calendar</code> will not be
41.103 + * interpreted until it needs to calculate its time value (milliseconds from
41.104 + * the Epoch) or values of the calendar fields. Calling the
41.105 + * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
41.106 + * <code>add</code> and <code>roll</code> involves such calculation.
41.107 + *
41.108 + * <h4>Leniency</h4>
41.109 + *
41.110 + * <p><code>Calendar</code> has two modes for interpreting the calendar
41.111 + * fields, <em>lenient</em> and <em>non-lenient</em>. When a
41.112 + * <code>Calendar</code> is in lenient mode, it accepts a wider range of
41.113 + * calendar field values than it produces. When a <code>Calendar</code>
41.114 + * recomputes calendar field values for return by <code>get()</code>, all of
41.115 + * the calendar fields are normalized. For example, a lenient
41.116 + * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
41.117 + * <code>DAY_OF_MONTH == 32</code> as February 1.
41.118 +
41.119 + * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
41.120 + * exception if there is any inconsistency in its calendar fields. For
41.121 + * example, a <code>GregorianCalendar</code> always produces
41.122 + * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
41.123 + * non-lenient <code>GregorianCalendar</code> throws an exception upon
41.124 + * calculating its time or calendar field values if any out-of-range field
41.125 + * value has been set.
41.126 + *
41.127 + * <h4><a name="first_week">First Week</a></h4>
41.128 + *
41.129 + * <code>Calendar</code> defines a locale-specific seven day week using two
41.130 + * parameters: the first day of the week and the minimal days in first week
41.131 + * (from 1 to 7). These numbers are taken from the locale resource data when a
41.132 + * <code>Calendar</code> is constructed. They may also be specified explicitly
41.133 + * through the methods for setting their values.
41.134 + *
41.135 + * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
41.136 + * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
41.137 + * first week of the month or year as a reference point. The first week of a
41.138 + * month or year is defined as the earliest seven day period beginning on
41.139 + * <code>getFirstDayOfWeek()</code> and containing at least
41.140 + * <code>getMinimalDaysInFirstWeek()</code> days of that month or year. Weeks
41.141 + * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
41.142 + * it. Note that the normalized numbering returned by <code>get()</code> may be
41.143 + * different. For example, a specific <code>Calendar</code> subclass may
41.144 + * designate the week before week 1 of a year as week <code><i>n</i></code> of
41.145 + * the previous year.
41.146 + *
41.147 + * <h4>Calendar Fields Resolution</h4>
41.148 + *
41.149 + * When computing a date and time from the calendar fields, there
41.150 + * may be insufficient information for the computation (such as only
41.151 + * year and month with no day of month), or there may be inconsistent
41.152 + * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
41.153 + * 1996 is actually a Monday). <code>Calendar</code> will resolve
41.154 + * calendar field values to determine the date and time in the
41.155 + * following way.
41.156 + *
41.157 + * <p>If there is any conflict in calendar field values,
41.158 + * <code>Calendar</code> gives priorities to calendar fields that have been set
41.159 + * more recently. The following are the default combinations of the
41.160 + * calendar fields. The most recent combination, as determined by the
41.161 + * most recently set single field, will be used.
41.162 + *
41.163 + * <p><a name="date_resolution">For the date fields</a>:
41.164 + * <blockquote>
41.165 + * <pre>
41.166 + * YEAR + MONTH + DAY_OF_MONTH
41.167 + * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
41.168 + * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
41.169 + * YEAR + DAY_OF_YEAR
41.170 + * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
41.171 + * </pre></blockquote>
41.172 + *
41.173 + * <a name="time_resolution">For the time of day fields</a>:
41.174 + * <blockquote>
41.175 + * <pre>
41.176 + * HOUR_OF_DAY
41.177 + * AM_PM + HOUR
41.178 + * </pre></blockquote>
41.179 + *
41.180 + * <p>If there are any calendar fields whose values haven't been set in the selected
41.181 + * field combination, <code>Calendar</code> uses their default values. The default
41.182 + * value of each field may vary by concrete calendar systems. For example, in
41.183 + * <code>GregorianCalendar</code>, the default of a field is the same as that
41.184 + * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
41.185 + * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
41.186 + *
41.187 + * <p>
41.188 + * <strong>Note:</strong> There are certain possible ambiguities in
41.189 + * interpretation of certain singular times, which are resolved in the
41.190 + * following ways:
41.191 + * <ol>
41.192 + * <li> 23:59 is the last minute of the day and 00:00 is the first
41.193 + * minute of the next day. Thus, 23:59 on Dec 31, 1999 < 00:00 on
41.194 + * Jan 1, 2000 < 00:01 on Jan 1, 2000.
41.195 + *
41.196 + * <li> Although historically not precise, midnight also belongs to "am",
41.197 + * and noon belongs to "pm", so on the same day,
41.198 + * 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm
41.199 + * </ol>
41.200 + *
41.201 + * <p>
41.202 + * The date or time format strings are not part of the definition of a
41.203 + * calendar, as those must be modifiable or overridable by the user at
41.204 + * runtime. Use {@link DateFormat}
41.205 + * to format dates.
41.206 + *
41.207 + * <h4>Field Manipulation</h4>
41.208 + *
41.209 + * The calendar fields can be changed using three methods:
41.210 + * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.</p>
41.211 + *
41.212 + * <p><strong><code>set(f, value)</code></strong> changes calendar field
41.213 + * <code>f</code> to <code>value</code>. In addition, it sets an
41.214 + * internal member variable to indicate that calendar field <code>f</code> has
41.215 + * been changed. Although calendar field <code>f</code> is changed immediately,
41.216 + * the calendar's time value in milliseconds is not recomputed until the next call to
41.217 + * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
41.218 + * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
41.219 + * <code>set()</code> do not trigger multiple, unnecessary
41.220 + * computations. As a result of changing a calendar field using
41.221 + * <code>set()</code>, other calendar fields may also change, depending on the
41.222 + * calendar field, the calendar field value, and the calendar system. In addition,
41.223 + * <code>get(f)</code> will not necessarily return <code>value</code> set by
41.224 + * the call to the <code>set</code> method
41.225 + * after the calendar fields have been recomputed. The specifics are determined by
41.226 + * the concrete calendar class.</p>
41.227 + *
41.228 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
41.229 + * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
41.230 + * Calendar.SEPTEMBER)</code> sets the date to September 31,
41.231 + * 1999. This is a temporary internal representation that resolves to
41.232 + * October 1, 1999 if <code>getTime()</code>is then called. However, a
41.233 + * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
41.234 + * <code>getTime()</code> sets the date to September 30, 1999, since
41.235 + * no recomputation occurs after <code>set()</code> itself.</p>
41.236 + *
41.237 + * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
41.238 + * to field <code>f</code>. This is equivalent to calling <code>set(f,
41.239 + * get(f) + delta)</code> with two adjustments:</p>
41.240 + *
41.241 + * <blockquote>
41.242 + * <p><strong>Add rule 1</strong>. The value of field <code>f</code>
41.243 + * after the call minus the value of field <code>f</code> before the
41.244 + * call is <code>delta</code>, modulo any overflow that has occurred in
41.245 + * field <code>f</code>. Overflow occurs when a field value exceeds its
41.246 + * range and, as a result, the next larger field is incremented or
41.247 + * decremented and the field value is adjusted back into its range.</p>
41.248 + *
41.249 + * <p><strong>Add rule 2</strong>. If a smaller field is expected to be
41.250 + * invariant, but it is impossible for it to be equal to its
41.251 + * prior value because of changes in its minimum or maximum after field
41.252 + * <code>f</code> is changed or other constraints, such as time zone
41.253 + * offset changes, then its value is adjusted to be as close
41.254 + * as possible to its expected value. A smaller field represents a
41.255 + * smaller unit of time. <code>HOUR</code> is a smaller field than
41.256 + * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
41.257 + * that are not expected to be invariant. The calendar system
41.258 + * determines what fields are expected to be invariant.</p>
41.259 + * </blockquote>
41.260 + *
41.261 + * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
41.262 + * an immediate recomputation of the calendar's milliseconds and all
41.263 + * fields.</p>
41.264 + *
41.265 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
41.266 + * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
41.267 + * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
41.268 + * 1</strong> sets the <code>MONTH</code> field to September, since
41.269 + * adding 13 months to August gives September of the next year. Since
41.270 + * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
41.271 + * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
41.272 + * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
41.273 + * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
41.274 + * rule 2, since it is expected to change when the month changes in a
41.275 + * <code>GregorianCalendar</code>.</p>
41.276 + *
41.277 + * <p><strong><code>roll(f, delta)</code></strong> adds
41.278 + * <code>delta</code> to field <code>f</code> without changing larger
41.279 + * fields. This is equivalent to calling <code>add(f, delta)</code> with
41.280 + * the following adjustment:</p>
41.281 + *
41.282 + * <blockquote>
41.283 + * <p><strong>Roll rule</strong>. Larger fields are unchanged after the
41.284 + * call. A larger field represents a larger unit of
41.285 + * time. <code>DAY_OF_MONTH</code> is a larger field than
41.286 + * <code>HOUR</code>.</p>
41.287 + * </blockquote>
41.288 + *
41.289 + * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
41.290 + *
41.291 + * <p><strong>Usage model</strong>. To motivate the behavior of
41.292 + * <code>add()</code> and <code>roll()</code>, consider a user interface
41.293 + * component with increment and decrement buttons for the month, day, and
41.294 + * year, and an underlying <code>GregorianCalendar</code>. If the
41.295 + * interface reads January 31, 1999 and the user presses the month
41.296 + * increment button, what should it read? If the underlying
41.297 + * implementation uses <code>set()</code>, it might read March 3, 1999. A
41.298 + * better result would be February 28, 1999. Furthermore, if the user
41.299 + * presses the month increment button again, it should read March 31,
41.300 + * 1999, not March 28, 1999. By saving the original date and using either
41.301 + * <code>add()</code> or <code>roll()</code>, depending on whether larger
41.302 + * fields should be affected, the user interface can behave as most users
41.303 + * will intuitively expect.</p>
41.304 + *
41.305 + * @see java.lang.System#currentTimeMillis()
41.306 + * @see Date
41.307 + * @see GregorianCalendar
41.308 + * @see TimeZone
41.309 + * @see java.text.DateFormat
41.310 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
41.311 + * @since JDK1.1
41.312 + */
41.313 +public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
41.314 +
41.315 + // Data flow in Calendar
41.316 + // ---------------------
41.317 +
41.318 + // The current time is represented in two ways by Calendar: as UTC
41.319 + // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
41.320 + // fields such as MONTH, HOUR, AM_PM, etc. It is possible to compute the
41.321 + // millis from the fields, and vice versa. The data needed to do this
41.322 + // conversion is encapsulated by a TimeZone object owned by the Calendar.
41.323 + // The data provided by the TimeZone object may also be overridden if the
41.324 + // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
41.325 + // keeps track of what information was most recently set by the caller, and
41.326 + // uses that to compute any other information as needed.
41.327 +
41.328 + // If the user sets the fields using set(), the data flow is as follows.
41.329 + // This is implemented by the Calendar subclass's computeTime() method.
41.330 + // During this process, certain fields may be ignored. The disambiguation
41.331 + // algorithm for resolving which fields to pay attention to is described
41.332 + // in the class documentation.
41.333 +
41.334 + // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
41.335 + // |
41.336 + // | Using Calendar-specific algorithm
41.337 + // V
41.338 + // local standard millis
41.339 + // |
41.340 + // | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
41.341 + // V
41.342 + // UTC millis (in time data member)
41.343 +
41.344 + // If the user sets the UTC millis using setTime() or setTimeInMillis(),
41.345 + // the data flow is as follows. This is implemented by the Calendar
41.346 + // subclass's computeFields() method.
41.347 +
41.348 + // UTC millis (in time data member)
41.349 + // |
41.350 + // | Using TimeZone getOffset()
41.351 + // V
41.352 + // local standard millis
41.353 + // |
41.354 + // | Using Calendar-specific algorithm
41.355 + // V
41.356 + // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
41.357 +
41.358 + // In general, a round trip from fields, through local and UTC millis, and
41.359 + // back out to fields is made when necessary. This is implemented by the
41.360 + // complete() method. Resolving a partial set of fields into a UTC millis
41.361 + // value allows all remaining fields to be generated from that value. If
41.362 + // the Calendar is lenient, the fields are also renormalized to standard
41.363 + // ranges when they are regenerated.
41.364 +
41.365 + /**
41.366 + * Field number for <code>get</code> and <code>set</code> indicating the
41.367 + * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
41.368 + * value; see subclass documentation.
41.369 + *
41.370 + * @see GregorianCalendar#AD
41.371 + * @see GregorianCalendar#BC
41.372 + */
41.373 + public final static int ERA = 0;
41.374 +
41.375 + /**
41.376 + * Field number for <code>get</code> and <code>set</code> indicating the
41.377 + * year. This is a calendar-specific value; see subclass documentation.
41.378 + */
41.379 + public final static int YEAR = 1;
41.380 +
41.381 + /**
41.382 + * Field number for <code>get</code> and <code>set</code> indicating the
41.383 + * month. This is a calendar-specific value. The first month of
41.384 + * the year in the Gregorian and Julian calendars is
41.385 + * <code>JANUARY</code> which is 0; the last depends on the number
41.386 + * of months in a year.
41.387 + *
41.388 + * @see #JANUARY
41.389 + * @see #FEBRUARY
41.390 + * @see #MARCH
41.391 + * @see #APRIL
41.392 + * @see #MAY
41.393 + * @see #JUNE
41.394 + * @see #JULY
41.395 + * @see #AUGUST
41.396 + * @see #SEPTEMBER
41.397 + * @see #OCTOBER
41.398 + * @see #NOVEMBER
41.399 + * @see #DECEMBER
41.400 + * @see #UNDECIMBER
41.401 + */
41.402 + public final static int MONTH = 2;
41.403 +
41.404 + /**
41.405 + * Field number for <code>get</code> and <code>set</code> indicating the
41.406 + * week number within the current year. The first week of the year, as
41.407 + * defined by <code>getFirstDayOfWeek()</code> and
41.408 + * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
41.409 + * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
41.410 + * the year.
41.411 + *
41.412 + * @see #getFirstDayOfWeek
41.413 + * @see #getMinimalDaysInFirstWeek
41.414 + */
41.415 + public final static int WEEK_OF_YEAR = 3;
41.416 +
41.417 + /**
41.418 + * Field number for <code>get</code> and <code>set</code> indicating the
41.419 + * week number within the current month. The first week of the month, as
41.420 + * defined by <code>getFirstDayOfWeek()</code> and
41.421 + * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
41.422 + * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
41.423 + * the month.
41.424 + *
41.425 + * @see #getFirstDayOfWeek
41.426 + * @see #getMinimalDaysInFirstWeek
41.427 + */
41.428 + public final static int WEEK_OF_MONTH = 4;
41.429 +
41.430 + /**
41.431 + * Field number for <code>get</code> and <code>set</code> indicating the
41.432 + * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
41.433 + * The first day of the month has value 1.
41.434 + *
41.435 + * @see #DAY_OF_MONTH
41.436 + */
41.437 + public final static int DATE = 5;
41.438 +
41.439 + /**
41.440 + * Field number for <code>get</code> and <code>set</code> indicating the
41.441 + * day of the month. This is a synonym for <code>DATE</code>.
41.442 + * The first day of the month has value 1.
41.443 + *
41.444 + * @see #DATE
41.445 + */
41.446 + public final static int DAY_OF_MONTH = 5;
41.447 +
41.448 + /**
41.449 + * Field number for <code>get</code> and <code>set</code> indicating the day
41.450 + * number within the current year. The first day of the year has value 1.
41.451 + */
41.452 + public final static int DAY_OF_YEAR = 6;
41.453 +
41.454 + /**
41.455 + * Field number for <code>get</code> and <code>set</code> indicating the day
41.456 + * of the week. This field takes values <code>SUNDAY</code>,
41.457 + * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
41.458 + * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
41.459 + *
41.460 + * @see #SUNDAY
41.461 + * @see #MONDAY
41.462 + * @see #TUESDAY
41.463 + * @see #WEDNESDAY
41.464 + * @see #THURSDAY
41.465 + * @see #FRIDAY
41.466 + * @see #SATURDAY
41.467 + */
41.468 + public final static int DAY_OF_WEEK = 7;
41.469 +
41.470 + /**
41.471 + * Field number for <code>get</code> and <code>set</code> indicating the
41.472 + * ordinal number of the day of the week within the current month. Together
41.473 + * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
41.474 + * within a month. Unlike <code>WEEK_OF_MONTH</code> and
41.475 + * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
41.476 + * <code>getFirstDayOfWeek()</code> or
41.477 + * <code>getMinimalDaysInFirstWeek()</code>. <code>DAY_OF_MONTH 1</code>
41.478 + * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
41.479 + * 1</code>; <code>8</code> through <code>14</code> correspond to
41.480 + * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
41.481 + * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
41.482 + * <code>DAY_OF_WEEK_IN_MONTH 1</code>. Negative values count back from the
41.483 + * end of the month, so the last Sunday of a month is specified as
41.484 + * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>. Because
41.485 + * negative values count backward they will usually be aligned differently
41.486 + * within the month than positive values. For example, if a month has 31
41.487 + * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
41.488 + * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
41.489 + *
41.490 + * @see #DAY_OF_WEEK
41.491 + * @see #WEEK_OF_MONTH
41.492 + */
41.493 + public final static int DAY_OF_WEEK_IN_MONTH = 8;
41.494 +
41.495 + /**
41.496 + * Field number for <code>get</code> and <code>set</code> indicating
41.497 + * whether the <code>HOUR</code> is before or after noon.
41.498 + * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
41.499 + *
41.500 + * @see #AM
41.501 + * @see #PM
41.502 + * @see #HOUR
41.503 + */
41.504 + public final static int AM_PM = 9;
41.505 +
41.506 + /**
41.507 + * Field number for <code>get</code> and <code>set</code> indicating the
41.508 + * hour of the morning or afternoon. <code>HOUR</code> is used for the
41.509 + * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
41.510 + * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
41.511 + *
41.512 + * @see #AM_PM
41.513 + * @see #HOUR_OF_DAY
41.514 + */
41.515 + public final static int HOUR = 10;
41.516 +
41.517 + /**
41.518 + * Field number for <code>get</code> and <code>set</code> indicating the
41.519 + * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
41.520 + * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
41.521 + *
41.522 + * @see #HOUR
41.523 + */
41.524 + public final static int HOUR_OF_DAY = 11;
41.525 +
41.526 + /**
41.527 + * Field number for <code>get</code> and <code>set</code> indicating the
41.528 + * minute within the hour.
41.529 + * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
41.530 + */
41.531 + public final static int MINUTE = 12;
41.532 +
41.533 + /**
41.534 + * Field number for <code>get</code> and <code>set</code> indicating the
41.535 + * second within the minute.
41.536 + * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
41.537 + */
41.538 + public final static int SECOND = 13;
41.539 +
41.540 + /**
41.541 + * Field number for <code>get</code> and <code>set</code> indicating the
41.542 + * millisecond within the second.
41.543 + * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
41.544 + */
41.545 + public final static int MILLISECOND = 14;
41.546 +
41.547 + /**
41.548 + * Field number for <code>get</code> and <code>set</code>
41.549 + * indicating the raw offset from GMT in milliseconds.
41.550 + * <p>
41.551 + * This field reflects the correct GMT offset value of the time
41.552 + * zone of this <code>Calendar</code> if the
41.553 + * <code>TimeZone</code> implementation subclass supports
41.554 + * historical GMT offset changes.
41.555 + */
41.556 + public final static int ZONE_OFFSET = 15;
41.557 +
41.558 + /**
41.559 + * Field number for <code>get</code> and <code>set</code> indicating the
41.560 + * daylight saving offset in milliseconds.
41.561 + * <p>
41.562 + * This field reflects the correct daylight saving offset value of
41.563 + * the time zone of this <code>Calendar</code> if the
41.564 + * <code>TimeZone</code> implementation subclass supports
41.565 + * historical Daylight Saving Time schedule changes.
41.566 + */
41.567 + public final static int DST_OFFSET = 16;
41.568 +
41.569 + /**
41.570 + * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
41.571 + * Field numbers range from <code>0..FIELD_COUNT-1</code>.
41.572 + */
41.573 + public final static int FIELD_COUNT = 17;
41.574 +
41.575 + /**
41.576 + * Value of the {@link #DAY_OF_WEEK} field indicating
41.577 + * Sunday.
41.578 + */
41.579 + public final static int SUNDAY = 1;
41.580 +
41.581 + /**
41.582 + * Value of the {@link #DAY_OF_WEEK} field indicating
41.583 + * Monday.
41.584 + */
41.585 + public final static int MONDAY = 2;
41.586 +
41.587 + /**
41.588 + * Value of the {@link #DAY_OF_WEEK} field indicating
41.589 + * Tuesday.
41.590 + */
41.591 + public final static int TUESDAY = 3;
41.592 +
41.593 + /**
41.594 + * Value of the {@link #DAY_OF_WEEK} field indicating
41.595 + * Wednesday.
41.596 + */
41.597 + public final static int WEDNESDAY = 4;
41.598 +
41.599 + /**
41.600 + * Value of the {@link #DAY_OF_WEEK} field indicating
41.601 + * Thursday.
41.602 + */
41.603 + public final static int THURSDAY = 5;
41.604 +
41.605 + /**
41.606 + * Value of the {@link #DAY_OF_WEEK} field indicating
41.607 + * Friday.
41.608 + */
41.609 + public final static int FRIDAY = 6;
41.610 +
41.611 + /**
41.612 + * Value of the {@link #DAY_OF_WEEK} field indicating
41.613 + * Saturday.
41.614 + */
41.615 + public final static int SATURDAY = 7;
41.616 +
41.617 + /**
41.618 + * Value of the {@link #MONTH} field indicating the
41.619 + * first month of the year in the Gregorian and Julian calendars.
41.620 + */
41.621 + public final static int JANUARY = 0;
41.622 +
41.623 + /**
41.624 + * Value of the {@link #MONTH} field indicating the
41.625 + * second month of the year in the Gregorian and Julian calendars.
41.626 + */
41.627 + public final static int FEBRUARY = 1;
41.628 +
41.629 + /**
41.630 + * Value of the {@link #MONTH} field indicating the
41.631 + * third month of the year in the Gregorian and Julian calendars.
41.632 + */
41.633 + public final static int MARCH = 2;
41.634 +
41.635 + /**
41.636 + * Value of the {@link #MONTH} field indicating the
41.637 + * fourth month of the year in the Gregorian and Julian calendars.
41.638 + */
41.639 + public final static int APRIL = 3;
41.640 +
41.641 + /**
41.642 + * Value of the {@link #MONTH} field indicating the
41.643 + * fifth month of the year in the Gregorian and Julian calendars.
41.644 + */
41.645 + public final static int MAY = 4;
41.646 +
41.647 + /**
41.648 + * Value of the {@link #MONTH} field indicating the
41.649 + * sixth month of the year in the Gregorian and Julian calendars.
41.650 + */
41.651 + public final static int JUNE = 5;
41.652 +
41.653 + /**
41.654 + * Value of the {@link #MONTH} field indicating the
41.655 + * seventh month of the year in the Gregorian and Julian calendars.
41.656 + */
41.657 + public final static int JULY = 6;
41.658 +
41.659 + /**
41.660 + * Value of the {@link #MONTH} field indicating the
41.661 + * eighth month of the year in the Gregorian and Julian calendars.
41.662 + */
41.663 + public final static int AUGUST = 7;
41.664 +
41.665 + /**
41.666 + * Value of the {@link #MONTH} field indicating the
41.667 + * ninth month of the year in the Gregorian and Julian calendars.
41.668 + */
41.669 + public final static int SEPTEMBER = 8;
41.670 +
41.671 + /**
41.672 + * Value of the {@link #MONTH} field indicating the
41.673 + * tenth month of the year in the Gregorian and Julian calendars.
41.674 + */
41.675 + public final static int OCTOBER = 9;
41.676 +
41.677 + /**
41.678 + * Value of the {@link #MONTH} field indicating the
41.679 + * eleventh month of the year in the Gregorian and Julian calendars.
41.680 + */
41.681 + public final static int NOVEMBER = 10;
41.682 +
41.683 + /**
41.684 + * Value of the {@link #MONTH} field indicating the
41.685 + * twelfth month of the year in the Gregorian and Julian calendars.
41.686 + */
41.687 + public final static int DECEMBER = 11;
41.688 +
41.689 + /**
41.690 + * Value of the {@link #MONTH} field indicating the
41.691 + * thirteenth month of the year. Although <code>GregorianCalendar</code>
41.692 + * does not use this value, lunar calendars do.
41.693 + */
41.694 + public final static int UNDECIMBER = 12;
41.695 +
41.696 + /**
41.697 + * Value of the {@link #AM_PM} field indicating the
41.698 + * period of the day from midnight to just before noon.
41.699 + */
41.700 + public final static int AM = 0;
41.701 +
41.702 + /**
41.703 + * Value of the {@link #AM_PM} field indicating the
41.704 + * period of the day from noon to just before midnight.
41.705 + */
41.706 + public final static int PM = 1;
41.707 +
41.708 + /**
41.709 + * A style specifier for {@link #getDisplayNames(int, int, Locale)
41.710 + * getDisplayNames} indicating names in all styles, such as
41.711 + * "January" and "Jan".
41.712 + *
41.713 + * @see #SHORT
41.714 + * @see #LONG
41.715 + * @since 1.6
41.716 + */
41.717 + public static final int ALL_STYLES = 0;
41.718 +
41.719 + /**
41.720 + * A style specifier for {@link #getDisplayName(int, int, Locale)
41.721 + * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
41.722 + * getDisplayNames} indicating a short name, such as "Jan".
41.723 + *
41.724 + * @see #LONG
41.725 + * @since 1.6
41.726 + */
41.727 + public static final int SHORT = 1;
41.728 +
41.729 + /**
41.730 + * A style specifier for {@link #getDisplayName(int, int, Locale)
41.731 + * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
41.732 + * getDisplayNames} indicating a long name, such as "January".
41.733 + *
41.734 + * @see #SHORT
41.735 + * @since 1.6
41.736 + */
41.737 + public static final int LONG = 2;
41.738 +
41.739 + // Internal notes:
41.740 + // Calendar contains two kinds of time representations: current "time" in
41.741 + // milliseconds, and a set of calendar "fields" representing the current time.
41.742 + // The two representations are usually in sync, but can get out of sync
41.743 + // as follows.
41.744 + // 1. Initially, no fields are set, and the time is invalid.
41.745 + // 2. If the time is set, all fields are computed and in sync.
41.746 + // 3. If a single field is set, the time is invalid.
41.747 + // Recomputation of the time and fields happens when the object needs
41.748 + // to return a result to the user, or use a result for a computation.
41.749 +
41.750 + /**
41.751 + * The calendar field values for the currently set time for this calendar.
41.752 + * This is an array of <code>FIELD_COUNT</code> integers, with index values
41.753 + * <code>ERA</code> through <code>DST_OFFSET</code>.
41.754 + * @serial
41.755 + */
41.756 + protected int fields[];
41.757 +
41.758 + /**
41.759 + * The flags which tell if a specified calendar field for the calendar is set.
41.760 + * A new object has no fields set. After the first call to a method
41.761 + * which generates the fields, they all remain set after that.
41.762 + * This is an array of <code>FIELD_COUNT</code> booleans, with index values
41.763 + * <code>ERA</code> through <code>DST_OFFSET</code>.
41.764 + * @serial
41.765 + */
41.766 + protected boolean isSet[];
41.767 +
41.768 + /**
41.769 + * Pseudo-time-stamps which specify when each field was set. There
41.770 + * are two special values, UNSET and COMPUTED. Values from
41.771 + * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
41.772 + */
41.773 + transient private int stamp[];
41.774 +
41.775 + /**
41.776 + * The currently set time for this calendar, expressed in milliseconds after
41.777 + * January 1, 1970, 0:00:00 GMT.
41.778 + * @see #isTimeSet
41.779 + * @serial
41.780 + */
41.781 + protected long time;
41.782 +
41.783 + /**
41.784 + * True if then the value of <code>time</code> is valid.
41.785 + * The time is made invalid by a change to an item of <code>field[]</code>.
41.786 + * @see #time
41.787 + * @serial
41.788 + */
41.789 + protected boolean isTimeSet;
41.790 +
41.791 + /**
41.792 + * True if <code>fields[]</code> are in sync with the currently set time.
41.793 + * If false, then the next attempt to get the value of a field will
41.794 + * force a recomputation of all fields from the current value of
41.795 + * <code>time</code>.
41.796 + * @serial
41.797 + */
41.798 + protected boolean areFieldsSet;
41.799 +
41.800 + /**
41.801 + * True if all fields have been set.
41.802 + * @serial
41.803 + */
41.804 + transient boolean areAllFieldsSet;
41.805 +
41.806 + /**
41.807 + * <code>True</code> if this calendar allows out-of-range field values during computation
41.808 + * of <code>time</code> from <code>fields[]</code>.
41.809 + * @see #setLenient
41.810 + * @see #isLenient
41.811 + * @serial
41.812 + */
41.813 + private boolean lenient = true;
41.814 +
41.815 + /**
41.816 + * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
41.817 + * uses the time zone data to translate between locale and GMT time.
41.818 + * @serial
41.819 + */
41.820 + private TimeZone zone;
41.821 +
41.822 + /**
41.823 + * <code>True</code> if zone references to a shared TimeZone object.
41.824 + */
41.825 + transient private boolean sharedZone = false;
41.826 +
41.827 + /**
41.828 + * The first day of the week, with possible values <code>SUNDAY</code>,
41.829 + * <code>MONDAY</code>, etc. This is a locale-dependent value.
41.830 + * @serial
41.831 + */
41.832 + private int firstDayOfWeek;
41.833 +
41.834 + /**
41.835 + * The number of days required for the first week in a month or year,
41.836 + * with possible values from 1 to 7. This is a locale-dependent value.
41.837 + * @serial
41.838 + */
41.839 + private int minimalDaysInFirstWeek;
41.840 +
41.841 + /**
41.842 + * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
41.843 + * of a Locale.
41.844 + */
41.845 + private static final ConcurrentMap<Locale, int[]> cachedLocaleData
41.846 + = new ConcurrentHashMap<Locale, int[]>(3);
41.847 +
41.848 + // Special values of stamp[]
41.849 + /**
41.850 + * The corresponding fields[] has no value.
41.851 + */
41.852 + private static final int UNSET = 0;
41.853 +
41.854 + /**
41.855 + * The value of the corresponding fields[] has been calculated internally.
41.856 + */
41.857 + private static final int COMPUTED = 1;
41.858 +
41.859 + /**
41.860 + * The value of the corresponding fields[] has been set externally. Stamp
41.861 + * values which are greater than 1 represents the (pseudo) time when the
41.862 + * corresponding fields[] value was set.
41.863 + */
41.864 + private static final int MINIMUM_USER_STAMP = 2;
41.865 +
41.866 + /**
41.867 + * The mask value that represents all of the fields.
41.868 + */
41.869 + static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
41.870 +
41.871 + /**
41.872 + * The next available value for <code>stamp[]</code>, an internal array.
41.873 + * This actually should not be written out to the stream, and will probably
41.874 + * be removed from the stream in the near future. In the meantime,
41.875 + * a value of <code>MINIMUM_USER_STAMP</code> should be used.
41.876 + * @serial
41.877 + */
41.878 + private int nextStamp = MINIMUM_USER_STAMP;
41.879 +
41.880 + // the internal serial version which says which version was written
41.881 + // - 0 (default) for version up to JDK 1.1.5
41.882 + // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
41.883 + // as well as compatible values for other fields. This is a
41.884 + // transitional format.
41.885 + // - 2 (not implemented yet) a future version, in which fields[],
41.886 + // areFieldsSet, and isTimeSet become transient, and isSet[] is
41.887 + // removed. In JDK 1.1.6 we write a format compatible with version 2.
41.888 + static final int currentSerialVersion = 1;
41.889 +
41.890 + /**
41.891 + * The version of the serialized data on the stream. Possible values:
41.892 + * <dl>
41.893 + * <dt><b>0</b> or not present on stream</dt>
41.894 + * <dd>
41.895 + * JDK 1.1.5 or earlier.
41.896 + * </dd>
41.897 + * <dt><b>1</b></dt>
41.898 + * <dd>
41.899 + * JDK 1.1.6 or later. Writes a correct 'time' value
41.900 + * as well as compatible values for other fields. This is a
41.901 + * transitional format.
41.902 + * </dd>
41.903 + * </dl>
41.904 + * When streaming out this class, the most recent format
41.905 + * and the highest allowable <code>serialVersionOnStream</code>
41.906 + * is written.
41.907 + * @serial
41.908 + * @since JDK1.1.6
41.909 + */
41.910 + private int serialVersionOnStream = currentSerialVersion;
41.911 +
41.912 + // Proclaim serialization compatibility with JDK 1.1
41.913 + static final long serialVersionUID = -1807547505821590642L;
41.914 +
41.915 + // Mask values for calendar fields
41.916 + final static int ERA_MASK = (1 << ERA);
41.917 + final static int YEAR_MASK = (1 << YEAR);
41.918 + final static int MONTH_MASK = (1 << MONTH);
41.919 + final static int WEEK_OF_YEAR_MASK = (1 << WEEK_OF_YEAR);
41.920 + final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
41.921 + final static int DAY_OF_MONTH_MASK = (1 << DAY_OF_MONTH);
41.922 + final static int DATE_MASK = DAY_OF_MONTH_MASK;
41.923 + final static int DAY_OF_YEAR_MASK = (1 << DAY_OF_YEAR);
41.924 + final static int DAY_OF_WEEK_MASK = (1 << DAY_OF_WEEK);
41.925 + final static int DAY_OF_WEEK_IN_MONTH_MASK = (1 << DAY_OF_WEEK_IN_MONTH);
41.926 + final static int AM_PM_MASK = (1 << AM_PM);
41.927 + final static int HOUR_MASK = (1 << HOUR);
41.928 + final static int HOUR_OF_DAY_MASK = (1 << HOUR_OF_DAY);
41.929 + final static int MINUTE_MASK = (1 << MINUTE);
41.930 + final static int SECOND_MASK = (1 << SECOND);
41.931 + final static int MILLISECOND_MASK = (1 << MILLISECOND);
41.932 + final static int ZONE_OFFSET_MASK = (1 << ZONE_OFFSET);
41.933 + final static int DST_OFFSET_MASK = (1 << DST_OFFSET);
41.934 +
41.935 + /**
41.936 + * Constructs a Calendar with the default time zone
41.937 + * and locale.
41.938 + * @see TimeZone#getDefault
41.939 + */
41.940 + protected Calendar()
41.941 + {
41.942 + this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
41.943 + sharedZone = true;
41.944 + }
41.945 +
41.946 + /**
41.947 + * Constructs a calendar with the specified time zone and locale.
41.948 + *
41.949 + * @param zone the time zone to use
41.950 + * @param aLocale the locale for the week data
41.951 + */
41.952 + protected Calendar(TimeZone zone, Locale aLocale)
41.953 + {
41.954 + fields = new int[FIELD_COUNT];
41.955 + isSet = new boolean[FIELD_COUNT];
41.956 + stamp = new int[FIELD_COUNT];
41.957 +
41.958 + this.zone = zone;
41.959 + setWeekCountData(aLocale);
41.960 + }
41.961 +
41.962 + /**
41.963 + * Gets a calendar using the default time zone and locale. The
41.964 + * <code>Calendar</code> returned is based on the current time
41.965 + * in the default time zone with the default locale.
41.966 + *
41.967 + * @return a Calendar.
41.968 + */
41.969 + public static Calendar getInstance()
41.970 + {
41.971 + Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
41.972 + cal.sharedZone = true;
41.973 + return cal;
41.974 + }
41.975 +
41.976 + /**
41.977 + * Gets a calendar using the specified time zone and default locale.
41.978 + * The <code>Calendar</code> returned is based on the current time
41.979 + * in the given time zone with the default locale.
41.980 + *
41.981 + * @param zone the time zone to use
41.982 + * @return a Calendar.
41.983 + */
41.984 + public static Calendar getInstance(TimeZone zone)
41.985 + {
41.986 + return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
41.987 + }
41.988 +
41.989 + /**
41.990 + * Gets a calendar using the default time zone and specified locale.
41.991 + * The <code>Calendar</code> returned is based on the current time
41.992 + * in the default time zone with the given locale.
41.993 + *
41.994 + * @param aLocale the locale for the week data
41.995 + * @return a Calendar.
41.996 + */
41.997 + public static Calendar getInstance(Locale aLocale)
41.998 + {
41.999 + Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale);
41.1000 + cal.sharedZone = true;
41.1001 + return cal;
41.1002 + }
41.1003 +
41.1004 + /**
41.1005 + * Gets a calendar with the specified time zone and locale.
41.1006 + * The <code>Calendar</code> returned is based on the current time
41.1007 + * in the given time zone with the given locale.
41.1008 + *
41.1009 + * @param zone the time zone to use
41.1010 + * @param aLocale the locale for the week data
41.1011 + * @return a Calendar.
41.1012 + */
41.1013 + public static Calendar getInstance(TimeZone zone,
41.1014 + Locale aLocale)
41.1015 + {
41.1016 + return createCalendar(zone, aLocale);
41.1017 + }
41.1018 +
41.1019 + private static Calendar createCalendar(TimeZone zone,
41.1020 + Locale aLocale)
41.1021 + {
41.1022 + Calendar cal = null;
41.1023 +
41.1024 + String caltype = aLocale.getUnicodeLocaleType("ca");
41.1025 + if (caltype == null) {
41.1026 + // Calendar type is not specified.
41.1027 + // If the specified locale is a Thai locale,
41.1028 + // returns a BuddhistCalendar instance.
41.1029 + if ("th".equals(aLocale.getLanguage())
41.1030 + && ("TH".equals(aLocale.getCountry()))) {
41.1031 + cal = new BuddhistCalendar(zone, aLocale);
41.1032 + } else {
41.1033 + cal = new GregorianCalendar(zone, aLocale);
41.1034 + }
41.1035 + } else if (caltype.equals("japanese")) {
41.1036 + cal = new JapaneseImperialCalendar(zone, aLocale);
41.1037 + } else if (caltype.equals("buddhist")) {
41.1038 + cal = new BuddhistCalendar(zone, aLocale);
41.1039 + } else {
41.1040 + // Unsupported calendar type.
41.1041 + // Use Gregorian calendar as a fallback.
41.1042 + cal = new GregorianCalendar(zone, aLocale);
41.1043 + }
41.1044 +
41.1045 + return cal;
41.1046 + }
41.1047 +
41.1048 + /**
41.1049 + * Returns an array of all locales for which the <code>getInstance</code>
41.1050 + * methods of this class can return localized instances.
41.1051 + * The array returned must contain at least a <code>Locale</code>
41.1052 + * instance equal to {@link java.util.Locale#US Locale.US}.
41.1053 + *
41.1054 + * @return An array of locales for which localized
41.1055 + * <code>Calendar</code> instances are available.
41.1056 + */
41.1057 + public static synchronized Locale[] getAvailableLocales()
41.1058 + {
41.1059 + return DateFormat.getAvailableLocales();
41.1060 + }
41.1061 +
41.1062 + /**
41.1063 + * Converts the current calendar field values in {@link #fields fields[]}
41.1064 + * to the millisecond time value
41.1065 + * {@link #time}.
41.1066 + *
41.1067 + * @see #complete()
41.1068 + * @see #computeFields()
41.1069 + */
41.1070 + protected abstract void computeTime();
41.1071 +
41.1072 + /**
41.1073 + * Converts the current millisecond time value {@link #time}
41.1074 + * to calendar field values in {@link #fields fields[]}.
41.1075 + * This allows you to sync up the calendar field values with
41.1076 + * a new time that is set for the calendar. The time is <em>not</em>
41.1077 + * recomputed first; to recompute the time, then the fields, call the
41.1078 + * {@link #complete()} method.
41.1079 + *
41.1080 + * @see #computeTime()
41.1081 + */
41.1082 + protected abstract void computeFields();
41.1083 +
41.1084 + /**
41.1085 + * Returns a <code>Date</code> object representing this
41.1086 + * <code>Calendar</code>'s time value (millisecond offset from the <a
41.1087 + * href="#Epoch">Epoch</a>").
41.1088 + *
41.1089 + * @return a <code>Date</code> representing the time value.
41.1090 + * @see #setTime(Date)
41.1091 + * @see #getTimeInMillis()
41.1092 + */
41.1093 + public final Date getTime() {
41.1094 + return new Date(getTimeInMillis());
41.1095 + }
41.1096 +
41.1097 + /**
41.1098 + * Sets this Calendar's time with the given <code>Date</code>.
41.1099 + * <p>
41.1100 + * Note: Calling <code>setTime()</code> with
41.1101 + * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
41.1102 + * may yield incorrect field values from <code>get()</code>.
41.1103 + *
41.1104 + * @param date the given Date.
41.1105 + * @see #getTime()
41.1106 + * @see #setTimeInMillis(long)
41.1107 + */
41.1108 + public final void setTime(Date date) {
41.1109 + setTimeInMillis(date.getTime());
41.1110 + }
41.1111 +
41.1112 + /**
41.1113 + * Returns this Calendar's time value in milliseconds.
41.1114 + *
41.1115 + * @return the current time as UTC milliseconds from the epoch.
41.1116 + * @see #getTime()
41.1117 + * @see #setTimeInMillis(long)
41.1118 + */
41.1119 + public long getTimeInMillis() {
41.1120 + if (!isTimeSet) {
41.1121 + updateTime();
41.1122 + }
41.1123 + return time;
41.1124 + }
41.1125 +
41.1126 + /**
41.1127 + * Sets this Calendar's current time from the given long value.
41.1128 + *
41.1129 + * @param millis the new time in UTC milliseconds from the epoch.
41.1130 + * @see #setTime(Date)
41.1131 + * @see #getTimeInMillis()
41.1132 + */
41.1133 + public void setTimeInMillis(long millis) {
41.1134 + // If we don't need to recalculate the calendar field values,
41.1135 + // do nothing.
41.1136 + if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
41.1137 + && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
41.1138 + return;
41.1139 + }
41.1140 + time = millis;
41.1141 + isTimeSet = true;
41.1142 + areFieldsSet = false;
41.1143 + computeFields();
41.1144 + areAllFieldsSet = areFieldsSet = true;
41.1145 + }
41.1146 +
41.1147 + /**
41.1148 + * Returns the value of the given calendar field. In lenient mode,
41.1149 + * all calendar fields are normalized. In non-lenient mode, all
41.1150 + * calendar fields are validated and this method throws an
41.1151 + * exception if any calendar fields have out-of-range values. The
41.1152 + * normalization and validation are handled by the
41.1153 + * {@link #complete()} method, which process is calendar
41.1154 + * system dependent.
41.1155 + *
41.1156 + * @param field the given calendar field.
41.1157 + * @return the value for the given calendar field.
41.1158 + * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
41.1159 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
41.1160 + * @see #set(int,int)
41.1161 + * @see #complete()
41.1162 + */
41.1163 + public int get(int field)
41.1164 + {
41.1165 + complete();
41.1166 + return internalGet(field);
41.1167 + }
41.1168 +
41.1169 + /**
41.1170 + * Returns the value of the given calendar field. This method does
41.1171 + * not involve normalization or validation of the field value.
41.1172 + *
41.1173 + * @param field the given calendar field.
41.1174 + * @return the value for the given calendar field.
41.1175 + * @see #get(int)
41.1176 + */
41.1177 + protected final int internalGet(int field)
41.1178 + {
41.1179 + return fields[field];
41.1180 + }
41.1181 +
41.1182 + /**
41.1183 + * Sets the value of the given calendar field. This method does
41.1184 + * not affect any setting state of the field in this
41.1185 + * <code>Calendar</code> instance.
41.1186 + *
41.1187 + * @throws IndexOutOfBoundsException if the specified field is out of range
41.1188 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
41.1189 + * @see #areFieldsSet
41.1190 + * @see #isTimeSet
41.1191 + * @see #areAllFieldsSet
41.1192 + * @see #set(int,int)
41.1193 + */
41.1194 + final void internalSet(int field, int value)
41.1195 + {
41.1196 + fields[field] = value;
41.1197 + }
41.1198 +
41.1199 + /**
41.1200 + * Sets the given calendar field to the given value. The value is not
41.1201 + * interpreted by this method regardless of the leniency mode.
41.1202 + *
41.1203 + * @param field the given calendar field.
41.1204 + * @param value the value to be set for the given calendar field.
41.1205 + * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
41.1206 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
41.1207 + * in non-lenient mode.
41.1208 + * @see #set(int,int,int)
41.1209 + * @see #set(int,int,int,int,int)
41.1210 + * @see #set(int,int,int,int,int,int)
41.1211 + * @see #get(int)
41.1212 + */
41.1213 + public void set(int field, int value)
41.1214 + {
41.1215 + // If the fields are partially normalized, calculate all the
41.1216 + // fields before changing any fields.
41.1217 + if (areFieldsSet && !areAllFieldsSet) {
41.1218 + computeFields();
41.1219 + }
41.1220 + internalSet(field, value);
41.1221 + isTimeSet = false;
41.1222 + areFieldsSet = false;
41.1223 + isSet[field] = true;
41.1224 + stamp[field] = nextStamp++;
41.1225 + if (nextStamp == Integer.MAX_VALUE) {
41.1226 + adjustStamp();
41.1227 + }
41.1228 + }
41.1229 +
41.1230 + /**
41.1231 + * Sets the values for the calendar fields <code>YEAR</code>,
41.1232 + * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
41.1233 + * Previous values of other calendar fields are retained. If this is not desired,
41.1234 + * call {@link #clear()} first.
41.1235 + *
41.1236 + * @param year the value used to set the <code>YEAR</code> calendar field.
41.1237 + * @param month the value used to set the <code>MONTH</code> calendar field.
41.1238 + * Month value is 0-based. e.g., 0 for January.
41.1239 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
41.1240 + * @see #set(int,int)
41.1241 + * @see #set(int,int,int,int,int)
41.1242 + * @see #set(int,int,int,int,int,int)
41.1243 + */
41.1244 + public final void set(int year, int month, int date)
41.1245 + {
41.1246 + set(YEAR, year);
41.1247 + set(MONTH, month);
41.1248 + set(DATE, date);
41.1249 + }
41.1250 +
41.1251 + /**
41.1252 + * Sets the values for the calendar fields <code>YEAR</code>,
41.1253 + * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
41.1254 + * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
41.1255 + * Previous values of other fields are retained. If this is not desired,
41.1256 + * call {@link #clear()} first.
41.1257 + *
41.1258 + * @param year the value used to set the <code>YEAR</code> calendar field.
41.1259 + * @param month the value used to set the <code>MONTH</code> calendar field.
41.1260 + * Month value is 0-based. e.g., 0 for January.
41.1261 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
41.1262 + * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
41.1263 + * @param minute the value used to set the <code>MINUTE</code> calendar field.
41.1264 + * @see #set(int,int)
41.1265 + * @see #set(int,int,int)
41.1266 + * @see #set(int,int,int,int,int,int)
41.1267 + */
41.1268 + public final void set(int year, int month, int date, int hourOfDay, int minute)
41.1269 + {
41.1270 + set(YEAR, year);
41.1271 + set(MONTH, month);
41.1272 + set(DATE, date);
41.1273 + set(HOUR_OF_DAY, hourOfDay);
41.1274 + set(MINUTE, minute);
41.1275 + }
41.1276 +
41.1277 + /**
41.1278 + * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
41.1279 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, <code>MINUTE</code>, and
41.1280 + * <code>SECOND</code>.
41.1281 + * Previous values of other fields are retained. If this is not desired,
41.1282 + * call {@link #clear()} first.
41.1283 + *
41.1284 + * @param year the value used to set the <code>YEAR</code> calendar field.
41.1285 + * @param month the value used to set the <code>MONTH</code> calendar field.
41.1286 + * Month value is 0-based. e.g., 0 for January.
41.1287 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
41.1288 + * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
41.1289 + * @param minute the value used to set the <code>MINUTE</code> calendar field.
41.1290 + * @param second the value used to set the <code>SECOND</code> calendar field.
41.1291 + * @see #set(int,int)
41.1292 + * @see #set(int,int,int)
41.1293 + * @see #set(int,int,int,int,int)
41.1294 + */
41.1295 + public final void set(int year, int month, int date, int hourOfDay, int minute,
41.1296 + int second)
41.1297 + {
41.1298 + set(YEAR, year);
41.1299 + set(MONTH, month);
41.1300 + set(DATE, date);
41.1301 + set(HOUR_OF_DAY, hourOfDay);
41.1302 + set(MINUTE, minute);
41.1303 + set(SECOND, second);
41.1304 + }
41.1305 +
41.1306 + /**
41.1307 + * Sets all the calendar field values and the time value
41.1308 + * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
41.1309 + * this <code>Calendar</code> undefined. This means that {@link
41.1310 + * #isSet(int) isSet()} will return <code>false</code> for all the
41.1311 + * calendar fields, and the date and time calculations will treat
41.1312 + * the fields as if they had never been set. A
41.1313 + * <code>Calendar</code> implementation class may use its specific
41.1314 + * default field values for date/time calculations. For example,
41.1315 + * <code>GregorianCalendar</code> uses 1970 if the
41.1316 + * <code>YEAR</code> field value is undefined.
41.1317 + *
41.1318 + * @see #clear(int)
41.1319 + */
41.1320 + public final void clear()
41.1321 + {
41.1322 + for (int i = 0; i < fields.length; ) {
41.1323 + stamp[i] = fields[i] = 0; // UNSET == 0
41.1324 + isSet[i++] = false;
41.1325 + }
41.1326 + areAllFieldsSet = areFieldsSet = false;
41.1327 + isTimeSet = false;
41.1328 + }
41.1329 +
41.1330 + /**
41.1331 + * Sets the given calendar field value and the time value
41.1332 + * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
41.1333 + * this <code>Calendar</code> undefined. This means that {@link
41.1334 + * #isSet(int) isSet(field)} will return <code>false</code>, and
41.1335 + * the date and time calculations will treat the field as if it
41.1336 + * had never been set. A <code>Calendar</code> implementation
41.1337 + * class may use the field's specific default value for date and
41.1338 + * time calculations.
41.1339 + *
41.1340 + * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
41.1341 + * fields are handled independently and the <a
41.1342 + * href="#time_resolution">the resolution rule for the time of
41.1343 + * day</a> is applied. Clearing one of the fields doesn't reset
41.1344 + * the hour of day value of this <code>Calendar</code>. Use {@link
41.1345 + * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
41.1346 + * value.
41.1347 + *
41.1348 + * @param field the calendar field to be cleared.
41.1349 + * @see #clear()
41.1350 + */
41.1351 + public final void clear(int field)
41.1352 + {
41.1353 + fields[field] = 0;
41.1354 + stamp[field] = UNSET;
41.1355 + isSet[field] = false;
41.1356 +
41.1357 + areAllFieldsSet = areFieldsSet = false;
41.1358 + isTimeSet = false;
41.1359 + }
41.1360 +
41.1361 + /**
41.1362 + * Determines if the given calendar field has a value set,
41.1363 + * including cases that the value has been set by internal fields
41.1364 + * calculations triggered by a <code>get</code> method call.
41.1365 + *
41.1366 + * @return <code>true</code> if the given calendar field has a value set;
41.1367 + * <code>false</code> otherwise.
41.1368 + */
41.1369 + public final boolean isSet(int field)
41.1370 + {
41.1371 + return stamp[field] != UNSET;
41.1372 + }
41.1373 +
41.1374 + /**
41.1375 + * Returns the string representation of the calendar
41.1376 + * <code>field</code> value in the given <code>style</code> and
41.1377 + * <code>locale</code>. If no string representation is
41.1378 + * applicable, <code>null</code> is returned. This method calls
41.1379 + * {@link Calendar#get(int) get(field)} to get the calendar
41.1380 + * <code>field</code> value if the string representation is
41.1381 + * applicable to the given calendar <code>field</code>.
41.1382 + *
41.1383 + * <p>For example, if this <code>Calendar</code> is a
41.1384 + * <code>GregorianCalendar</code> and its date is 2005-01-01, then
41.1385 + * the string representation of the {@link #MONTH} field would be
41.1386 + * "January" in the long style in an English locale or "Jan" in
41.1387 + * the short style. However, no string representation would be
41.1388 + * available for the {@link #DAY_OF_MONTH} field, and this method
41.1389 + * would return <code>null</code>.
41.1390 + *
41.1391 + * <p>The default implementation supports the calendar fields for
41.1392 + * which a {@link DateFormatSymbols} has names in the given
41.1393 + * <code>locale</code>.
41.1394 + *
41.1395 + * @param field
41.1396 + * the calendar field for which the string representation
41.1397 + * is returned
41.1398 + * @param style
41.1399 + * the style applied to the string representation; one of
41.1400 + * {@link #SHORT} or {@link #LONG}.
41.1401 + * @param locale
41.1402 + * the locale for the string representation
41.1403 + * @return the string representation of the given
41.1404 + * <code>field</code> in the given <code>style</code>, or
41.1405 + * <code>null</code> if no string representation is
41.1406 + * applicable.
41.1407 + * @exception IllegalArgumentException
41.1408 + * if <code>field</code> or <code>style</code> is invalid,
41.1409 + * or if this <code>Calendar</code> is non-lenient and any
41.1410 + * of the calendar fields have invalid values
41.1411 + * @exception NullPointerException
41.1412 + * if <code>locale</code> is null
41.1413 + * @since 1.6
41.1414 + */
41.1415 + public String getDisplayName(int field, int style, Locale locale) {
41.1416 + if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
41.1417 + ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
41.1418 + return null;
41.1419 + }
41.1420 +
41.1421 + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
41.1422 + String[] strings = getFieldStrings(field, style, symbols);
41.1423 + if (strings != null) {
41.1424 + int fieldValue = get(field);
41.1425 + if (fieldValue < strings.length) {
41.1426 + return strings[fieldValue];
41.1427 + }
41.1428 + }
41.1429 + return null;
41.1430 + }
41.1431 +
41.1432 + /**
41.1433 + * Returns a <code>Map</code> containing all names of the calendar
41.1434 + * <code>field</code> in the given <code>style</code> and
41.1435 + * <code>locale</code> and their corresponding field values. For
41.1436 + * example, if this <code>Calendar</code> is a {@link
41.1437 + * GregorianCalendar}, the returned map would contain "Jan" to
41.1438 + * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
41.1439 + * {@linkplain #SHORT short} style in an English locale.
41.1440 + *
41.1441 + * <p>The values of other calendar fields may be taken into
41.1442 + * account to determine a set of display names. For example, if
41.1443 + * this <code>Calendar</code> is a lunisolar calendar system and
41.1444 + * the year value given by the {@link #YEAR} field has a leap
41.1445 + * month, this method would return month names containing the leap
41.1446 + * month name, and month names are mapped to their values specific
41.1447 + * for the year.
41.1448 + *
41.1449 + * <p>The default implementation supports display names contained in
41.1450 + * a {@link DateFormatSymbols}. For example, if <code>field</code>
41.1451 + * is {@link #MONTH} and <code>style</code> is {@link
41.1452 + * #ALL_STYLES}, this method returns a <code>Map</code> containing
41.1453 + * all strings returned by {@link DateFormatSymbols#getShortMonths()}
41.1454 + * and {@link DateFormatSymbols#getMonths()}.
41.1455 + *
41.1456 + * @param field
41.1457 + * the calendar field for which the display names are returned
41.1458 + * @param style
41.1459 + * the style applied to the display names; one of {@link
41.1460 + * #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}.
41.1461 + * @param locale
41.1462 + * the locale for the display names
41.1463 + * @return a <code>Map</code> containing all display names in
41.1464 + * <code>style</code> and <code>locale</code> and their
41.1465 + * field values, or <code>null</code> if no display names
41.1466 + * are defined for <code>field</code>
41.1467 + * @exception IllegalArgumentException
41.1468 + * if <code>field</code> or <code>style</code> is invalid,
41.1469 + * or if this <code>Calendar</code> is non-lenient and any
41.1470 + * of the calendar fields have invalid values
41.1471 + * @exception NullPointerException
41.1472 + * if <code>locale</code> is null
41.1473 + * @since 1.6
41.1474 + */
41.1475 + public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
41.1476 + if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
41.1477 + ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
41.1478 + return null;
41.1479 + }
41.1480 +
41.1481 + // ALL_STYLES
41.1482 + if (style == ALL_STYLES) {
41.1483 + Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
41.1484 + if (field == ERA || field == AM_PM) {
41.1485 + return shortNames;
41.1486 + }
41.1487 + Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale);
41.1488 + if (shortNames == null) {
41.1489 + return longNames;
41.1490 + }
41.1491 + if (longNames != null) {
41.1492 + shortNames.putAll(longNames);
41.1493 + }
41.1494 + return shortNames;
41.1495 + }
41.1496 +
41.1497 + // SHORT or LONG
41.1498 + return getDisplayNamesImpl(field, style, locale);
41.1499 + }
41.1500 +
41.1501 + private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
41.1502 + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
41.1503 + String[] strings = getFieldStrings(field, style, symbols);
41.1504 + if (strings != null) {
41.1505 + Map<String,Integer> names = new HashMap<String,Integer>();
41.1506 + for (int i = 0; i < strings.length; i++) {
41.1507 + if (strings[i].length() == 0) {
41.1508 + continue;
41.1509 + }
41.1510 + names.put(strings[i], i);
41.1511 + }
41.1512 + return names;
41.1513 + }
41.1514 + return null;
41.1515 + }
41.1516 +
41.1517 + boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
41.1518 + Locale locale, int fieldMask) {
41.1519 + if (field < 0 || field >= fields.length ||
41.1520 + style < minStyle || style > maxStyle) {
41.1521 + throw new IllegalArgumentException();
41.1522 + }
41.1523 + if (locale == null) {
41.1524 + throw new NullPointerException();
41.1525 + }
41.1526 + return isFieldSet(fieldMask, field);
41.1527 + }
41.1528 +
41.1529 + private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
41.1530 + String[] strings = null;
41.1531 + switch (field) {
41.1532 + case ERA:
41.1533 + strings = symbols.getEras();
41.1534 + break;
41.1535 +
41.1536 + case MONTH:
41.1537 + strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths();
41.1538 + break;
41.1539 +
41.1540 + case DAY_OF_WEEK:
41.1541 + strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
41.1542 + break;
41.1543 +
41.1544 + case AM_PM:
41.1545 + strings = symbols.getAmPmStrings();
41.1546 + break;
41.1547 + }
41.1548 + return strings;
41.1549 + }
41.1550 +
41.1551 + /**
41.1552 + * Fills in any unset fields in the calendar fields. First, the {@link
41.1553 + * #computeTime()} method is called if the time value (millisecond offset
41.1554 + * from the <a href="#Epoch">Epoch</a>) has not been calculated from
41.1555 + * calendar field values. Then, the {@link #computeFields()} method is
41.1556 + * called to calculate all calendar field values.
41.1557 + */
41.1558 + protected void complete()
41.1559 + {
41.1560 + if (!isTimeSet)
41.1561 + updateTime();
41.1562 + if (!areFieldsSet || !areAllFieldsSet) {
41.1563 + computeFields(); // fills in unset fields
41.1564 + areAllFieldsSet = areFieldsSet = true;
41.1565 + }
41.1566 + }
41.1567 +
41.1568 + /**
41.1569 + * Returns whether the value of the specified calendar field has been set
41.1570 + * externally by calling one of the setter methods rather than by the
41.1571 + * internal time calculation.
41.1572 + *
41.1573 + * @return <code>true</code> if the field has been set externally,
41.1574 + * <code>false</code> otherwise.
41.1575 + * @exception IndexOutOfBoundsException if the specified
41.1576 + * <code>field</code> is out of range
41.1577 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
41.1578 + * @see #selectFields()
41.1579 + * @see #setFieldsComputed(int)
41.1580 + */
41.1581 + final boolean isExternallySet(int field) {
41.1582 + return stamp[field] >= MINIMUM_USER_STAMP;
41.1583 + }
41.1584 +
41.1585 + /**
41.1586 + * Returns a field mask (bit mask) indicating all calendar fields that
41.1587 + * have the state of externally or internally set.
41.1588 + *
41.1589 + * @return a bit mask indicating set state fields
41.1590 + */
41.1591 + final int getSetStateFields() {
41.1592 + int mask = 0;
41.1593 + for (int i = 0; i < fields.length; i++) {
41.1594 + if (stamp[i] != UNSET) {
41.1595 + mask |= 1 << i;
41.1596 + }
41.1597 + }
41.1598 + return mask;
41.1599 + }
41.1600 +
41.1601 + /**
41.1602 + * Sets the state of the specified calendar fields to
41.1603 + * <em>computed</em>. This state means that the specified calendar fields
41.1604 + * have valid values that have been set by internal time calculation
41.1605 + * rather than by calling one of the setter methods.
41.1606 + *
41.1607 + * @param fieldMask the field to be marked as computed.
41.1608 + * @exception IndexOutOfBoundsException if the specified
41.1609 + * <code>field</code> is out of range
41.1610 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
41.1611 + * @see #isExternallySet(int)
41.1612 + * @see #selectFields()
41.1613 + */
41.1614 + final void setFieldsComputed(int fieldMask) {
41.1615 + if (fieldMask == ALL_FIELDS) {
41.1616 + for (int i = 0; i < fields.length; i++) {
41.1617 + stamp[i] = COMPUTED;
41.1618 + isSet[i] = true;
41.1619 + }
41.1620 + areFieldsSet = areAllFieldsSet = true;
41.1621 + } else {
41.1622 + for (int i = 0; i < fields.length; i++) {
41.1623 + if ((fieldMask & 1) == 1) {
41.1624 + stamp[i] = COMPUTED;
41.1625 + isSet[i] = true;
41.1626 + } else {
41.1627 + if (areAllFieldsSet && !isSet[i]) {
41.1628 + areAllFieldsSet = false;
41.1629 + }
41.1630 + }
41.1631 + fieldMask >>>= 1;
41.1632 + }
41.1633 + }
41.1634 + }
41.1635 +
41.1636 + /**
41.1637 + * Sets the state of the calendar fields that are <em>not</em> specified
41.1638 + * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
41.1639 + * specifies all the calendar fields, then the state of this
41.1640 + * <code>Calendar</code> becomes that all the calendar fields are in sync
41.1641 + * with the time value (millisecond offset from the Epoch).
41.1642 + *
41.1643 + * @param fieldMask the field mask indicating which calendar fields are in
41.1644 + * sync with the time value.
41.1645 + * @exception IndexOutOfBoundsException if the specified
41.1646 + * <code>field</code> is out of range
41.1647 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
41.1648 + * @see #isExternallySet(int)
41.1649 + * @see #selectFields()
41.1650 + */
41.1651 + final void setFieldsNormalized(int fieldMask) {
41.1652 + if (fieldMask != ALL_FIELDS) {
41.1653 + for (int i = 0; i < fields.length; i++) {
41.1654 + if ((fieldMask & 1) == 0) {
41.1655 + stamp[i] = fields[i] = 0; // UNSET == 0
41.1656 + isSet[i] = false;
41.1657 + }
41.1658 + fieldMask >>= 1;
41.1659 + }
41.1660 + }
41.1661 +
41.1662 + // Some or all of the fields are in sync with the
41.1663 + // milliseconds, but the stamp values are not normalized yet.
41.1664 + areFieldsSet = true;
41.1665 + areAllFieldsSet = false;
41.1666 + }
41.1667 +
41.1668 + /**
41.1669 + * Returns whether the calendar fields are partially in sync with the time
41.1670 + * value or fully in sync but not stamp values are not normalized yet.
41.1671 + */
41.1672 + final boolean isPartiallyNormalized() {
41.1673 + return areFieldsSet && !areAllFieldsSet;
41.1674 + }
41.1675 +
41.1676 + /**
41.1677 + * Returns whether the calendar fields are fully in sync with the time
41.1678 + * value.
41.1679 + */
41.1680 + final boolean isFullyNormalized() {
41.1681 + return areFieldsSet && areAllFieldsSet;
41.1682 + }
41.1683 +
41.1684 + /**
41.1685 + * Marks this Calendar as not sync'd.
41.1686 + */
41.1687 + final void setUnnormalized() {
41.1688 + areFieldsSet = areAllFieldsSet = false;
41.1689 + }
41.1690 +
41.1691 + /**
41.1692 + * Returns whether the specified <code>field</code> is on in the
41.1693 + * <code>fieldMask</code>.
41.1694 + */
41.1695 + static final boolean isFieldSet(int fieldMask, int field) {
41.1696 + return (fieldMask & (1 << field)) != 0;
41.1697 + }
41.1698 +
41.1699 + /**
41.1700 + * Returns a field mask indicating which calendar field values
41.1701 + * to be used to calculate the time value. The calendar fields are
41.1702 + * returned as a bit mask, each bit of which corresponds to a field, i.e.,
41.1703 + * the mask value of <code>field</code> is <code>(1 <<
41.1704 + * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
41.1705 + * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
41.1706 + * equal to
41.1707 + * <code>(1<<YEAR)|(1<<MONTH)|(1<<DAY_OF_MONTH))</code>.
41.1708 + *
41.1709 + * <p>This method supports the calendar fields resolution as described in
41.1710 + * the class description. If the bit mask for a given field is on and its
41.1711 + * field has not been set (i.e., <code>isSet(field)</code> is
41.1712 + * <code>false</code>), then the default value of the field has to be
41.1713 + * used, which case means that the field has been selected because the
41.1714 + * selected combination involves the field.
41.1715 + *
41.1716 + * @return a bit mask of selected fields
41.1717 + * @see #isExternallySet(int)
41.1718 + * @see #setInternallySetState(int)
41.1719 + */
41.1720 + final int selectFields() {
41.1721 + // This implementation has been taken from the GregorianCalendar class.
41.1722 +
41.1723 + // The YEAR field must always be used regardless of its SET
41.1724 + // state because YEAR is a mandatory field to determine the date
41.1725 + // and the default value (EPOCH_YEAR) may change through the
41.1726 + // normalization process.
41.1727 + int fieldMask = YEAR_MASK;
41.1728 +
41.1729 + if (stamp[ERA] != UNSET) {
41.1730 + fieldMask |= ERA_MASK;
41.1731 + }
41.1732 + // Find the most recent group of fields specifying the day within
41.1733 + // the year. These may be any of the following combinations:
41.1734 + // MONTH + DAY_OF_MONTH
41.1735 + // MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
41.1736 + // MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
41.1737 + // DAY_OF_YEAR
41.1738 + // WEEK_OF_YEAR + DAY_OF_WEEK
41.1739 + // We look for the most recent of the fields in each group to determine
41.1740 + // the age of the group. For groups involving a week-related field such
41.1741 + // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
41.1742 + // week-related field and the DAY_OF_WEEK must be set for the group as a
41.1743 + // whole to be considered. (See bug 4153860 - liu 7/24/98.)
41.1744 + int dowStamp = stamp[DAY_OF_WEEK];
41.1745 + int monthStamp = stamp[MONTH];
41.1746 + int domStamp = stamp[DAY_OF_MONTH];
41.1747 + int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
41.1748 + int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
41.1749 + int doyStamp = stamp[DAY_OF_YEAR];
41.1750 + int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
41.1751 +
41.1752 + int bestStamp = domStamp;
41.1753 + if (womStamp > bestStamp) {
41.1754 + bestStamp = womStamp;
41.1755 + }
41.1756 + if (dowimStamp > bestStamp) {
41.1757 + bestStamp = dowimStamp;
41.1758 + }
41.1759 + if (doyStamp > bestStamp) {
41.1760 + bestStamp = doyStamp;
41.1761 + }
41.1762 + if (woyStamp > bestStamp) {
41.1763 + bestStamp = woyStamp;
41.1764 + }
41.1765 +
41.1766 + /* No complete combination exists. Look for WEEK_OF_MONTH,
41.1767 + * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone. Treat DAY_OF_WEEK alone
41.1768 + * as DAY_OF_WEEK_IN_MONTH.
41.1769 + */
41.1770 + if (bestStamp == UNSET) {
41.1771 + womStamp = stamp[WEEK_OF_MONTH];
41.1772 + dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
41.1773 + woyStamp = stamp[WEEK_OF_YEAR];
41.1774 + bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
41.1775 +
41.1776 + /* Treat MONTH alone or no fields at all as DAY_OF_MONTH. This may
41.1777 + * result in bestStamp = domStamp = UNSET if no fields are set,
41.1778 + * which indicates DAY_OF_MONTH.
41.1779 + */
41.1780 + if (bestStamp == UNSET) {
41.1781 + bestStamp = domStamp = monthStamp;
41.1782 + }
41.1783 + }
41.1784 +
41.1785 + if (bestStamp == domStamp ||
41.1786 + (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
41.1787 + (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
41.1788 + fieldMask |= MONTH_MASK;
41.1789 + if (bestStamp == domStamp) {
41.1790 + fieldMask |= DAY_OF_MONTH_MASK;
41.1791 + } else {
41.1792 + assert (bestStamp == womStamp || bestStamp == dowimStamp);
41.1793 + if (dowStamp != UNSET) {
41.1794 + fieldMask |= DAY_OF_WEEK_MASK;
41.1795 + }
41.1796 + if (womStamp == dowimStamp) {
41.1797 + // When they are equal, give the priority to
41.1798 + // WEEK_OF_MONTH for compatibility.
41.1799 + if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
41.1800 + fieldMask |= WEEK_OF_MONTH_MASK;
41.1801 + } else {
41.1802 + fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
41.1803 + }
41.1804 + } else {
41.1805 + if (bestStamp == womStamp) {
41.1806 + fieldMask |= WEEK_OF_MONTH_MASK;
41.1807 + } else {
41.1808 + assert (bestStamp == dowimStamp);
41.1809 + if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
41.1810 + fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
41.1811 + }
41.1812 + }
41.1813 + }
41.1814 + }
41.1815 + } else {
41.1816 + assert (bestStamp == doyStamp || bestStamp == woyStamp ||
41.1817 + bestStamp == UNSET);
41.1818 + if (bestStamp == doyStamp) {
41.1819 + fieldMask |= DAY_OF_YEAR_MASK;
41.1820 + } else {
41.1821 + assert (bestStamp == woyStamp);
41.1822 + if (dowStamp != UNSET) {
41.1823 + fieldMask |= DAY_OF_WEEK_MASK;
41.1824 + }
41.1825 + fieldMask |= WEEK_OF_YEAR_MASK;
41.1826 + }
41.1827 + }
41.1828 +
41.1829 + // Find the best set of fields specifying the time of day. There
41.1830 + // are only two possibilities here; the HOUR_OF_DAY or the
41.1831 + // AM_PM and the HOUR.
41.1832 + int hourOfDayStamp = stamp[HOUR_OF_DAY];
41.1833 + int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
41.1834 + bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
41.1835 +
41.1836 + // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
41.1837 + if (bestStamp == UNSET) {
41.1838 + bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
41.1839 + }
41.1840 +
41.1841 + // Hours
41.1842 + if (bestStamp != UNSET) {
41.1843 + if (bestStamp == hourOfDayStamp) {
41.1844 + fieldMask |= HOUR_OF_DAY_MASK;
41.1845 + } else {
41.1846 + fieldMask |= HOUR_MASK;
41.1847 + if (stamp[AM_PM] != UNSET) {
41.1848 + fieldMask |= AM_PM_MASK;
41.1849 + }
41.1850 + }
41.1851 + }
41.1852 + if (stamp[MINUTE] != UNSET) {
41.1853 + fieldMask |= MINUTE_MASK;
41.1854 + }
41.1855 + if (stamp[SECOND] != UNSET) {
41.1856 + fieldMask |= SECOND_MASK;
41.1857 + }
41.1858 + if (stamp[MILLISECOND] != UNSET) {
41.1859 + fieldMask |= MILLISECOND_MASK;
41.1860 + }
41.1861 + if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
41.1862 + fieldMask |= ZONE_OFFSET_MASK;
41.1863 + }
41.1864 + if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
41.1865 + fieldMask |= DST_OFFSET_MASK;
41.1866 + }
41.1867 +
41.1868 + return fieldMask;
41.1869 + }
41.1870 +
41.1871 + /**
41.1872 + * Returns the pseudo-time-stamp for two fields, given their
41.1873 + * individual pseudo-time-stamps. If either of the fields
41.1874 + * is unset, then the aggregate is unset. Otherwise, the
41.1875 + * aggregate is the later of the two stamps.
41.1876 + */
41.1877 + private static final int aggregateStamp(int stamp_a, int stamp_b) {
41.1878 + if (stamp_a == UNSET || stamp_b == UNSET) {
41.1879 + return UNSET;
41.1880 + }
41.1881 + return (stamp_a > stamp_b) ? stamp_a : stamp_b;
41.1882 + }
41.1883 +
41.1884 + /**
41.1885 + * Compares this <code>Calendar</code> to the specified
41.1886 + * <code>Object</code>. The result is <code>true</code> if and only if
41.1887 + * the argument is a <code>Calendar</code> object of the same calendar
41.1888 + * system that represents the same time value (millisecond offset from the
41.1889 + * <a href="#Epoch">Epoch</a>) under the same
41.1890 + * <code>Calendar</code> parameters as this object.
41.1891 + *
41.1892 + * <p>The <code>Calendar</code> parameters are the values represented
41.1893 + * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
41.1894 + * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
41.1895 + * methods. If there is any difference in those parameters
41.1896 + * between the two <code>Calendar</code>s, this method returns
41.1897 + * <code>false</code>.
41.1898 + *
41.1899 + * <p>Use the {@link #compareTo(Calendar) compareTo} method to
41.1900 + * compare only the time values.
41.1901 + *
41.1902 + * @param obj the object to compare with.
41.1903 + * @return <code>true</code> if this object is equal to <code>obj</code>;
41.1904 + * <code>false</code> otherwise.
41.1905 + */
41.1906 + public boolean equals(Object obj) {
41.1907 + if (this == obj)
41.1908 + return true;
41.1909 + try {
41.1910 + Calendar that = (Calendar)obj;
41.1911 + return compareTo(getMillisOf(that)) == 0 &&
41.1912 + lenient == that.lenient &&
41.1913 + firstDayOfWeek == that.firstDayOfWeek &&
41.1914 + minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
41.1915 + zone.equals(that.zone);
41.1916 + } catch (Exception e) {
41.1917 + // Note: GregorianCalendar.computeTime throws
41.1918 + // IllegalArgumentException if the ERA value is invalid
41.1919 + // even it's in lenient mode.
41.1920 + }
41.1921 + return false;
41.1922 + }
41.1923 +
41.1924 + /**
41.1925 + * Returns a hash code for this calendar.
41.1926 + *
41.1927 + * @return a hash code value for this object.
41.1928 + * @since 1.2
41.1929 + */
41.1930 + public int hashCode() {
41.1931 + // 'otheritems' represents the hash code for the previous versions.
41.1932 + int otheritems = (lenient ? 1 : 0)
41.1933 + | (firstDayOfWeek << 1)
41.1934 + | (minimalDaysInFirstWeek << 4)
41.1935 + | (zone.hashCode() << 7);
41.1936 + long t = getMillisOf(this);
41.1937 + return (int) t ^ (int)(t >> 32) ^ otheritems;
41.1938 + }
41.1939 +
41.1940 + /**
41.1941 + * Returns whether this <code>Calendar</code> represents a time
41.1942 + * before the time represented by the specified
41.1943 + * <code>Object</code>. This method is equivalent to:
41.1944 + * <pre><blockquote>
41.1945 + * compareTo(when) < 0
41.1946 + * </blockquote></pre>
41.1947 + * if and only if <code>when</code> is a <code>Calendar</code>
41.1948 + * instance. Otherwise, the method returns <code>false</code>.
41.1949 + *
41.1950 + * @param when the <code>Object</code> to be compared
41.1951 + * @return <code>true</code> if the time of this
41.1952 + * <code>Calendar</code> is before the time represented by
41.1953 + * <code>when</code>; <code>false</code> otherwise.
41.1954 + * @see #compareTo(Calendar)
41.1955 + */
41.1956 + public boolean before(Object when) {
41.1957 + return when instanceof Calendar
41.1958 + && compareTo((Calendar)when) < 0;
41.1959 + }
41.1960 +
41.1961 + /**
41.1962 + * Returns whether this <code>Calendar</code> represents a time
41.1963 + * after the time represented by the specified
41.1964 + * <code>Object</code>. This method is equivalent to:
41.1965 + * <pre><blockquote>
41.1966 + * compareTo(when) > 0
41.1967 + * </blockquote></pre>
41.1968 + * if and only if <code>when</code> is a <code>Calendar</code>
41.1969 + * instance. Otherwise, the method returns <code>false</code>.
41.1970 + *
41.1971 + * @param when the <code>Object</code> to be compared
41.1972 + * @return <code>true</code> if the time of this <code>Calendar</code> is
41.1973 + * after the time represented by <code>when</code>; <code>false</code>
41.1974 + * otherwise.
41.1975 + * @see #compareTo(Calendar)
41.1976 + */
41.1977 + public boolean after(Object when) {
41.1978 + return when instanceof Calendar
41.1979 + && compareTo((Calendar)when) > 0;
41.1980 + }
41.1981 +
41.1982 + /**
41.1983 + * Compares the time values (millisecond offsets from the <a
41.1984 + * href="#Epoch">Epoch</a>) represented by two
41.1985 + * <code>Calendar</code> objects.
41.1986 + *
41.1987 + * @param anotherCalendar the <code>Calendar</code> to be compared.
41.1988 + * @return the value <code>0</code> if the time represented by the argument
41.1989 + * is equal to the time represented by this <code>Calendar</code>; a value
41.1990 + * less than <code>0</code> if the time of this <code>Calendar</code> is
41.1991 + * before the time represented by the argument; and a value greater than
41.1992 + * <code>0</code> if the time of this <code>Calendar</code> is after the
41.1993 + * time represented by the argument.
41.1994 + * @exception NullPointerException if the specified <code>Calendar</code> is
41.1995 + * <code>null</code>.
41.1996 + * @exception IllegalArgumentException if the time value of the
41.1997 + * specified <code>Calendar</code> object can't be obtained due to
41.1998 + * any invalid calendar values.
41.1999 + * @since 1.5
41.2000 + */
41.2001 + public int compareTo(Calendar anotherCalendar) {
41.2002 + return compareTo(getMillisOf(anotherCalendar));
41.2003 + }
41.2004 +
41.2005 + /**
41.2006 + * Adds or subtracts the specified amount of time to the given calendar field,
41.2007 + * based on the calendar's rules. For example, to subtract 5 days from
41.2008 + * the current time of the calendar, you can achieve it by calling:
41.2009 + * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
41.2010 + *
41.2011 + * @param field the calendar field.
41.2012 + * @param amount the amount of date or time to be added to the field.
41.2013 + * @see #roll(int,int)
41.2014 + * @see #set(int,int)
41.2015 + */
41.2016 + abstract public void add(int field, int amount);
41.2017 +
41.2018 + /**
41.2019 + * Adds or subtracts (up/down) a single unit of time on the given time
41.2020 + * field without changing larger fields. For example, to roll the current
41.2021 + * date up by one day, you can achieve it by calling:
41.2022 + * <p>roll(Calendar.DATE, true).
41.2023 + * When rolling on the year or Calendar.YEAR field, it will roll the year
41.2024 + * value in the range between 1 and the value returned by calling
41.2025 + * <code>getMaximum(Calendar.YEAR)</code>.
41.2026 + * When rolling on the month or Calendar.MONTH field, other fields like
41.2027 + * date might conflict and, need to be changed. For instance,
41.2028 + * rolling the month on the date 01/31/96 will result in 02/29/96.
41.2029 + * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
41.2030 + * roll the hour value in the range between 0 and 23, which is zero-based.
41.2031 + *
41.2032 + * @param field the time field.
41.2033 + * @param up indicates if the value of the specified time field is to be
41.2034 + * rolled up or rolled down. Use true if rolling up, false otherwise.
41.2035 + * @see Calendar#add(int,int)
41.2036 + * @see Calendar#set(int,int)
41.2037 + */
41.2038 + abstract public void roll(int field, boolean up);
41.2039 +
41.2040 + /**
41.2041 + * Adds the specified (signed) amount to the specified calendar field
41.2042 + * without changing larger fields. A negative amount means to roll
41.2043 + * down.
41.2044 + *
41.2045 + * <p>NOTE: This default implementation on <code>Calendar</code> just repeatedly calls the
41.2046 + * version of {@link #roll(int,boolean) roll()} that rolls by one unit. This may not
41.2047 + * always do the right thing. For example, if the <code>DAY_OF_MONTH</code> field is 31,
41.2048 + * rolling through February will leave it set to 28. The <code>GregorianCalendar</code>
41.2049 + * version of this function takes care of this problem. Other subclasses
41.2050 + * should also provide overrides of this function that do the right thing.
41.2051 + *
41.2052 + * @param field the calendar field.
41.2053 + * @param amount the signed amount to add to the calendar <code>field</code>.
41.2054 + * @since 1.2
41.2055 + * @see #roll(int,boolean)
41.2056 + * @see #add(int,int)
41.2057 + * @see #set(int,int)
41.2058 + */
41.2059 + public void roll(int field, int amount)
41.2060 + {
41.2061 + while (amount > 0) {
41.2062 + roll(field, true);
41.2063 + amount--;
41.2064 + }
41.2065 + while (amount < 0) {
41.2066 + roll(field, false);
41.2067 + amount++;
41.2068 + }
41.2069 + }
41.2070 +
41.2071 + /**
41.2072 + * Sets the time zone with the given time zone value.
41.2073 + *
41.2074 + * @param value the given time zone.
41.2075 + */
41.2076 + public void setTimeZone(TimeZone value)
41.2077 + {
41.2078 + zone = value;
41.2079 + sharedZone = false;
41.2080 + /* Recompute the fields from the time using the new zone. This also
41.2081 + * works if isTimeSet is false (after a call to set()). In that case
41.2082 + * the time will be computed from the fields using the new zone, then
41.2083 + * the fields will get recomputed from that. Consider the sequence of
41.2084 + * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
41.2085 + * Is cal set to 1 o'clock EST or 1 o'clock PST? Answer: PST. More
41.2086 + * generally, a call to setTimeZone() affects calls to set() BEFORE AND
41.2087 + * AFTER it up to the next call to complete().
41.2088 + */
41.2089 + areAllFieldsSet = areFieldsSet = false;
41.2090 + }
41.2091 +
41.2092 + /**
41.2093 + * Gets the time zone.
41.2094 + *
41.2095 + * @return the time zone object associated with this calendar.
41.2096 + */
41.2097 + public TimeZone getTimeZone()
41.2098 + {
41.2099 + // If the TimeZone object is shared by other Calendar instances, then
41.2100 + // create a clone.
41.2101 + if (sharedZone) {
41.2102 + zone = (TimeZone) zone.clone();
41.2103 + sharedZone = false;
41.2104 + }
41.2105 + return zone;
41.2106 + }
41.2107 +
41.2108 + /**
41.2109 + * Returns the time zone (without cloning).
41.2110 + */
41.2111 + TimeZone getZone() {
41.2112 + return zone;
41.2113 + }
41.2114 +
41.2115 + /**
41.2116 + * Sets the sharedZone flag to <code>shared</code>.
41.2117 + */
41.2118 + void setZoneShared(boolean shared) {
41.2119 + sharedZone = shared;
41.2120 + }
41.2121 +
41.2122 + /**
41.2123 + * Specifies whether or not date/time interpretation is to be lenient. With
41.2124 + * lenient interpretation, a date such as "February 942, 1996" will be
41.2125 + * treated as being equivalent to the 941st day after February 1, 1996.
41.2126 + * With strict (non-lenient) interpretation, such dates will cause an exception to be
41.2127 + * thrown. The default is lenient.
41.2128 + *
41.2129 + * @param lenient <code>true</code> if the lenient mode is to be turned
41.2130 + * on; <code>false</code> if it is to be turned off.
41.2131 + * @see #isLenient()
41.2132 + * @see java.text.DateFormat#setLenient
41.2133 + */
41.2134 + public void setLenient(boolean lenient)
41.2135 + {
41.2136 + this.lenient = lenient;
41.2137 + }
41.2138 +
41.2139 + /**
41.2140 + * Tells whether date/time interpretation is to be lenient.
41.2141 + *
41.2142 + * @return <code>true</code> if the interpretation mode of this calendar is lenient;
41.2143 + * <code>false</code> otherwise.
41.2144 + * @see #setLenient(boolean)
41.2145 + */
41.2146 + public boolean isLenient()
41.2147 + {
41.2148 + return lenient;
41.2149 + }
41.2150 +
41.2151 + /**
41.2152 + * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
41.2153 + * <code>MONDAY</code> in France.
41.2154 + *
41.2155 + * @param value the given first day of the week.
41.2156 + * @see #getFirstDayOfWeek()
41.2157 + * @see #getMinimalDaysInFirstWeek()
41.2158 + */
41.2159 + public void setFirstDayOfWeek(int value)
41.2160 + {
41.2161 + if (firstDayOfWeek == value) {
41.2162 + return;
41.2163 + }
41.2164 + firstDayOfWeek = value;
41.2165 + invalidateWeekFields();
41.2166 + }
41.2167 +
41.2168 + /**
41.2169 + * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
41.2170 + * <code>MONDAY</code> in France.
41.2171 + *
41.2172 + * @return the first day of the week.
41.2173 + * @see #setFirstDayOfWeek(int)
41.2174 + * @see #getMinimalDaysInFirstWeek()
41.2175 + */
41.2176 + public int getFirstDayOfWeek()
41.2177 + {
41.2178 + return firstDayOfWeek;
41.2179 + }
41.2180 +
41.2181 + /**
41.2182 + * Sets what the minimal days required in the first week of the year are;
41.2183 + * For example, if the first week is defined as one that contains the first
41.2184 + * day of the first month of a year, call this method with value 1. If it
41.2185 + * must be a full week, use value 7.
41.2186 + *
41.2187 + * @param value the given minimal days required in the first week
41.2188 + * of the year.
41.2189 + * @see #getMinimalDaysInFirstWeek()
41.2190 + */
41.2191 + public void setMinimalDaysInFirstWeek(int value)
41.2192 + {
41.2193 + if (minimalDaysInFirstWeek == value) {
41.2194 + return;
41.2195 + }
41.2196 + minimalDaysInFirstWeek = value;
41.2197 + invalidateWeekFields();
41.2198 + }
41.2199 +
41.2200 + /**
41.2201 + * Gets what the minimal days required in the first week of the year are;
41.2202 + * e.g., if the first week is defined as one that contains the first day
41.2203 + * of the first month of a year, this method returns 1. If
41.2204 + * the minimal days required must be a full week, this method
41.2205 + * returns 7.
41.2206 + *
41.2207 + * @return the minimal days required in the first week of the year.
41.2208 + * @see #setMinimalDaysInFirstWeek(int)
41.2209 + */
41.2210 + public int getMinimalDaysInFirstWeek()
41.2211 + {
41.2212 + return minimalDaysInFirstWeek;
41.2213 + }
41.2214 +
41.2215 + /**
41.2216 + * Returns whether this {@code Calendar} supports week dates.
41.2217 + *
41.2218 + * <p>The default implementation of this method returns {@code false}.
41.2219 + *
41.2220 + * @return {@code true} if this {@code Calendar} supports week dates;
41.2221 + * {@code false} otherwise.
41.2222 + * @see #getWeekYear()
41.2223 + * @see #setWeekDate(int,int,int)
41.2224 + * @see #getWeeksInWeekYear()
41.2225 + * @since 1.7
41.2226 + */
41.2227 + public boolean isWeekDateSupported() {
41.2228 + return false;
41.2229 + }
41.2230 +
41.2231 + /**
41.2232 + * Returns the week year represented by this {@code Calendar}. The
41.2233 + * week year is in sync with the week cycle. The {@linkplain
41.2234 + * #getFirstDayOfWeek() first day of the first week} is the first
41.2235 + * day of the week year.
41.2236 + *
41.2237 + * <p>The default implementation of this method throws an
41.2238 + * {@link UnsupportedOperationException}.
41.2239 + *
41.2240 + * @return the week year of this {@code Calendar}
41.2241 + * @exception UnsupportedOperationException
41.2242 + * if any week year numbering isn't supported
41.2243 + * in this {@code Calendar}.
41.2244 + * @see #isWeekDateSupported()
41.2245 + * @see #getFirstDayOfWeek()
41.2246 + * @see #getMinimalDaysInFirstWeek()
41.2247 + * @since 1.7
41.2248 + */
41.2249 + public int getWeekYear() {
41.2250 + throw new UnsupportedOperationException();
41.2251 + }
41.2252 +
41.2253 + /**
41.2254 + * Sets the date of this {@code Calendar} with the the given date
41.2255 + * specifiers - week year, week of year, and day of week.
41.2256 + *
41.2257 + * <p>Unlike the {@code set} method, all of the calendar fields
41.2258 + * and {@code time} values are calculated upon return.
41.2259 + *
41.2260 + * <p>If {@code weekOfYear} is out of the valid week-of-year range
41.2261 + * in {@code weekYear}, the {@code weekYear} and {@code
41.2262 + * weekOfYear} values are adjusted in lenient mode, or an {@code
41.2263 + * IllegalArgumentException} is thrown in non-lenient mode.
41.2264 + *
41.2265 + * <p>The default implementation of this method throws an
41.2266 + * {@code UnsupportedOperationException}.
41.2267 + *
41.2268 + * @param weekYear the week year
41.2269 + * @param weekOfYear the week number based on {@code weekYear}
41.2270 + * @param dayOfWeek the day of week value: one of the constants
41.2271 + * for the {@link #DAY_OF_WEEK} field: {@link
41.2272 + * #SUNDAY}, ..., {@link #SATURDAY}.
41.2273 + * @exception IllegalArgumentException
41.2274 + * if any of the given date specifiers is invalid
41.2275 + * or any of the calendar fields are inconsistent
41.2276 + * with the given date specifiers in non-lenient mode
41.2277 + * @exception UnsupportedOperationException
41.2278 + * if any week year numbering isn't supported in this
41.2279 + * {@code Calendar}.
41.2280 + * @see #isWeekDateSupported()
41.2281 + * @see #getFirstDayOfWeek()
41.2282 + * @see #getMinimalDaysInFirstWeek()
41.2283 + * @since 1.7
41.2284 + */
41.2285 + public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
41.2286 + throw new UnsupportedOperationException();
41.2287 + }
41.2288 +
41.2289 + /**
41.2290 + * Returns the number of weeks in the week year represented by this
41.2291 + * {@code Calendar}.
41.2292 + *
41.2293 + * <p>The default implementation of this method throws an
41.2294 + * {@code UnsupportedOperationException}.
41.2295 + *
41.2296 + * @return the number of weeks in the week year.
41.2297 + * @exception UnsupportedOperationException
41.2298 + * if any week year numbering isn't supported in this
41.2299 + * {@code Calendar}.
41.2300 + * @see #WEEK_OF_YEAR
41.2301 + * @see #isWeekDateSupported()
41.2302 + * @see #getWeekYear()
41.2303 + * @see #getActualMaximum(int)
41.2304 + * @since 1.7
41.2305 + */
41.2306 + public int getWeeksInWeekYear() {
41.2307 + throw new UnsupportedOperationException();
41.2308 + }
41.2309 +
41.2310 + /**
41.2311 + * Returns the minimum value for the given calendar field of this
41.2312 + * <code>Calendar</code> instance. The minimum value is defined as
41.2313 + * the smallest value returned by the {@link #get(int) get} method
41.2314 + * for any possible time value. The minimum value depends on
41.2315 + * calendar system specific parameters of the instance.
41.2316 + *
41.2317 + * @param field the calendar field.
41.2318 + * @return the minimum value for the given calendar field.
41.2319 + * @see #getMaximum(int)
41.2320 + * @see #getGreatestMinimum(int)
41.2321 + * @see #getLeastMaximum(int)
41.2322 + * @see #getActualMinimum(int)
41.2323 + * @see #getActualMaximum(int)
41.2324 + */
41.2325 + abstract public int getMinimum(int field);
41.2326 +
41.2327 + /**
41.2328 + * Returns the maximum value for the given calendar field of this
41.2329 + * <code>Calendar</code> instance. The maximum value is defined as
41.2330 + * the largest value returned by the {@link #get(int) get} method
41.2331 + * for any possible time value. The maximum value depends on
41.2332 + * calendar system specific parameters of the instance.
41.2333 + *
41.2334 + * @param field the calendar field.
41.2335 + * @return the maximum value for the given calendar field.
41.2336 + * @see #getMinimum(int)
41.2337 + * @see #getGreatestMinimum(int)
41.2338 + * @see #getLeastMaximum(int)
41.2339 + * @see #getActualMinimum(int)
41.2340 + * @see #getActualMaximum(int)
41.2341 + */
41.2342 + abstract public int getMaximum(int field);
41.2343 +
41.2344 + /**
41.2345 + * Returns the highest minimum value for the given calendar field
41.2346 + * of this <code>Calendar</code> instance. The highest minimum
41.2347 + * value is defined as the largest value returned by {@link
41.2348 + * #getActualMinimum(int)} for any possible time value. The
41.2349 + * greatest minimum value depends on calendar system specific
41.2350 + * parameters of the instance.
41.2351 + *
41.2352 + * @param field the calendar field.
41.2353 + * @return the highest minimum value for the given calendar field.
41.2354 + * @see #getMinimum(int)
41.2355 + * @see #getMaximum(int)
41.2356 + * @see #getLeastMaximum(int)
41.2357 + * @see #getActualMinimum(int)
41.2358 + * @see #getActualMaximum(int)
41.2359 + */
41.2360 + abstract public int getGreatestMinimum(int field);
41.2361 +
41.2362 + /**
41.2363 + * Returns the lowest maximum value for the given calendar field
41.2364 + * of this <code>Calendar</code> instance. The lowest maximum
41.2365 + * value is defined as the smallest value returned by {@link
41.2366 + * #getActualMaximum(int)} for any possible time value. The least
41.2367 + * maximum value depends on calendar system specific parameters of
41.2368 + * the instance. For example, a <code>Calendar</code> for the
41.2369 + * Gregorian calendar system returns 28 for the
41.2370 + * <code>DAY_OF_MONTH</code> field, because the 28th is the last
41.2371 + * day of the shortest month of this calendar, February in a
41.2372 + * common year.
41.2373 + *
41.2374 + * @param field the calendar field.
41.2375 + * @return the lowest maximum value for the given calendar field.
41.2376 + * @see #getMinimum(int)
41.2377 + * @see #getMaximum(int)
41.2378 + * @see #getGreatestMinimum(int)
41.2379 + * @see #getActualMinimum(int)
41.2380 + * @see #getActualMaximum(int)
41.2381 + */
41.2382 + abstract public int getLeastMaximum(int field);
41.2383 +
41.2384 + /**
41.2385 + * Returns the minimum value that the specified calendar field
41.2386 + * could have, given the time value of this <code>Calendar</code>.
41.2387 + *
41.2388 + * <p>The default implementation of this method uses an iterative
41.2389 + * algorithm to determine the actual minimum value for the
41.2390 + * calendar field. Subclasses should, if possible, override this
41.2391 + * with a more efficient implementation - in many cases, they can
41.2392 + * simply return <code>getMinimum()</code>.
41.2393 + *
41.2394 + * @param field the calendar field
41.2395 + * @return the minimum of the given calendar field for the time
41.2396 + * value of this <code>Calendar</code>
41.2397 + * @see #getMinimum(int)
41.2398 + * @see #getMaximum(int)
41.2399 + * @see #getGreatestMinimum(int)
41.2400 + * @see #getLeastMaximum(int)
41.2401 + * @see #getActualMaximum(int)
41.2402 + * @since 1.2
41.2403 + */
41.2404 + public int getActualMinimum(int field) {
41.2405 + int fieldValue = getGreatestMinimum(field);
41.2406 + int endValue = getMinimum(field);
41.2407 +
41.2408 + // if we know that the minimum value is always the same, just return it
41.2409 + if (fieldValue == endValue) {
41.2410 + return fieldValue;
41.2411 + }
41.2412 +
41.2413 + // clone the calendar so we don't mess with the real one, and set it to
41.2414 + // accept anything for the field values
41.2415 + Calendar work = (Calendar)this.clone();
41.2416 + work.setLenient(true);
41.2417 +
41.2418 + // now try each value from getLeastMaximum() to getMaximum() one by one until
41.2419 + // we get a value that normalizes to another value. The last value that
41.2420 + // normalizes to itself is the actual minimum for the current date
41.2421 + int result = fieldValue;
41.2422 +
41.2423 + do {
41.2424 + work.set(field, fieldValue);
41.2425 + if (work.get(field) != fieldValue) {
41.2426 + break;
41.2427 + } else {
41.2428 + result = fieldValue;
41.2429 + fieldValue--;
41.2430 + }
41.2431 + } while (fieldValue >= endValue);
41.2432 +
41.2433 + return result;
41.2434 + }
41.2435 +
41.2436 + /**
41.2437 + * Returns the maximum value that the specified calendar field
41.2438 + * could have, given the time value of this
41.2439 + * <code>Calendar</code>. For example, the actual maximum value of
41.2440 + * the <code>MONTH</code> field is 12 in some years, and 13 in
41.2441 + * other years in the Hebrew calendar system.
41.2442 + *
41.2443 + * <p>The default implementation of this method uses an iterative
41.2444 + * algorithm to determine the actual maximum value for the
41.2445 + * calendar field. Subclasses should, if possible, override this
41.2446 + * with a more efficient implementation.
41.2447 + *
41.2448 + * @param field the calendar field
41.2449 + * @return the maximum of the given calendar field for the time
41.2450 + * value of this <code>Calendar</code>
41.2451 + * @see #getMinimum(int)
41.2452 + * @see #getMaximum(int)
41.2453 + * @see #getGreatestMinimum(int)
41.2454 + * @see #getLeastMaximum(int)
41.2455 + * @see #getActualMinimum(int)
41.2456 + * @since 1.2
41.2457 + */
41.2458 + public int getActualMaximum(int field) {
41.2459 + int fieldValue = getLeastMaximum(field);
41.2460 + int endValue = getMaximum(field);
41.2461 +
41.2462 + // if we know that the maximum value is always the same, just return it.
41.2463 + if (fieldValue == endValue) {
41.2464 + return fieldValue;
41.2465 + }
41.2466 +
41.2467 + // clone the calendar so we don't mess with the real one, and set it to
41.2468 + // accept anything for the field values.
41.2469 + Calendar work = (Calendar)this.clone();
41.2470 + work.setLenient(true);
41.2471 +
41.2472 + // if we're counting weeks, set the day of the week to Sunday. We know the
41.2473 + // last week of a month or year will contain the first day of the week.
41.2474 + if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH)
41.2475 + work.set(DAY_OF_WEEK, firstDayOfWeek);
41.2476 +
41.2477 + // now try each value from getLeastMaximum() to getMaximum() one by one until
41.2478 + // we get a value that normalizes to another value. The last value that
41.2479 + // normalizes to itself is the actual maximum for the current date
41.2480 + int result = fieldValue;
41.2481 +
41.2482 + do {
41.2483 + work.set(field, fieldValue);
41.2484 + if (work.get(field) != fieldValue) {
41.2485 + break;
41.2486 + } else {
41.2487 + result = fieldValue;
41.2488 + fieldValue++;
41.2489 + }
41.2490 + } while (fieldValue <= endValue);
41.2491 +
41.2492 + return result;
41.2493 + }
41.2494 +
41.2495 + /**
41.2496 + * Creates and returns a copy of this object.
41.2497 + *
41.2498 + * @return a copy of this object.
41.2499 + */
41.2500 + public Object clone()
41.2501 + {
41.2502 + try {
41.2503 + Calendar other = (Calendar) super.clone();
41.2504 +
41.2505 + other.fields = new int[FIELD_COUNT];
41.2506 + other.isSet = new boolean[FIELD_COUNT];
41.2507 + other.stamp = new int[FIELD_COUNT];
41.2508 + for (int i = 0; i < FIELD_COUNT; i++) {
41.2509 + other.fields[i] = fields[i];
41.2510 + other.stamp[i] = stamp[i];
41.2511 + other.isSet[i] = isSet[i];
41.2512 + }
41.2513 + other.zone = (TimeZone) zone.clone();
41.2514 + return other;
41.2515 + }
41.2516 + catch (CloneNotSupportedException e) {
41.2517 + // this shouldn't happen, since we are Cloneable
41.2518 + throw new InternalError();
41.2519 + }
41.2520 + }
41.2521 +
41.2522 + private static final String[] FIELD_NAME = {
41.2523 + "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
41.2524 + "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
41.2525 + "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
41.2526 + "DST_OFFSET"
41.2527 + };
41.2528 +
41.2529 + /**
41.2530 + * Returns the name of the specified calendar field.
41.2531 + *
41.2532 + * @param field the calendar field
41.2533 + * @return the calendar field name
41.2534 + * @exception IndexOutOfBoundsException if <code>field</code> is negative,
41.2535 + * equal to or greater then <code>FIELD_COUNT</code>.
41.2536 + */
41.2537 + static final String getFieldName(int field) {
41.2538 + return FIELD_NAME[field];
41.2539 + }
41.2540 +
41.2541 + /**
41.2542 + * Return a string representation of this calendar. This method
41.2543 + * is intended to be used only for debugging purposes, and the
41.2544 + * format of the returned string may vary between implementations.
41.2545 + * The returned string may be empty but may not be <code>null</code>.
41.2546 + *
41.2547 + * @return a string representation of this calendar.
41.2548 + */
41.2549 + public String toString() {
41.2550 + // NOTE: BuddhistCalendar.toString() interprets the string
41.2551 + // produced by this method so that the Gregorian year number
41.2552 + // is substituted by its B.E. year value. It relies on
41.2553 + // "...,YEAR=<year>,..." or "...,YEAR=?,...".
41.2554 + StringBuilder buffer = new StringBuilder(800);
41.2555 + buffer.append(getClass().getName()).append('[');
41.2556 + appendValue(buffer, "time", isTimeSet, time);
41.2557 + buffer.append(",areFieldsSet=").append(areFieldsSet);
41.2558 + buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
41.2559 + buffer.append(",lenient=").append(lenient);
41.2560 + buffer.append(",zone=").append(zone);
41.2561 + appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
41.2562 + appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
41.2563 + for (int i = 0; i < FIELD_COUNT; ++i) {
41.2564 + buffer.append(',');
41.2565 + appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
41.2566 + }
41.2567 + buffer.append(']');
41.2568 + return buffer.toString();
41.2569 + }
41.2570 +
41.2571 + // =======================privates===============================
41.2572 +
41.2573 + private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) {
41.2574 + sb.append(item).append('=');
41.2575 + if (valid) {
41.2576 + sb.append(value);
41.2577 + } else {
41.2578 + sb.append('?');
41.2579 + }
41.2580 + }
41.2581 +
41.2582 + /**
41.2583 + * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
41.2584 + * They are used to figure out the week count for a specific date for
41.2585 + * a given locale. These must be set when a Calendar is constructed.
41.2586 + * @param desiredLocale the given locale.
41.2587 + */
41.2588 + private void setWeekCountData(Locale desiredLocale)
41.2589 + {
41.2590 + /* try to get the Locale data from the cache */
41.2591 + int[] data = cachedLocaleData.get(desiredLocale);
41.2592 + if (data == null) { /* cache miss */
41.2593 + ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale);
41.2594 + data = new int[2];
41.2595 + data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
41.2596 + data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
41.2597 + cachedLocaleData.putIfAbsent(desiredLocale, data);
41.2598 + }
41.2599 + firstDayOfWeek = data[0];
41.2600 + minimalDaysInFirstWeek = data[1];
41.2601 + }
41.2602 +
41.2603 + /**
41.2604 + * Recomputes the time and updates the status fields isTimeSet
41.2605 + * and areFieldsSet. Callers should check isTimeSet and only
41.2606 + * call this method if isTimeSet is false.
41.2607 + */
41.2608 + private void updateTime() {
41.2609 + computeTime();
41.2610 + // The areFieldsSet and areAllFieldsSet values are no longer
41.2611 + // controlled here (as of 1.5).
41.2612 + isTimeSet = true;
41.2613 + }
41.2614 +
41.2615 + private int compareTo(long t) {
41.2616 + long thisTime = getMillisOf(this);
41.2617 + return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
41.2618 + }
41.2619 +
41.2620 + private static final long getMillisOf(Calendar calendar) {
41.2621 + if (calendar.isTimeSet) {
41.2622 + return calendar.time;
41.2623 + }
41.2624 + Calendar cal = (Calendar) calendar.clone();
41.2625 + cal.setLenient(true);
41.2626 + return cal.getTimeInMillis();
41.2627 + }
41.2628 +
41.2629 + /**
41.2630 + * Adjusts the stamp[] values before nextStamp overflow. nextStamp
41.2631 + * is set to the next stamp value upon the return.
41.2632 + */
41.2633 + private final void adjustStamp() {
41.2634 + int max = MINIMUM_USER_STAMP;
41.2635 + int newStamp = MINIMUM_USER_STAMP;
41.2636 +
41.2637 + for (;;) {
41.2638 + int min = Integer.MAX_VALUE;
41.2639 + for (int i = 0; i < stamp.length; i++) {
41.2640 + int v = stamp[i];
41.2641 + if (v >= newStamp && min > v) {
41.2642 + min = v;
41.2643 + }
41.2644 + if (max < v) {
41.2645 + max = v;
41.2646 + }
41.2647 + }
41.2648 + if (max != min && min == Integer.MAX_VALUE) {
41.2649 + break;
41.2650 + }
41.2651 + for (int i = 0; i < stamp.length; i++) {
41.2652 + if (stamp[i] == min) {
41.2653 + stamp[i] = newStamp;
41.2654 + }
41.2655 + }
41.2656 + newStamp++;
41.2657 + if (min == max) {
41.2658 + break;
41.2659 + }
41.2660 + }
41.2661 + nextStamp = newStamp;
41.2662 + }
41.2663 +
41.2664 + /**
41.2665 + * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
41.2666 + * new parameter value if they have been calculated internally.
41.2667 + */
41.2668 + private void invalidateWeekFields()
41.2669 + {
41.2670 + if (stamp[WEEK_OF_MONTH] != COMPUTED &&
41.2671 + stamp[WEEK_OF_YEAR] != COMPUTED) {
41.2672 + return;
41.2673 + }
41.2674 +
41.2675 + // We have to check the new values of these fields after changing
41.2676 + // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
41.2677 + // have been changed, then set the new values. (4822110)
41.2678 + Calendar cal = (Calendar) clone();
41.2679 + cal.setLenient(true);
41.2680 + cal.clear(WEEK_OF_MONTH);
41.2681 + cal.clear(WEEK_OF_YEAR);
41.2682 +
41.2683 + if (stamp[WEEK_OF_MONTH] == COMPUTED) {
41.2684 + int weekOfMonth = cal.get(WEEK_OF_MONTH);
41.2685 + if (fields[WEEK_OF_MONTH] != weekOfMonth) {
41.2686 + fields[WEEK_OF_MONTH] = weekOfMonth;
41.2687 + }
41.2688 + }
41.2689 +
41.2690 + if (stamp[WEEK_OF_YEAR] == COMPUTED) {
41.2691 + int weekOfYear = cal.get(WEEK_OF_YEAR);
41.2692 + if (fields[WEEK_OF_YEAR] != weekOfYear) {
41.2693 + fields[WEEK_OF_YEAR] = weekOfYear;
41.2694 + }
41.2695 + }
41.2696 + }
41.2697 +
41.2698 + /**
41.2699 + * Save the state of this object to a stream (i.e., serialize it).
41.2700 + *
41.2701 + * Ideally, <code>Calendar</code> would only write out its state data and
41.2702 + * the current time, and not write any field data out, such as
41.2703 + * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
41.2704 + * and <code>isSet[]</code>. <code>nextStamp</code> also should not be part
41.2705 + * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
41.2706 + * shipped. To be compatible with JDK 1.1, we will always have to write out
41.2707 + * the field values and state flags. However, <code>nextStamp</code> can be
41.2708 + * removed from the serialization stream; this will probably happen in the
41.2709 + * near future.
41.2710 + */
41.2711 + private void writeObject(ObjectOutputStream stream)
41.2712 + throws IOException
41.2713 + {
41.2714 + // Try to compute the time correctly, for the future (stream
41.2715 + // version 2) in which we don't write out fields[] or isSet[].
41.2716 + if (!isTimeSet) {
41.2717 + try {
41.2718 + updateTime();
41.2719 + }
41.2720 + catch (IllegalArgumentException e) {}
41.2721 + }
41.2722 +
41.2723 + // If this Calendar has a ZoneInfo, save it and set a
41.2724 + // SimpleTimeZone equivalent (as a single DST schedule) for
41.2725 + // backward compatibility.
41.2726 + TimeZone savedZone = null;
41.2727 + if (zone instanceof ZoneInfo) {
41.2728 + SimpleTimeZone stz = ((ZoneInfo)zone).getLastRuleInstance();
41.2729 + if (stz == null) {
41.2730 + stz = new SimpleTimeZone(zone.getRawOffset(), zone.getID());
41.2731 + }
41.2732 + savedZone = zone;
41.2733 + zone = stz;
41.2734 + }
41.2735 +
41.2736 + // Write out the 1.1 FCS object.
41.2737 + stream.defaultWriteObject();
41.2738 +
41.2739 + // Write out the ZoneInfo object
41.2740 + // 4802409: we write out even if it is null, a temporary workaround
41.2741 + // the real fix for bug 4844924 in corba-iiop
41.2742 + stream.writeObject(savedZone);
41.2743 + if (savedZone != null) {
41.2744 + zone = savedZone;
41.2745 + }
41.2746 + }
41.2747 +
41.2748 + private static class CalendarAccessControlContext {
41.2749 + private static final AccessControlContext INSTANCE;
41.2750 + static {
41.2751 + RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
41.2752 + PermissionCollection perms = perm.newPermissionCollection();
41.2753 + perms.add(perm);
41.2754 + INSTANCE = new AccessControlContext(new ProtectionDomain[] {
41.2755 + new ProtectionDomain(null, perms)
41.2756 + });
41.2757 + }
41.2758 + }
41.2759 +
41.2760 + /**
41.2761 + * Reconstitutes this object from a stream (i.e., deserialize it).
41.2762 + */
41.2763 + private void readObject(ObjectInputStream stream)
41.2764 + throws IOException, ClassNotFoundException
41.2765 + {
41.2766 + final ObjectInputStream input = stream;
41.2767 + input.defaultReadObject();
41.2768 +
41.2769 + stamp = new int[FIELD_COUNT];
41.2770 +
41.2771 + // Starting with version 2 (not implemented yet), we expect that
41.2772 + // fields[], isSet[], isTimeSet, and areFieldsSet may not be
41.2773 + // streamed out anymore. We expect 'time' to be correct.
41.2774 + if (serialVersionOnStream >= 2)
41.2775 + {
41.2776 + isTimeSet = true;
41.2777 + if (fields == null) fields = new int[FIELD_COUNT];
41.2778 + if (isSet == null) isSet = new boolean[FIELD_COUNT];
41.2779 + }
41.2780 + else if (serialVersionOnStream >= 0)
41.2781 + {
41.2782 + for (int i=0; i<FIELD_COUNT; ++i)
41.2783 + stamp[i] = isSet[i] ? COMPUTED : UNSET;
41.2784 + }
41.2785 +
41.2786 + serialVersionOnStream = currentSerialVersion;
41.2787 +
41.2788 + // If there's a ZoneInfo object, use it for zone.
41.2789 + ZoneInfo zi = null;
41.2790 + try {
41.2791 + zi = AccessController.doPrivileged(
41.2792 + new PrivilegedExceptionAction<ZoneInfo>() {
41.2793 + public ZoneInfo run() throws Exception {
41.2794 + return (ZoneInfo) input.readObject();
41.2795 + }
41.2796 + },
41.2797 + CalendarAccessControlContext.INSTANCE);
41.2798 + } catch (PrivilegedActionException pae) {
41.2799 + Exception e = pae.getException();
41.2800 + if (!(e instanceof OptionalDataException)) {
41.2801 + if (e instanceof RuntimeException) {
41.2802 + throw (RuntimeException) e;
41.2803 + } else if (e instanceof IOException) {
41.2804 + throw (IOException) e;
41.2805 + } else if (e instanceof ClassNotFoundException) {
41.2806 + throw (ClassNotFoundException) e;
41.2807 + }
41.2808 + throw new RuntimeException(e);
41.2809 + }
41.2810 + }
41.2811 + if (zi != null) {
41.2812 + zone = zi;
41.2813 + }
41.2814 +
41.2815 + // If the deserialized object has a SimpleTimeZone, try to
41.2816 + // replace it with a ZoneInfo equivalent (as of 1.4) in order
41.2817 + // to be compatible with the SimpleTimeZone-based
41.2818 + // implementation as much as possible.
41.2819 + if (zone instanceof SimpleTimeZone) {
41.2820 + String id = zone.getID();
41.2821 + TimeZone tz = TimeZone.getTimeZone(id);
41.2822 + if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
41.2823 + zone = tz;
41.2824 + }
41.2825 + }
41.2826 + }
41.2827 +}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/rt/emul/compact/src/main/java/java/util/Currency.java Thu Oct 03 15:43:10 2013 +0200
42.3 @@ -0,0 +1,741 @@
42.4 +/*
42.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
42.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
42.7 + *
42.8 + * This code is free software; you can redistribute it and/or modify it
42.9 + * under the terms of the GNU General Public License version 2 only, as
42.10 + * published by the Free Software Foundation. Oracle designates this
42.11 + * particular file as subject to the "Classpath" exception as provided
42.12 + * by Oracle in the LICENSE file that accompanied this code.
42.13 + *
42.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
42.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
42.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
42.17 + * version 2 for more details (a copy is included in the LICENSE file that
42.18 + * accompanied this code).
42.19 + *
42.20 + * You should have received a copy of the GNU General Public License version
42.21 + * 2 along with this work; if not, write to the Free Software Foundation,
42.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
42.23 + *
42.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
42.25 + * or visit www.oracle.com if you need additional information or have any
42.26 + * questions.
42.27 + */
42.28 +
42.29 +package java.util;
42.30 +
42.31 +import java.io.BufferedInputStream;
42.32 +import java.io.DataInputStream;
42.33 +import java.io.File;
42.34 +import java.io.FileInputStream;
42.35 +import java.io.FileReader;
42.36 +import java.io.IOException;
42.37 +import java.io.Serializable;
42.38 +import java.security.AccessController;
42.39 +import java.security.PrivilegedAction;
42.40 +import java.util.logging.Level;
42.41 +import java.util.regex.Pattern;
42.42 +import java.util.regex.Matcher;
42.43 +import java.util.spi.CurrencyNameProvider;
42.44 +import java.util.spi.LocaleServiceProvider;
42.45 +import sun.util.LocaleServiceProviderPool;
42.46 +import sun.util.logging.PlatformLogger;
42.47 +import sun.util.resources.LocaleData;
42.48 +import sun.util.resources.OpenListResourceBundle;
42.49 +
42.50 +
42.51 +/**
42.52 + * Represents a currency. Currencies are identified by their ISO 4217 currency
42.53 + * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
42.54 + * ISO web site</a> for more information, including a table of
42.55 + * currency codes.
42.56 + * <p>
42.57 + * The class is designed so that there's never more than one
42.58 + * <code>Currency</code> instance for any given currency. Therefore, there's
42.59 + * no public constructor. You obtain a <code>Currency</code> instance using
42.60 + * the <code>getInstance</code> methods.
42.61 + * <p>
42.62 + * Users can supersede the Java runtime currency data by creating a properties
42.63 + * file named <code><JAVA_HOME>/lib/currency.properties</code>. The contents
42.64 + * of the properties file are key/value pairs of the ISO 3166 country codes
42.65 + * and the ISO 4217 currency data respectively. The value part consists of
42.66 + * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
42.67 + * code, and a minor unit. Those three ISO 4217 values are separated by commas.
42.68 + * The lines which start with '#'s are considered comment lines. For example,
42.69 + * <p>
42.70 + * <code>
42.71 + * #Sample currency properties<br>
42.72 + * JP=JPZ,999,0
42.73 + * </code>
42.74 + * <p>
42.75 + * will supersede the currency data for Japan.
42.76 + *
42.77 + * @since 1.4
42.78 + */
42.79 +public final class Currency implements Serializable {
42.80 +
42.81 + private static final long serialVersionUID = -158308464356906721L;
42.82 +
42.83 + /**
42.84 + * ISO 4217 currency code for this currency.
42.85 + *
42.86 + * @serial
42.87 + */
42.88 + private final String currencyCode;
42.89 +
42.90 + /**
42.91 + * Default fraction digits for this currency.
42.92 + * Set from currency data tables.
42.93 + */
42.94 + transient private final int defaultFractionDigits;
42.95 +
42.96 + /**
42.97 + * ISO 4217 numeric code for this currency.
42.98 + * Set from currency data tables.
42.99 + */
42.100 + transient private final int numericCode;
42.101 +
42.102 +
42.103 + // class data: instance map
42.104 +
42.105 + private static HashMap<String, Currency> instances = new HashMap<String, Currency>(7);
42.106 + private static HashSet<Currency> available;
42.107 +
42.108 +
42.109 + // Class data: currency data obtained from currency.data file.
42.110 + // Purpose:
42.111 + // - determine valid country codes
42.112 + // - determine valid currency codes
42.113 + // - map country codes to currency codes
42.114 + // - obtain default fraction digits for currency codes
42.115 + //
42.116 + // sc = special case; dfd = default fraction digits
42.117 + // Simple countries are those where the country code is a prefix of the
42.118 + // currency code, and there are no known plans to change the currency.
42.119 + //
42.120 + // table formats:
42.121 + // - mainTable:
42.122 + // - maps country code to 32-bit int
42.123 + // - 26*26 entries, corresponding to [A-Z]*[A-Z]
42.124 + // - \u007F -> not valid country
42.125 + // - bits 18-31: unused
42.126 + // - bits 8-17: numeric code (0 to 1023)
42.127 + // - bit 7: 1 - special case, bits 0-4 indicate which one
42.128 + // 0 - simple country, bits 0-4 indicate final char of currency code
42.129 + // - bits 5-6: fraction digits for simple countries, 0 for special cases
42.130 + // - bits 0-4: final char for currency code for simple country, or ID of special case
42.131 + // - special case IDs:
42.132 + // - 0: country has no currency
42.133 + // - other: index into sc* arrays + 1
42.134 + // - scCutOverTimes: cut-over time in millis as returned by
42.135 + // System.currentTimeMillis for special case countries that are changing
42.136 + // currencies; Long.MAX_VALUE for countries that are not changing currencies
42.137 + // - scOldCurrencies: old currencies for special case countries
42.138 + // - scNewCurrencies: new currencies for special case countries that are
42.139 + // changing currencies; null for others
42.140 + // - scOldCurrenciesDFD: default fraction digits for old currencies
42.141 + // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
42.142 + // countries that are not changing currencies
42.143 + // - otherCurrencies: concatenation of all currency codes that are not the
42.144 + // main currency of a simple country, separated by "-"
42.145 + // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
42.146 +
42.147 + static int formatVersion;
42.148 + static int dataVersion;
42.149 + static int[] mainTable;
42.150 + static long[] scCutOverTimes;
42.151 + static String[] scOldCurrencies;
42.152 + static String[] scNewCurrencies;
42.153 + static int[] scOldCurrenciesDFD;
42.154 + static int[] scNewCurrenciesDFD;
42.155 + static int[] scOldCurrenciesNumericCode;
42.156 + static int[] scNewCurrenciesNumericCode;
42.157 + static String otherCurrencies;
42.158 + static int[] otherCurrenciesDFD;
42.159 + static int[] otherCurrenciesNumericCode;
42.160 +
42.161 + // handy constants - must match definitions in GenerateCurrencyData
42.162 + // magic number
42.163 + private static final int MAGIC_NUMBER = 0x43757244;
42.164 + // number of characters from A to Z
42.165 + private static final int A_TO_Z = ('Z' - 'A') + 1;
42.166 + // entry for invalid country codes
42.167 + private static final int INVALID_COUNTRY_ENTRY = 0x007F;
42.168 + // entry for countries without currency
42.169 + private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x0080;
42.170 + // mask for simple case country entries
42.171 + private static final int SIMPLE_CASE_COUNTRY_MASK = 0x0000;
42.172 + // mask for simple case country entry final character
42.173 + private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x001F;
42.174 + // mask for simple case country entry default currency digits
42.175 + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x0060;
42.176 + // shift count for simple case country entry default currency digits
42.177 + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
42.178 + // mask for special case country entries
42.179 + private static final int SPECIAL_CASE_COUNTRY_MASK = 0x0080;
42.180 + // mask for special case country index
42.181 + private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x001F;
42.182 + // delta from entry index component in main table to index into special case tables
42.183 + private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
42.184 + // mask for distinguishing simple and special case countries
42.185 + private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
42.186 + // mask for the numeric code of the currency
42.187 + private static final int NUMERIC_CODE_MASK = 0x0003FF00;
42.188 + // shift count for the numeric code of the currency
42.189 + private static final int NUMERIC_CODE_SHIFT = 8;
42.190 +
42.191 + // Currency data format version
42.192 + private static final int VALID_FORMAT_VERSION = 1;
42.193 +
42.194 + static {
42.195 + AccessController.doPrivileged(new PrivilegedAction() {
42.196 + public Object run() {
42.197 + String homeDir = System.getProperty("java.home");
42.198 + try {
42.199 + String dataFile = homeDir + File.separator +
42.200 + "lib" + File.separator + "currency.data";
42.201 + DataInputStream dis = new DataInputStream(
42.202 + new BufferedInputStream(
42.203 + new FileInputStream(dataFile)));
42.204 + if (dis.readInt() != MAGIC_NUMBER) {
42.205 + throw new InternalError("Currency data is possibly corrupted");
42.206 + }
42.207 + formatVersion = dis.readInt();
42.208 + if (formatVersion != VALID_FORMAT_VERSION) {
42.209 + throw new InternalError("Currency data format is incorrect");
42.210 + }
42.211 + dataVersion = dis.readInt();
42.212 + mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
42.213 + int scCount = dis.readInt();
42.214 + scCutOverTimes = readLongArray(dis, scCount);
42.215 + scOldCurrencies = readStringArray(dis, scCount);
42.216 + scNewCurrencies = readStringArray(dis, scCount);
42.217 + scOldCurrenciesDFD = readIntArray(dis, scCount);
42.218 + scNewCurrenciesDFD = readIntArray(dis, scCount);
42.219 + scOldCurrenciesNumericCode = readIntArray(dis, scCount);
42.220 + scNewCurrenciesNumericCode = readIntArray(dis, scCount);
42.221 + int ocCount = dis.readInt();
42.222 + otherCurrencies = dis.readUTF();
42.223 + otherCurrenciesDFD = readIntArray(dis, ocCount);
42.224 + otherCurrenciesNumericCode = readIntArray(dis, ocCount);
42.225 + dis.close();
42.226 + } catch (IOException e) {
42.227 + InternalError ie = new InternalError();
42.228 + ie.initCause(e);
42.229 + throw ie;
42.230 + }
42.231 +
42.232 + // look for the properties file for overrides
42.233 + try {
42.234 + File propFile = new File(homeDir + File.separator +
42.235 + "lib" + File.separator +
42.236 + "currency.properties");
42.237 + if (propFile.exists()) {
42.238 + Properties props = new Properties();
42.239 + try (FileReader fr = new FileReader(propFile)) {
42.240 + props.load(fr);
42.241 + }
42.242 + Set<String> keys = props.stringPropertyNames();
42.243 + Pattern propertiesPattern =
42.244 + Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*([0-3])");
42.245 + for (String key : keys) {
42.246 + replaceCurrencyData(propertiesPattern,
42.247 + key.toUpperCase(Locale.ROOT),
42.248 + props.getProperty(key).toUpperCase(Locale.ROOT));
42.249 + }
42.250 + }
42.251 + } catch (IOException e) {
42.252 + info("currency.properties is ignored because of an IOException", e);
42.253 + }
42.254 + return null;
42.255 + }
42.256 + });
42.257 + }
42.258 +
42.259 + /**
42.260 + * Constants for retrieving localized names from the name providers.
42.261 + */
42.262 + private static final int SYMBOL = 0;
42.263 + private static final int DISPLAYNAME = 1;
42.264 +
42.265 +
42.266 + /**
42.267 + * Constructs a <code>Currency</code> instance. The constructor is private
42.268 + * so that we can insure that there's never more than one instance for a
42.269 + * given currency.
42.270 + */
42.271 + private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
42.272 + this.currencyCode = currencyCode;
42.273 + this.defaultFractionDigits = defaultFractionDigits;
42.274 + this.numericCode = numericCode;
42.275 + }
42.276 +
42.277 + /**
42.278 + * Returns the <code>Currency</code> instance for the given currency code.
42.279 + *
42.280 + * @param currencyCode the ISO 4217 code of the currency
42.281 + * @return the <code>Currency</code> instance for the given currency code
42.282 + * @exception NullPointerException if <code>currencyCode</code> is null
42.283 + * @exception IllegalArgumentException if <code>currencyCode</code> is not
42.284 + * a supported ISO 4217 code.
42.285 + */
42.286 + public static Currency getInstance(String currencyCode) {
42.287 + return getInstance(currencyCode, Integer.MIN_VALUE, 0);
42.288 + }
42.289 +
42.290 + private static Currency getInstance(String currencyCode, int defaultFractionDigits,
42.291 + int numericCode) {
42.292 + synchronized (instances) {
42.293 + // Try to look up the currency code in the instances table.
42.294 + // This does the null pointer check as a side effect.
42.295 + // Also, if there already is an entry, the currencyCode must be valid.
42.296 + Currency instance = instances.get(currencyCode);
42.297 + if (instance != null) {
42.298 + return instance;
42.299 + }
42.300 +
42.301 + if (defaultFractionDigits == Integer.MIN_VALUE) {
42.302 + // Currency code not internally generated, need to verify first
42.303 + // A currency code must have 3 characters and exist in the main table
42.304 + // or in the list of other currencies.
42.305 + if (currencyCode.length() != 3) {
42.306 + throw new IllegalArgumentException();
42.307 + }
42.308 + char char1 = currencyCode.charAt(0);
42.309 + char char2 = currencyCode.charAt(1);
42.310 + int tableEntry = getMainTableEntry(char1, char2);
42.311 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
42.312 + && tableEntry != INVALID_COUNTRY_ENTRY
42.313 + && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
42.314 + defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
42.315 + numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
42.316 + } else {
42.317 + // Check for '-' separately so we don't get false hits in the table.
42.318 + if (currencyCode.charAt(2) == '-') {
42.319 + throw new IllegalArgumentException();
42.320 + }
42.321 + int index = otherCurrencies.indexOf(currencyCode);
42.322 + if (index == -1) {
42.323 + throw new IllegalArgumentException();
42.324 + }
42.325 + defaultFractionDigits = otherCurrenciesDFD[index / 4];
42.326 + numericCode = otherCurrenciesNumericCode[index / 4];
42.327 + }
42.328 + }
42.329 +
42.330 + instance = new Currency(currencyCode, defaultFractionDigits, numericCode);
42.331 + instances.put(currencyCode, instance);
42.332 + return instance;
42.333 + }
42.334 + }
42.335 +
42.336 + /**
42.337 + * Returns the <code>Currency</code> instance for the country of the
42.338 + * given locale. The language and variant components of the locale
42.339 + * are ignored. The result may vary over time, as countries change their
42.340 + * currencies. For example, for the original member countries of the
42.341 + * European Monetary Union, the method returns the old national currencies
42.342 + * until December 31, 2001, and the Euro from January 1, 2002, local time
42.343 + * of the respective countries.
42.344 + * <p>
42.345 + * The method returns <code>null</code> for territories that don't
42.346 + * have a currency, such as Antarctica.
42.347 + *
42.348 + * @param locale the locale for whose country a <code>Currency</code>
42.349 + * instance is needed
42.350 + * @return the <code>Currency</code> instance for the country of the given
42.351 + * locale, or null
42.352 + * @exception NullPointerException if <code>locale</code> or its country
42.353 + * code is null
42.354 + * @exception IllegalArgumentException if the country of the given locale
42.355 + * is not a supported ISO 3166 country code.
42.356 + */
42.357 + public static Currency getInstance(Locale locale) {
42.358 + String country = locale.getCountry();
42.359 + if (country == null) {
42.360 + throw new NullPointerException();
42.361 + }
42.362 +
42.363 + if (country.length() != 2) {
42.364 + throw new IllegalArgumentException();
42.365 + }
42.366 +
42.367 + char char1 = country.charAt(0);
42.368 + char char2 = country.charAt(1);
42.369 + int tableEntry = getMainTableEntry(char1, char2);
42.370 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
42.371 + && tableEntry != INVALID_COUNTRY_ENTRY) {
42.372 + char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
42.373 + int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
42.374 + int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
42.375 + StringBuffer sb = new StringBuffer(country);
42.376 + sb.append(finalChar);
42.377 + return getInstance(sb.toString(), defaultFractionDigits, numericCode);
42.378 + } else {
42.379 + // special cases
42.380 + if (tableEntry == INVALID_COUNTRY_ENTRY) {
42.381 + throw new IllegalArgumentException();
42.382 + }
42.383 + if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
42.384 + return null;
42.385 + } else {
42.386 + int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
42.387 + if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
42.388 + return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
42.389 + scOldCurrenciesNumericCode[index]);
42.390 + } else {
42.391 + return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
42.392 + scNewCurrenciesNumericCode[index]);
42.393 + }
42.394 + }
42.395 + }
42.396 + }
42.397 +
42.398 + /**
42.399 + * Gets the set of available currencies. The returned set of currencies
42.400 + * contains all of the available currencies, which may include currencies
42.401 + * that represent obsolete ISO 4217 codes. The set can be modified
42.402 + * without affecting the available currencies in the runtime.
42.403 + *
42.404 + * @return the set of available currencies. If there is no currency
42.405 + * available in the runtime, the returned set is empty.
42.406 + * @since 1.7
42.407 + */
42.408 + public static Set<Currency> getAvailableCurrencies() {
42.409 + synchronized(Currency.class) {
42.410 + if (available == null) {
42.411 + available = new HashSet<Currency>(256);
42.412 +
42.413 + // Add simple currencies first
42.414 + for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
42.415 + for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
42.416 + int tableEntry = getMainTableEntry(c1, c2);
42.417 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
42.418 + && tableEntry != INVALID_COUNTRY_ENTRY) {
42.419 + char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
42.420 + int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
42.421 + int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
42.422 + StringBuilder sb = new StringBuilder();
42.423 + sb.append(c1);
42.424 + sb.append(c2);
42.425 + sb.append(finalChar);
42.426 + available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
42.427 + }
42.428 + }
42.429 + }
42.430 +
42.431 + // Now add other currencies
42.432 + StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
42.433 + while (st.hasMoreElements()) {
42.434 + available.add(getInstance((String)st.nextElement()));
42.435 + }
42.436 + }
42.437 + }
42.438 +
42.439 + return (Set<Currency>) available.clone();
42.440 + }
42.441 +
42.442 + /**
42.443 + * Gets the ISO 4217 currency code of this currency.
42.444 + *
42.445 + * @return the ISO 4217 currency code of this currency.
42.446 + */
42.447 + public String getCurrencyCode() {
42.448 + return currencyCode;
42.449 + }
42.450 +
42.451 + /**
42.452 + * Gets the symbol of this currency for the default locale.
42.453 + * For example, for the US Dollar, the symbol is "$" if the default
42.454 + * locale is the US, while for other locales it may be "US$". If no
42.455 + * symbol can be determined, the ISO 4217 currency code is returned.
42.456 + *
42.457 + * @return the symbol of this currency for the default locale
42.458 + */
42.459 + public String getSymbol() {
42.460 + return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
42.461 + }
42.462 +
42.463 + /**
42.464 + * Gets the symbol of this currency for the specified locale.
42.465 + * For example, for the US Dollar, the symbol is "$" if the specified
42.466 + * locale is the US, while for other locales it may be "US$". If no
42.467 + * symbol can be determined, the ISO 4217 currency code is returned.
42.468 + *
42.469 + * @param locale the locale for which a display name for this currency is
42.470 + * needed
42.471 + * @return the symbol of this currency for the specified locale
42.472 + * @exception NullPointerException if <code>locale</code> is null
42.473 + */
42.474 + public String getSymbol(Locale locale) {
42.475 + try {
42.476 + // Check whether a provider can provide an implementation that's closer
42.477 + // to the requested locale than what the Java runtime itself can provide.
42.478 + LocaleServiceProviderPool pool =
42.479 + LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
42.480 +
42.481 + if (pool.hasProviders()) {
42.482 + // Assuming that all the country locales include necessary currency
42.483 + // symbols in the Java runtime's resources, so there is no need to
42.484 + // examine whether Java runtime's currency resource bundle is missing
42.485 + // names. Therefore, no resource bundle is provided for calling this
42.486 + // method.
42.487 + String symbol = pool.getLocalizedObject(
42.488 + CurrencyNameGetter.INSTANCE,
42.489 + locale, (OpenListResourceBundle)null,
42.490 + currencyCode, SYMBOL);
42.491 + if (symbol != null) {
42.492 + return symbol;
42.493 + }
42.494 + }
42.495 +
42.496 + ResourceBundle bundle = LocaleData.getCurrencyNames(locale);
42.497 + return bundle.getString(currencyCode);
42.498 + } catch (MissingResourceException e) {
42.499 + // use currency code as symbol of last resort
42.500 + return currencyCode;
42.501 + }
42.502 + }
42.503 +
42.504 + /**
42.505 + * Gets the default number of fraction digits used with this currency.
42.506 + * For example, the default number of fraction digits for the Euro is 2,
42.507 + * while for the Japanese Yen it's 0.
42.508 + * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
42.509 + * -1 is returned.
42.510 + *
42.511 + * @return the default number of fraction digits used with this currency
42.512 + */
42.513 + public int getDefaultFractionDigits() {
42.514 + return defaultFractionDigits;
42.515 + }
42.516 +
42.517 + /**
42.518 + * Returns the ISO 4217 numeric code of this currency.
42.519 + *
42.520 + * @return the ISO 4217 numeric code of this currency
42.521 + * @since 1.7
42.522 + */
42.523 + public int getNumericCode() {
42.524 + return numericCode;
42.525 + }
42.526 +
42.527 + /**
42.528 + * Gets the name that is suitable for displaying this currency for
42.529 + * the default locale. If there is no suitable display name found
42.530 + * for the default locale, the ISO 4217 currency code is returned.
42.531 + *
42.532 + * @return the display name of this currency for the default locale
42.533 + * @since 1.7
42.534 + */
42.535 + public String getDisplayName() {
42.536 + return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
42.537 + }
42.538 +
42.539 + /**
42.540 + * Gets the name that is suitable for displaying this currency for
42.541 + * the specified locale. If there is no suitable display name found
42.542 + * for the specified locale, the ISO 4217 currency code is returned.
42.543 + *
42.544 + * @param locale the locale for which a display name for this currency is
42.545 + * needed
42.546 + * @return the display name of this currency for the specified locale
42.547 + * @exception NullPointerException if <code>locale</code> is null
42.548 + * @since 1.7
42.549 + */
42.550 + public String getDisplayName(Locale locale) {
42.551 + try {
42.552 + OpenListResourceBundle bundle = LocaleData.getCurrencyNames(locale);
42.553 + String result = null;
42.554 + String bundleKey = currencyCode.toLowerCase(Locale.ROOT);
42.555 +
42.556 + // Check whether a provider can provide an implementation that's closer
42.557 + // to the requested locale than what the Java runtime itself can provide.
42.558 + LocaleServiceProviderPool pool =
42.559 + LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
42.560 + if (pool.hasProviders()) {
42.561 + result = pool.getLocalizedObject(
42.562 + CurrencyNameGetter.INSTANCE,
42.563 + locale, bundleKey, bundle, currencyCode, DISPLAYNAME);
42.564 + }
42.565 +
42.566 + if (result == null) {
42.567 + result = bundle.getString(bundleKey);
42.568 + }
42.569 +
42.570 + if (result != null) {
42.571 + return result;
42.572 + }
42.573 + } catch (MissingResourceException e) {
42.574 + // fall through
42.575 + }
42.576 +
42.577 + // use currency code as symbol of last resort
42.578 + return currencyCode;
42.579 + }
42.580 +
42.581 + /**
42.582 + * Returns the ISO 4217 currency code of this currency.
42.583 + *
42.584 + * @return the ISO 4217 currency code of this currency
42.585 + */
42.586 + public String toString() {
42.587 + return currencyCode;
42.588 + }
42.589 +
42.590 + /**
42.591 + * Resolves instances being deserialized to a single instance per currency.
42.592 + */
42.593 + private Object readResolve() {
42.594 + return getInstance(currencyCode);
42.595 + }
42.596 +
42.597 + /**
42.598 + * Gets the main table entry for the country whose country code consists
42.599 + * of char1 and char2.
42.600 + */
42.601 + private static int getMainTableEntry(char char1, char char2) {
42.602 + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
42.603 + throw new IllegalArgumentException();
42.604 + }
42.605 + return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
42.606 + }
42.607 +
42.608 + /**
42.609 + * Sets the main table entry for the country whose country code consists
42.610 + * of char1 and char2.
42.611 + */
42.612 + private static void setMainTableEntry(char char1, char char2, int entry) {
42.613 + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
42.614 + throw new IllegalArgumentException();
42.615 + }
42.616 + mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
42.617 + }
42.618 +
42.619 + /**
42.620 + * Obtains a localized currency names from a CurrencyNameProvider
42.621 + * implementation.
42.622 + */
42.623 + private static class CurrencyNameGetter
42.624 + implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
42.625 + String> {
42.626 + private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
42.627 +
42.628 + public String getObject(CurrencyNameProvider currencyNameProvider,
42.629 + Locale locale,
42.630 + String key,
42.631 + Object... params) {
42.632 + assert params.length == 1;
42.633 + int type = (Integer)params[0];
42.634 +
42.635 + switch(type) {
42.636 + case SYMBOL:
42.637 + return currencyNameProvider.getSymbol(key, locale);
42.638 + case DISPLAYNAME:
42.639 + return currencyNameProvider.getDisplayName(key, locale);
42.640 + default:
42.641 + assert false; // shouldn't happen
42.642 + }
42.643 +
42.644 + return null;
42.645 + }
42.646 + }
42.647 +
42.648 + private static int[] readIntArray(DataInputStream dis, int count) throws IOException {
42.649 + int[] ret = new int[count];
42.650 + for (int i = 0; i < count; i++) {
42.651 + ret[i] = dis.readInt();
42.652 + }
42.653 +
42.654 + return ret;
42.655 + }
42.656 +
42.657 + private static long[] readLongArray(DataInputStream dis, int count) throws IOException {
42.658 + long[] ret = new long[count];
42.659 + for (int i = 0; i < count; i++) {
42.660 + ret[i] = dis.readLong();
42.661 + }
42.662 +
42.663 + return ret;
42.664 + }
42.665 +
42.666 + private static String[] readStringArray(DataInputStream dis, int count) throws IOException {
42.667 + String[] ret = new String[count];
42.668 + for (int i = 0; i < count; i++) {
42.669 + ret[i] = dis.readUTF();
42.670 + }
42.671 +
42.672 + return ret;
42.673 + }
42.674 +
42.675 + /**
42.676 + * Replaces currency data found in the currencydata.properties file
42.677 + *
42.678 + * @param pattern regex pattern for the properties
42.679 + * @param ctry country code
42.680 + * @param data currency data. This is a comma separated string that
42.681 + * consists of "three-letter alphabet code", "three-digit numeric code",
42.682 + * and "one-digit (0,1,2, or 3) default fraction digit".
42.683 + * For example, "JPZ,392,0".
42.684 + * @throws
42.685 + */
42.686 + private static void replaceCurrencyData(Pattern pattern, String ctry, String curdata) {
42.687 +
42.688 + if (ctry.length() != 2) {
42.689 + // ignore invalid country code
42.690 + String message = new StringBuilder()
42.691 + .append("The entry in currency.properties for ")
42.692 + .append(ctry).append(" is ignored because of the invalid country code.")
42.693 + .toString();
42.694 + info(message, null);
42.695 + return;
42.696 + }
42.697 +
42.698 + Matcher m = pattern.matcher(curdata);
42.699 + if (!m.find()) {
42.700 + // format is not recognized. ignore the data
42.701 + String message = new StringBuilder()
42.702 + .append("The entry in currency.properties for ")
42.703 + .append(ctry)
42.704 + .append(" is ignored because the value format is not recognized.")
42.705 + .toString();
42.706 + info(message, null);
42.707 + return;
42.708 + }
42.709 +
42.710 + String code = m.group(1);
42.711 + int numeric = Integer.parseInt(m.group(2));
42.712 + int fraction = Integer.parseInt(m.group(3));
42.713 + int entry = numeric << NUMERIC_CODE_SHIFT;
42.714 +
42.715 + int index;
42.716 + for (index = 0; index < scOldCurrencies.length; index++) {
42.717 + if (scOldCurrencies[index].equals(code)) {
42.718 + break;
42.719 + }
42.720 + }
42.721 +
42.722 + if (index == scOldCurrencies.length) {
42.723 + // simple case
42.724 + entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) |
42.725 + (code.charAt(2) - 'A');
42.726 + } else {
42.727 + // special case
42.728 + entry |= SPECIAL_CASE_COUNTRY_MASK |
42.729 + (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
42.730 + }
42.731 + setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
42.732 + }
42.733 +
42.734 + private static void info(String message, Throwable t) {
42.735 + PlatformLogger logger = PlatformLogger.getLogger("java.util.Currency");
42.736 + if (logger.isLoggable(PlatformLogger.INFO)) {
42.737 + if (t != null) {
42.738 + logger.info(message, t);
42.739 + } else {
42.740 + logger.info(message);
42.741 + }
42.742 + }
42.743 + }
42.744 +}
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/rt/emul/compact/src/main/java/java/util/CurrencyData.properties Thu Oct 03 15:43:10 2013 +0200
43.3 @@ -0,0 +1,586 @@
43.4 +#
43.5 +# Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
43.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
43.7 +#
43.8 +# This code is free software; you can redistribute it and/or modify it
43.9 +# under the terms of the GNU General Public License version 2 only, as
43.10 +# published by the Free Software Foundation. Oracle designates this
43.11 +# particular file as subject to the "Classpath" exception as provided
43.12 +# by Oracle in the LICENSE file that accompanied this code.
43.13 +#
43.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
43.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
43.16 +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
43.17 +# version 2 for more details (a copy is included in the LICENSE file that
43.18 +# accompanied this code).
43.19 +#
43.20 +# You should have received a copy of the GNU General Public License version
43.21 +# 2 along with this work; if not, write to the Free Software Foundation,
43.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
43.23 +#
43.24 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
43.25 +# or visit www.oracle.com if you need additional information or have any
43.26 +# questions.
43.27 +#
43.28 +
43.29 +formatVersion=1
43.30 +
43.31 +# Version of the currency code information in this class.
43.32 +# It is a serial number that accompanies with each amendment, such as
43.33 +# 'MAxxx.doc'
43.34 +
43.35 +dataVersion=140
43.36 +
43.37 +# List of all valid ISO 4217 currency codes.
43.38 +# To ensure compatibility, do not remove codes.
43.39 +
43.40 +all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036-\
43.41 + AWG533-AYM945-AZM031-AZN944-BAM977-BBD052-BDT050-BEF056-BGL100-BGN975-BHD048-BIF108-\
43.42 + BMD060-BND096-BOB068-BOV984-BRL986-BSD044-BTN064-BWP072-BYB112-BYR974-\
43.43 + BZD084-CAD124-CDF976-CHF756-CLF990-CLP152-CNY156-COP170-CRC188-CSD891-CUP192-\
43.44 + CVE132-CYP196-CZK203-DEM276-DJF262-DKK208-DOP214-DZD012-EEK233-EGP818-\
43.45 + ERN232-ESP724-ETB230-EUR978-FIM246-FJD242-FKP238-FRF250-GBP826-GEL981-\
43.46 + GHC288-GHS936-GIP292-GMD270-GNF324-GRD300-GTQ320-GWP624-GYD328-HKD344-HNL340-\
43.47 + HRK191-HTG332-HUF348-IDR360-IEP372-ILS376-INR356-IQD368-IRR364-ISK352-\
43.48 + ITL380-JMD388-JOD400-JPY392-KES404-KGS417-KHR116-KMF174-KPW408-KRW410-\
43.49 + KWD414-KYD136-KZT398-LAK418-LBP422-LKR144-LRD430-LSL426-LTL440-LUF442-\
43.50 + LVL428-LYD434-MAD504-MDL498-MGA969-MGF450-MKD807-MMK104-MNT496-MOP446-MRO478-\
43.51 + MTL470-MUR480-MVR462-MWK454-MXN484-MXV979-MYR458-MZM508-MZN943-NAD516-NGN566-\
43.52 + NIO558-NLG528-NOK578-NPR524-NZD554-OMR512-PAB590-PEN604-PGK598-PHP608-\
43.53 + PKR586-PLN985-PTE620-PYG600-QAR634-ROL946-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\
43.54 + SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\
43.55 + SRD968-SRG740-STD678-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TND788-TOP776-\
43.56 + TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-\
43.57 + UYU858-UZS860-VEB862-VEF937-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\
43.58 + XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\
43.59 + XPT962-XTS963-XXX999-YER886-YUM891-ZAR710-ZMK894-ZWD716-ZWN942
43.60 +
43.61 +
43.62 +# Mappings from ISO 3166 country codes to ISO 4217 currency codes.
43.63 +#
43.64 +# Three forms are used:
43.65 +# Form 1: <country code>=<currency code>
43.66 +# Form 2: <country code>=<currency code 1>;<time stamp>;<currency code 2>
43.67 +# Form 3: <country code>=
43.68 +# Form 1 is used if no future change in currency is known.
43.69 +# Form 2 indicates that before the specified time currency 1 is used, from
43.70 +# the specified time currency 2. The time is given in SimpleDateFormat's
43.71 +# yyyy-MM-dd-HH-mm-ss format in the GMT time zone.
43.72 +# Form 3 indicates the country doesn't have a currency (the entry is still
43.73 +# needed to verify that the country code is valid).
43.74 +#
43.75 +# The table is based on the following web sites:
43.76 +# http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/db_en.html
43.77 +# http://www.bsi-global.com/iso4217currency
43.78 +# http://www.cia.gov/cia/publications/factbook/indexgeo.html
43.79 +
43.80 +# AFGHANISTAN
43.81 +AF=AFN
43.82 +# \u00c5LAND ISLANDS
43.83 +AX=EUR
43.84 +# ALBANIA
43.85 +AL=ALL
43.86 +# ALGERIA
43.87 +DZ=DZD
43.88 +# AMERICAN SAMOA
43.89 +AS=USD
43.90 +# ANDORRA
43.91 +AD=EUR
43.92 +# ANGOLA
43.93 +AO=AOA
43.94 +# ANGUILLA
43.95 +AI=XCD
43.96 +# ANTARCTICA
43.97 +AQ=
43.98 +# ANTIGUA AND BARBUDA
43.99 +AG=XCD
43.100 +# ARGENTINA
43.101 +AR=ARS
43.102 +# ARMENIA
43.103 +AM=AMD
43.104 +# ARUBA
43.105 +AW=AWG
43.106 +# AUSTRALIA
43.107 +AU=AUD
43.108 +# AUSTRIA
43.109 +AT=EUR
43.110 +# AZERBAIJAN
43.111 +AZ=AZM;2005-12-31-20-00-00;AZN
43.112 +# BAHAMAS
43.113 +BS=BSD
43.114 +# BAHRAIN
43.115 +BH=BHD
43.116 +# BANGLADESH
43.117 +BD=BDT
43.118 +# BARBADOS
43.119 +BB=BBD
43.120 +# BELARUS
43.121 +BY=BYR
43.122 +# BELGIUM
43.123 +BE=EUR
43.124 +# BELIZE
43.125 +BZ=BZD
43.126 +# BENIN
43.127 +BJ=XOF
43.128 +# BERMUDA
43.129 +BM=BMD
43.130 +# BHUTAN
43.131 +BT=BTN
43.132 +# BOLIVIA
43.133 +BO=BOB
43.134 +# BOSNIA AND HERZEGOVINA
43.135 +BA=BAM
43.136 +# BOTSWANA
43.137 +BW=BWP
43.138 +# BOUVET ISLAND
43.139 +BV=NOK
43.140 +# BRAZIL
43.141 +BR=BRL
43.142 +# BRITISH INDIAN OCEAN TERRITORY
43.143 +IO=USD
43.144 +# BRUNEI DARUSSALAM
43.145 +BN=BND
43.146 +# BULGARIA
43.147 +BG=BGN
43.148 +# BURKINA FASO
43.149 +BF=XOF
43.150 +# BURUNDI
43.151 +BI=BIF
43.152 +# CAMBODIA
43.153 +KH=KHR
43.154 +# CAMEROON
43.155 +CM=XAF
43.156 +# CANADA
43.157 +CA=CAD
43.158 +# CAPE VERDE
43.159 +CV=CVE
43.160 +# CAYMAN ISLANDS
43.161 +KY=KYD
43.162 +# CENTRAL AFRICAN REPUBLIC
43.163 +CF=XAF
43.164 +# CHAD
43.165 +TD=XAF
43.166 +# CHILE
43.167 +CL=CLP
43.168 +# CHINA
43.169 +CN=CNY
43.170 +# CHRISTMAS ISLAND
43.171 +CX=AUD
43.172 +# COCOS (KEELING) ISLANDS
43.173 +CC=AUD
43.174 +# COLOMBIA
43.175 +CO=COP
43.176 +# COMOROS
43.177 +KM=KMF
43.178 +# CONGO
43.179 +CG=XAF
43.180 +# CONGO, THE DEMOCRATIC REPUBLIC OF THE
43.181 +CD=CDF
43.182 +# COOK ISLANDS
43.183 +CK=NZD
43.184 +# COSTA RICA
43.185 +CR=CRC
43.186 +# COTE D'IVOIRE
43.187 +CI=XOF
43.188 +# CROATIA
43.189 +HR=HRK
43.190 +# CUBA
43.191 +CU=CUP
43.192 +# CYPRUS
43.193 +CY=EUR
43.194 +# CZECH REPUBLIC
43.195 +CZ=CZK
43.196 +# DENMARK
43.197 +DK=DKK
43.198 +# DJIBOUTI
43.199 +DJ=DJF
43.200 +# DOMINICA
43.201 +DM=XCD
43.202 +# DOMINICAN REPUBLIC
43.203 +DO=DOP
43.204 +# ECUADOR
43.205 +EC=USD
43.206 +# EGYPT
43.207 +EG=EGP
43.208 +# EL SALVADOR
43.209 +# USD is also legal currency as of 2001/01/01
43.210 +SV=SVC
43.211 +# EQUATORIAL GUINEA
43.212 +GQ=XAF
43.213 +# ERITREA
43.214 +ER=ERN
43.215 +# ESTONIA
43.216 +EE=EEK
43.217 +# ETHIOPIA
43.218 +ET=ETB
43.219 +# FALKLAND ISLANDS (MALVINAS)
43.220 +FK=FKP
43.221 +# FAROE ISLANDS
43.222 +FO=DKK
43.223 +# FIJI
43.224 +FJ=FJD
43.225 +# FINLAND
43.226 +FI=EUR
43.227 +# FRANCE
43.228 +FR=EUR
43.229 +# FRENCH GUIANA
43.230 +GF=EUR
43.231 +# FRENCH POLYNESIA
43.232 +PF=XPF
43.233 +# FRENCH SOUTHERN TERRITORIES
43.234 +TF=EUR
43.235 +# GABON
43.236 +GA=XAF
43.237 +# GAMBIA
43.238 +GM=GMD
43.239 +# GEORGIA
43.240 +GE=GEL
43.241 +# GERMANY
43.242 +DE=EUR
43.243 +# GHANA
43.244 +GH=GHS
43.245 +# GIBRALTAR
43.246 +GI=GIP
43.247 +# GREECE
43.248 +GR=EUR
43.249 +# GREENLAND
43.250 +GL=DKK
43.251 +# GRENADA
43.252 +GD=XCD
43.253 +# GUADELOUPE
43.254 +GP=EUR
43.255 +# GUAM
43.256 +GU=USD
43.257 +# GUATEMALA
43.258 +GT=GTQ
43.259 +# GUERNSEY
43.260 +GG=GBP
43.261 +# GUINEA
43.262 +GN=GNF
43.263 +# GUINEA-BISSAU
43.264 +GW=XOF
43.265 +# GUYANA
43.266 +GY=GYD
43.267 +# HAITI
43.268 +HT=HTG
43.269 +# HEARD ISLAND AND MCDONALD ISLANDS
43.270 +HM=AUD
43.271 +# HOLY SEE (VATICAN CITY STATE)
43.272 +VA=EUR
43.273 +# HONDURAS
43.274 +HN=HNL
43.275 +# HONG KONG
43.276 +HK=HKD
43.277 +# HUNGARY
43.278 +HU=HUF
43.279 +# ICELAND
43.280 +IS=ISK
43.281 +# INDIA
43.282 +IN=INR
43.283 +# INDONESIA
43.284 +ID=IDR
43.285 +# IRAN, ISLAMIC REPUBLIC OF
43.286 +IR=IRR
43.287 +# IRAQ
43.288 +IQ=IQD
43.289 +# IRELAND
43.290 +IE=EUR
43.291 +# ISLE OF MAN
43.292 +IM=GBP
43.293 +# ISRAEL
43.294 +IL=ILS
43.295 +# ITALY
43.296 +IT=EUR
43.297 +# JAMAICA
43.298 +JM=JMD
43.299 +# JAPAN
43.300 +JP=JPY
43.301 +# JERSEY
43.302 +JE=GBP
43.303 +# JORDAN
43.304 +JO=JOD
43.305 +# KAZAKSTAN
43.306 +KZ=KZT
43.307 +# KENYA
43.308 +KE=KES
43.309 +# KIRIBATI
43.310 +KI=AUD
43.311 +# KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF
43.312 +KP=KPW
43.313 +# KOREA, REPUBLIC OF
43.314 +KR=KRW
43.315 +# KUWAIT
43.316 +KW=KWD
43.317 +# KYRGYZSTAN
43.318 +KG=KGS
43.319 +# LAO PEOPLE'S DEMOCRATIC REPUBLIC
43.320 +LA=LAK
43.321 +# LATVIA
43.322 +LV=LVL
43.323 +# LEBANON
43.324 +LB=LBP
43.325 +# LESOTHO
43.326 +LS=LSL
43.327 +# LIBERIA
43.328 +LR=LRD
43.329 +# LIBYAN ARAB JAMAHIRIYA
43.330 +LY=LYD
43.331 +# LIECHTENSTEIN
43.332 +LI=CHF
43.333 +# LITHUANIA
43.334 +LT=LTL
43.335 +# LUXEMBOURG
43.336 +LU=EUR
43.337 +# MACAU
43.338 +MO=MOP
43.339 +# MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF
43.340 +MK=MKD
43.341 +# MADAGASCAR
43.342 +MG=MGA
43.343 +# MALAWI
43.344 +MW=MWK
43.345 +# MALAYSIA
43.346 +MY=MYR
43.347 +# MALDIVES
43.348 +MV=MVR
43.349 +# MALI
43.350 +ML=XOF
43.351 +# MALTA
43.352 +MT=EUR
43.353 +# MARSHALL ISLANDS
43.354 +MH=USD
43.355 +# MARTINIQUE
43.356 +MQ=EUR
43.357 +# MAURITANIA
43.358 +MR=MRO
43.359 +# MAURITIUS
43.360 +MU=MUR
43.361 +# MAYOTTE
43.362 +YT=EUR
43.363 +# MEXICO
43.364 +MX=MXN
43.365 +# MICRONESIA, FEDERATED STATES OF
43.366 +FM=USD
43.367 +# MOLDOVA, REPUBLIC OF
43.368 +MD=MDL
43.369 +# MONACO
43.370 +MC=EUR
43.371 +# MONGOLIA
43.372 +MN=MNT
43.373 +# MONTENEGRO
43.374 +ME=EUR
43.375 +# MONTSERRAT
43.376 +MS=XCD
43.377 +# MOROCCO
43.378 +MA=MAD
43.379 +# MOZAMBIQUE
43.380 +MZ=MZM;2006-06-30-22-00-00;MZN
43.381 +# MYANMAR
43.382 +MM=MMK
43.383 +# NAMIBIA
43.384 +NA=NAD
43.385 +# NAURU
43.386 +NR=AUD
43.387 +# NEPAL
43.388 +NP=NPR
43.389 +# NETHERLANDS
43.390 +NL=EUR
43.391 +# NETHERLANDS ANTILLES
43.392 +AN=ANG
43.393 +# NEW CALEDONIA
43.394 +NC=XPF
43.395 +# NEW ZEALAND
43.396 +NZ=NZD
43.397 +# NICARAGUA
43.398 +NI=NIO
43.399 +# NIGER
43.400 +NE=XOF
43.401 +# NIGERIA
43.402 +NG=NGN
43.403 +# NIUE
43.404 +NU=NZD
43.405 +# NORFOLK ISLAND
43.406 +NF=AUD
43.407 +# NORTHERN MARIANA ISLANDS
43.408 +MP=USD
43.409 +# NORWAY
43.410 +NO=NOK
43.411 +# OMAN
43.412 +OM=OMR
43.413 +# PAKISTAN
43.414 +PK=PKR
43.415 +# PALAU
43.416 +PW=USD
43.417 +# PALESTINIAN TERRITORY, OCCUPIED
43.418 +PS=ILS
43.419 +# PANAMA
43.420 +PA=PAB
43.421 +# PAPUA NEW GUINEA
43.422 +PG=PGK
43.423 +# PARAGUAY
43.424 +PY=PYG
43.425 +# PERU
43.426 +PE=PEN
43.427 +# PHILIPPINES
43.428 +PH=PHP
43.429 +# PITCAIRN
43.430 +PN=NZD
43.431 +# POLAND
43.432 +PL=PLN
43.433 +# PORTUGAL
43.434 +PT=EUR
43.435 +# PUERTO RICO
43.436 +PR=USD
43.437 +# QATAR
43.438 +QA=QAR
43.439 +# REUNION
43.440 +RE=EUR
43.441 +# ROMANIA
43.442 +RO=ROL;2005-06-30-21-00-00;RON
43.443 +# RUSSIAN FEDERATION
43.444 +RU=RUB
43.445 +# RWANDA
43.446 +RW=RWF
43.447 +# SAINT BARTHELEMY
43.448 +BL=EUR
43.449 +# SAINT HELENA
43.450 +SH=SHP
43.451 +# SAINT KITTS AND NEVIS
43.452 +KN=XCD
43.453 +# SAINT LUCIA
43.454 +LC=XCD
43.455 +# SAINT MARTIN
43.456 +MF=EUR
43.457 +# SAINT PIERRE AND MIQUELON
43.458 +PM=EUR
43.459 +# SAINT VINCENT AND THE GRENADINES
43.460 +VC=XCD
43.461 +# SAMOA
43.462 +WS=WST
43.463 +# SAN MARINO
43.464 +SM=EUR
43.465 +# SAO TOME AND PRINCIPE
43.466 +ST=STD
43.467 +# SAUDI ARABIA
43.468 +SA=SAR
43.469 +# SENEGAL
43.470 +SN=XOF
43.471 +# SERBIA
43.472 +RS=RSD
43.473 +# SERBIA AND MONTENEGRO
43.474 +CS=CSD
43.475 +# SEYCHELLES
43.476 +SC=SCR
43.477 +# SIERRA LEONE
43.478 +SL=SLL
43.479 +# SINGAPORE
43.480 +SG=SGD
43.481 +# SLOVAKIA
43.482 +SK=SKK
43.483 +# SLOVENIA
43.484 +SI=EUR
43.485 +# SOLOMON ISLANDS
43.486 +SB=SBD
43.487 +# SOMALIA
43.488 +SO=SOS
43.489 +# SOUTH AFRICA
43.490 +ZA=ZAR
43.491 +# SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS
43.492 +GS=GBP
43.493 +# SPAIN
43.494 +ES=EUR
43.495 +# SRI LANKA
43.496 +LK=LKR
43.497 +# SUDAN
43.498 +SD=SDG
43.499 +# SURINAME
43.500 +SR=SRD
43.501 +# SVALBARD AND JAN MAYEN
43.502 +SJ=NOK
43.503 +# SWAZILAND
43.504 +SZ=SZL
43.505 +# SWEDEN
43.506 +SE=SEK
43.507 +# SWITZERLAND
43.508 +CH=CHF
43.509 +# SYRIAN ARAB REPUBLIC
43.510 +SY=SYP
43.511 +# TAIWAN
43.512 +TW=TWD
43.513 +# TAJIKISTAN
43.514 +TJ=TJS
43.515 +# TANZANIA, UNITED REPUBLIC OF
43.516 +TZ=TZS
43.517 +# THAILAND
43.518 +TH=THB
43.519 +# TIMOR-LESTE
43.520 +TL=USD
43.521 +# TOGO
43.522 +TG=XOF
43.523 +# TOKELAU
43.524 +TK=NZD
43.525 +# TONGA
43.526 +TO=TOP
43.527 +# TRINIDAD AND TOBAGO
43.528 +TT=TTD
43.529 +# TUNISIA
43.530 +TN=TND
43.531 +# TURKEY
43.532 +TR=TRL;2004-12-31-22-00-00;TRY
43.533 +# TURKMENISTAN
43.534 +TM=TMM
43.535 +# TURKS AND CAICOS ISLANDS
43.536 +TC=USD
43.537 +# TUVALU
43.538 +TV=AUD
43.539 +# UGANDA
43.540 +UG=UGX
43.541 +# UKRAINE
43.542 +UA=UAH
43.543 +# UNITED ARAB EMIRATES
43.544 +AE=AED
43.545 +# UNITED KINGDOM
43.546 +GB=GBP
43.547 +# UNITED STATES
43.548 +US=USD
43.549 +# UNITED STATES MINOR OUTLYING ISLANDS
43.550 +UM=USD
43.551 +# URUGUAY
43.552 +UY=UYU
43.553 +# UZBEKISTAN
43.554 +UZ=UZS
43.555 +# VANUATU
43.556 +VU=VUV
43.557 +# VENEZUELA
43.558 +VE=VEB;2008-01-01-04-00-00;VEF
43.559 +# VIET NAM
43.560 +VN=VND
43.561 +# VIRGIN ISLANDS, BRITISH
43.562 +VG=USD
43.563 +# VIRGIN ISLANDS, U.S.
43.564 +VI=USD
43.565 +# WALLIS AND FUTUNA
43.566 +WF=XPF
43.567 +# WESTERN SAHARA
43.568 +EH=MAD
43.569 +# YEMEN
43.570 +YE=YER
43.571 +# ZAMBIA
43.572 +ZM=ZMK
43.573 +# ZIMBABWE
43.574 +ZW=ZWD
43.575 +
43.576 +
43.577 +# List of currencies with 0, 1, OR 3 decimals for minor units, or where there
43.578 +# are no minor units defined. All others use 2 decimals.
43.579 +
43.580 +minor0=\
43.581 + ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\
43.582 + GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
43.583 + TPE-TRL-VUV-XAF-XOF-XPF
43.584 +minor1=
43.585 +minor3=\
43.586 + BHD-IQD-JOD-KWD-LYD-OMR-TND
43.587 +minorUndefined=\
43.588 + XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-\
43.589 + XPT-XTS-XXX
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/rt/emul/compact/src/main/java/java/util/Date.java Thu Oct 03 15:43:10 2013 +0200
44.3 @@ -0,0 +1,1331 @@
44.4 +/*
44.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
44.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44.7 + *
44.8 + * This code is free software; you can redistribute it and/or modify it
44.9 + * under the terms of the GNU General Public License version 2 only, as
44.10 + * published by the Free Software Foundation. Oracle designates this
44.11 + * particular file as subject to the "Classpath" exception as provided
44.12 + * by Oracle in the LICENSE file that accompanied this code.
44.13 + *
44.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
44.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
44.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
44.17 + * version 2 for more details (a copy is included in the LICENSE file that
44.18 + * accompanied this code).
44.19 + *
44.20 + * You should have received a copy of the GNU General Public License version
44.21 + * 2 along with this work; if not, write to the Free Software Foundation,
44.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
44.23 + *
44.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
44.25 + * or visit www.oracle.com if you need additional information or have any
44.26 + * questions.
44.27 + */
44.28 +
44.29 +package java.util;
44.30 +
44.31 +import java.text.DateFormat;
44.32 +import java.io.IOException;
44.33 +import java.io.ObjectOutputStream;
44.34 +import java.io.ObjectInputStream;
44.35 +import java.lang.ref.SoftReference;
44.36 +import sun.util.calendar.BaseCalendar;
44.37 +import sun.util.calendar.CalendarDate;
44.38 +import sun.util.calendar.CalendarSystem;
44.39 +import sun.util.calendar.CalendarUtils;
44.40 +import sun.util.calendar.Era;
44.41 +import sun.util.calendar.Gregorian;
44.42 +import sun.util.calendar.ZoneInfo;
44.43 +
44.44 +/**
44.45 + * The class <code>Date</code> represents a specific instant
44.46 + * in time, with millisecond precision.
44.47 + * <p>
44.48 + * Prior to JDK 1.1, the class <code>Date</code> had two additional
44.49 + * functions. It allowed the interpretation of dates as year, month, day, hour,
44.50 + * minute, and second values. It also allowed the formatting and parsing
44.51 + * of date strings. Unfortunately, the API for these functions was not
44.52 + * amenable to internationalization. As of JDK 1.1, the
44.53 + * <code>Calendar</code> class should be used to convert between dates and time
44.54 + * fields and the <code>DateFormat</code> class should be used to format and
44.55 + * parse date strings.
44.56 + * The corresponding methods in <code>Date</code> are deprecated.
44.57 + * <p>
44.58 + * Although the <code>Date</code> class is intended to reflect
44.59 + * coordinated universal time (UTC), it may not do so exactly,
44.60 + * depending on the host environment of the Java Virtual Machine.
44.61 + * Nearly all modern operating systems assume that 1 day =
44.62 + * 24 × 60 × 60 = 86400 seconds
44.63 + * in all cases. In UTC, however, about once every year or two there
44.64 + * is an extra second, called a "leap second." The leap
44.65 + * second is always added as the last second of the day, and always
44.66 + * on December 31 or June 30. For example, the last minute of the
44.67 + * year 1995 was 61 seconds long, thanks to an added leap second.
44.68 + * Most computer clocks are not accurate enough to be able to reflect
44.69 + * the leap-second distinction.
44.70 + * <p>
44.71 + * Some computer standards are defined in terms of Greenwich mean
44.72 + * time (GMT), which is equivalent to universal time (UT). GMT is
44.73 + * the "civil" name for the standard; UT is the
44.74 + * "scientific" name for the same standard. The
44.75 + * distinction between UTC and UT is that UTC is based on an atomic
44.76 + * clock and UT is based on astronomical observations, which for all
44.77 + * practical purposes is an invisibly fine hair to split. Because the
44.78 + * earth's rotation is not uniform (it slows down and speeds up
44.79 + * in complicated ways), UT does not always flow uniformly. Leap
44.80 + * seconds are introduced as needed into UTC so as to keep UTC within
44.81 + * 0.9 seconds of UT1, which is a version of UT with certain
44.82 + * corrections applied. There are other time and date systems as
44.83 + * well; for example, the time scale used by the satellite-based
44.84 + * global positioning system (GPS) is synchronized to UTC but is
44.85 + * <i>not</i> adjusted for leap seconds. An interesting source of
44.86 + * further information is the U.S. Naval Observatory, particularly
44.87 + * the Directorate of Time at:
44.88 + * <blockquote><pre>
44.89 + * <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
44.90 + * </pre></blockquote>
44.91 + * <p>
44.92 + * and their definitions of "Systems of Time" at:
44.93 + * <blockquote><pre>
44.94 + * <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
44.95 + * </pre></blockquote>
44.96 + * <p>
44.97 + * In all methods of class <code>Date</code> that accept or return
44.98 + * year, month, date, hours, minutes, and seconds values, the
44.99 + * following representations are used:
44.100 + * <ul>
44.101 + * <li>A year <i>y</i> is represented by the integer
44.102 + * <i>y</i> <code>- 1900</code>.
44.103 + * <li>A month is represented by an integer from 0 to 11; 0 is January,
44.104 + * 1 is February, and so forth; thus 11 is December.
44.105 + * <li>A date (day of month) is represented by an integer from 1 to 31
44.106 + * in the usual manner.
44.107 + * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
44.108 + * from midnight to 1 a.m. is hour 0, and the hour from noon to 1
44.109 + * p.m. is hour 12.
44.110 + * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
44.111 + * <li>A second is represented by an integer from 0 to 61; the values 60 and
44.112 + * 61 occur only for leap seconds and even then only in Java
44.113 + * implementations that actually track leap seconds correctly. Because
44.114 + * of the manner in which leap seconds are currently introduced, it is
44.115 + * extremely unlikely that two leap seconds will occur in the same
44.116 + * minute, but this specification follows the date and time conventions
44.117 + * for ISO C.
44.118 + * </ul>
44.119 + * <p>
44.120 + * In all cases, arguments given to methods for these purposes need
44.121 + * not fall within the indicated ranges; for example, a date may be
44.122 + * specified as January 32 and is interpreted as meaning February 1.
44.123 + *
44.124 + * @author James Gosling
44.125 + * @author Arthur van Hoff
44.126 + * @author Alan Liu
44.127 + * @see java.text.DateFormat
44.128 + * @see java.util.Calendar
44.129 + * @see java.util.TimeZone
44.130 + * @since JDK1.0
44.131 + */
44.132 +public class Date
44.133 + implements java.io.Serializable, Cloneable, Comparable<Date>
44.134 +{
44.135 + private static final BaseCalendar gcal =
44.136 + CalendarSystem.getGregorianCalendar();
44.137 + private static BaseCalendar jcal;
44.138 +
44.139 + private transient long fastTime;
44.140 +
44.141 + /*
44.142 + * If cdate is null, then fastTime indicates the time in millis.
44.143 + * If cdate.isNormalized() is true, then fastTime and cdate are in
44.144 + * synch. Otherwise, fastTime is ignored, and cdate indicates the
44.145 + * time.
44.146 + */
44.147 + private transient BaseCalendar.Date cdate;
44.148 +
44.149 + // Initialized just before the value is used. See parse().
44.150 + private static int defaultCenturyStart;
44.151 +
44.152 + /* use serialVersionUID from modified java.util.Date for
44.153 + * interoperability with JDK1.1. The Date was modified to write
44.154 + * and read only the UTC time.
44.155 + */
44.156 + private static final long serialVersionUID = 7523967970034938905L;
44.157 +
44.158 + /**
44.159 + * Allocates a <code>Date</code> object and initializes it so that
44.160 + * it represents the time at which it was allocated, measured to the
44.161 + * nearest millisecond.
44.162 + *
44.163 + * @see java.lang.System#currentTimeMillis()
44.164 + */
44.165 + public Date() {
44.166 + this(System.currentTimeMillis());
44.167 + }
44.168 +
44.169 + /**
44.170 + * Allocates a <code>Date</code> object and initializes it to
44.171 + * represent the specified number of milliseconds since the
44.172 + * standard base time known as "the epoch", namely January 1,
44.173 + * 1970, 00:00:00 GMT.
44.174 + *
44.175 + * @param date the milliseconds since January 1, 1970, 00:00:00 GMT.
44.176 + * @see java.lang.System#currentTimeMillis()
44.177 + */
44.178 + public Date(long date) {
44.179 + fastTime = date;
44.180 + }
44.181 +
44.182 + /**
44.183 + * Allocates a <code>Date</code> object and initializes it so that
44.184 + * it represents midnight, local time, at the beginning of the day
44.185 + * specified by the <code>year</code>, <code>month</code>, and
44.186 + * <code>date</code> arguments.
44.187 + *
44.188 + * @param year the year minus 1900.
44.189 + * @param month the month between 0-11.
44.190 + * @param date the day of the month between 1-31.
44.191 + * @see java.util.Calendar
44.192 + * @deprecated As of JDK version 1.1,
44.193 + * replaced by <code>Calendar.set(year + 1900, month, date)</code>
44.194 + * or <code>GregorianCalendar(year + 1900, month, date)</code>.
44.195 + */
44.196 + @Deprecated
44.197 + public Date(int year, int month, int date) {
44.198 + this(year, month, date, 0, 0, 0);
44.199 + }
44.200 +
44.201 + /**
44.202 + * Allocates a <code>Date</code> object and initializes it so that
44.203 + * it represents the instant at the start of the minute specified by
44.204 + * the <code>year</code>, <code>month</code>, <code>date</code>,
44.205 + * <code>hrs</code>, and <code>min</code> arguments, in the local
44.206 + * time zone.
44.207 + *
44.208 + * @param year the year minus 1900.
44.209 + * @param month the month between 0-11.
44.210 + * @param date the day of the month between 1-31.
44.211 + * @param hrs the hours between 0-23.
44.212 + * @param min the minutes between 0-59.
44.213 + * @see java.util.Calendar
44.214 + * @deprecated As of JDK version 1.1,
44.215 + * replaced by <code>Calendar.set(year + 1900, month, date,
44.216 + * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
44.217 + * month, date, hrs, min)</code>.
44.218 + */
44.219 + @Deprecated
44.220 + public Date(int year, int month, int date, int hrs, int min) {
44.221 + this(year, month, date, hrs, min, 0);
44.222 + }
44.223 +
44.224 + /**
44.225 + * Allocates a <code>Date</code> object and initializes it so that
44.226 + * it represents the instant at the start of the second specified
44.227 + * by the <code>year</code>, <code>month</code>, <code>date</code>,
44.228 + * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
44.229 + * in the local time zone.
44.230 + *
44.231 + * @param year the year minus 1900.
44.232 + * @param month the month between 0-11.
44.233 + * @param date the day of the month between 1-31.
44.234 + * @param hrs the hours between 0-23.
44.235 + * @param min the minutes between 0-59.
44.236 + * @param sec the seconds between 0-59.
44.237 + * @see java.util.Calendar
44.238 + * @deprecated As of JDK version 1.1,
44.239 + * replaced by <code>Calendar.set(year + 1900, month, date,
44.240 + * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
44.241 + * month, date, hrs, min, sec)</code>.
44.242 + */
44.243 + @Deprecated
44.244 + public Date(int year, int month, int date, int hrs, int min, int sec) {
44.245 + int y = year + 1900;
44.246 + // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
44.247 + if (month >= 12) {
44.248 + y += month / 12;
44.249 + month %= 12;
44.250 + } else if (month < 0) {
44.251 + y += CalendarUtils.floorDivide(month, 12);
44.252 + month = CalendarUtils.mod(month, 12);
44.253 + }
44.254 + BaseCalendar cal = getCalendarSystem(y);
44.255 + cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
44.256 + cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
44.257 + getTimeImpl();
44.258 + cdate = null;
44.259 + }
44.260 +
44.261 + /**
44.262 + * Allocates a <code>Date</code> object and initializes it so that
44.263 + * it represents the date and time indicated by the string
44.264 + * <code>s</code>, which is interpreted as if by the
44.265 + * {@link Date#parse} method.
44.266 + *
44.267 + * @param s a string representation of the date.
44.268 + * @see java.text.DateFormat
44.269 + * @see java.util.Date#parse(java.lang.String)
44.270 + * @deprecated As of JDK version 1.1,
44.271 + * replaced by <code>DateFormat.parse(String s)</code>.
44.272 + */
44.273 + @Deprecated
44.274 + public Date(String s) {
44.275 + this(parse(s));
44.276 + }
44.277 +
44.278 + /**
44.279 + * Return a copy of this object.
44.280 + */
44.281 + public Object clone() {
44.282 + Date d = null;
44.283 + try {
44.284 + d = (Date)super.clone();
44.285 + if (cdate != null) {
44.286 + d.cdate = (BaseCalendar.Date) cdate.clone();
44.287 + }
44.288 + } catch (CloneNotSupportedException e) {} // Won't happen
44.289 + return d;
44.290 + }
44.291 +
44.292 + /**
44.293 + * Determines the date and time based on the arguments. The
44.294 + * arguments are interpreted as a year, month, day of the month,
44.295 + * hour of the day, minute within the hour, and second within the
44.296 + * minute, exactly as for the <tt>Date</tt> constructor with six
44.297 + * arguments, except that the arguments are interpreted relative
44.298 + * to UTC rather than to the local time zone. The time indicated is
44.299 + * returned represented as the distance, measured in milliseconds,
44.300 + * of that time from the epoch (00:00:00 GMT on January 1, 1970).
44.301 + *
44.302 + * @param year the year minus 1900.
44.303 + * @param month the month between 0-11.
44.304 + * @param date the day of the month between 1-31.
44.305 + * @param hrs the hours between 0-23.
44.306 + * @param min the minutes between 0-59.
44.307 + * @param sec the seconds between 0-59.
44.308 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT for
44.309 + * the date and time specified by the arguments.
44.310 + * @see java.util.Calendar
44.311 + * @deprecated As of JDK version 1.1,
44.312 + * replaced by <code>Calendar.set(year + 1900, month, date,
44.313 + * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
44.314 + * month, date, hrs, min, sec)</code>, using a UTC
44.315 + * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
44.316 + */
44.317 + @Deprecated
44.318 + public static long UTC(int year, int month, int date,
44.319 + int hrs, int min, int sec) {
44.320 + int y = year + 1900;
44.321 + // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
44.322 + if (month >= 12) {
44.323 + y += month / 12;
44.324 + month %= 12;
44.325 + } else if (month < 0) {
44.326 + y += CalendarUtils.floorDivide(month, 12);
44.327 + month = CalendarUtils.mod(month, 12);
44.328 + }
44.329 + int m = month + 1;
44.330 + BaseCalendar cal = getCalendarSystem(y);
44.331 + BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
44.332 + udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
44.333 +
44.334 + // Use a Date instance to perform normalization. Its fastTime
44.335 + // is the UTC value after the normalization.
44.336 + Date d = new Date(0);
44.337 + d.normalize(udate);
44.338 + return d.fastTime;
44.339 + }
44.340 +
44.341 + /**
44.342 + * Attempts to interpret the string <tt>s</tt> as a representation
44.343 + * of a date and time. If the attempt is successful, the time
44.344 + * indicated is returned represented as the distance, measured in
44.345 + * milliseconds, of that time from the epoch (00:00:00 GMT on
44.346 + * January 1, 1970). If the attempt fails, an
44.347 + * <tt>IllegalArgumentException</tt> is thrown.
44.348 + * <p>
44.349 + * It accepts many syntaxes; in particular, it recognizes the IETF
44.350 + * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
44.351 + * understands the continental U.S. time-zone abbreviations, but for
44.352 + * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
44.353 + * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
44.354 + * meridian). If no time zone is specified, the local time zone is
44.355 + * assumed. GMT and UTC are considered equivalent.
44.356 + * <p>
44.357 + * The string <tt>s</tt> is processed from left to right, looking for
44.358 + * data of interest. Any material in <tt>s</tt> that is within the
44.359 + * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
44.360 + * Parentheses may be nested. Otherwise, the only characters permitted
44.361 + * within <tt>s</tt> are these ASCII characters:
44.362 + * <blockquote><pre>
44.363 + * abcdefghijklmnopqrstuvwxyz
44.364 + * ABCDEFGHIJKLMNOPQRSTUVWXYZ
44.365 + * 0123456789,+-:/</pre></blockquote>
44.366 + * and whitespace characters.<p>
44.367 + * A consecutive sequence of decimal digits is treated as a decimal
44.368 + * number:<ul>
44.369 + * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
44.370 + * has already been recognized, then the number is a time-zone
44.371 + * offset. If the number is less than 24, it is an offset measured
44.372 + * in hours. Otherwise, it is regarded as an offset in minutes,
44.373 + * expressed in 24-hour time format without punctuation. A
44.374 + * preceding <tt>-</tt> means a westward offset. Time zone offsets
44.375 + * are always relative to UTC (Greenwich). Thus, for example,
44.376 + * <tt>-5</tt> occurring in the string would mean "five hours west
44.377 + * of Greenwich" and <tt>+0430</tt> would mean "four hours and
44.378 + * thirty minutes east of Greenwich." It is permitted for the
44.379 + * string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
44.380 + * redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
44.381 + * <li>The number is regarded as a year number if one of the
44.382 + * following conditions is true:
44.383 + * <ul>
44.384 + * <li>The number is equal to or greater than 70 and followed by a
44.385 + * space, comma, slash, or end of string
44.386 + * <li>The number is less than 70, and both a month and a day of
44.387 + * the month have already been recognized</li>
44.388 + * </ul>
44.389 + * If the recognized year number is less than 100, it is
44.390 + * interpreted as an abbreviated year relative to a century of
44.391 + * which dates are within 80 years before and 19 years after
44.392 + * the time when the Date class is initialized.
44.393 + * After adjusting the year number, 1900 is subtracted from
44.394 + * it. For example, if the current year is 1999 then years in
44.395 + * the range 19 to 99 are assumed to mean 1919 to 1999, while
44.396 + * years from 0 to 18 are assumed to mean 2000 to 2018. Note
44.397 + * that this is slightly different from the interpretation of
44.398 + * years less than 100 that is used in {@link java.text.SimpleDateFormat}.
44.399 + * <li>If the number is followed by a colon, it is regarded as an hour,
44.400 + * unless an hour has already been recognized, in which case it is
44.401 + * regarded as a minute.
44.402 + * <li>If the number is followed by a slash, it is regarded as a month
44.403 + * (it is decreased by 1 to produce a number in the range <tt>0</tt>
44.404 + * to <tt>11</tt>), unless a month has already been recognized, in
44.405 + * which case it is regarded as a day of the month.
44.406 + * <li>If the number is followed by whitespace, a comma, a hyphen, or
44.407 + * end of string, then if an hour has been recognized but not a
44.408 + * minute, it is regarded as a minute; otherwise, if a minute has
44.409 + * been recognized but not a second, it is regarded as a second;
44.410 + * otherwise, it is regarded as a day of the month. </ul><p>
44.411 + * A consecutive sequence of letters is regarded as a word and treated
44.412 + * as follows:<ul>
44.413 + * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
44.414 + * the parse fails if an hour has not been recognized or is less
44.415 + * than <tt>1</tt> or greater than <tt>12</tt>).
44.416 + * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
44.417 + * to the hour (but the parse fails if an hour has not been
44.418 + * recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
44.419 + * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
44.420 + * WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
44.421 + * case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
44.422 + * <tt>Thurs</tt> are ignored.
44.423 + * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
44.424 + * FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
44.425 + * OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
44.426 + * considering them in the order given here, is recognized as
44.427 + * specifying a month and is converted to a number (<tt>0</tt> to
44.428 + * <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
44.429 + * <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
44.430 + * is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
44.431 + * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
44.432 + * case, is treated as referring to UTC.
44.433 + * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
44.434 + * ignoring case, is recognized as referring to the time zone in
44.435 + * North America that is five, six, seven, or eight hours west of
44.436 + * Greenwich, respectively. Any word that matches <tt>EDT, CDT,
44.437 + * MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
44.438 + * referring to the same time zone, respectively, during daylight
44.439 + * saving time.</ul><p>
44.440 + * Once the entire string s has been scanned, it is converted to a time
44.441 + * result in one of two ways. If a time zone or time-zone offset has been
44.442 + * recognized, then the year, month, day of month, hour, minute, and
44.443 + * second are interpreted in UTC and then the time-zone offset is
44.444 + * applied. Otherwise, the year, month, day of month, hour, minute, and
44.445 + * second are interpreted in the local time zone.
44.446 + *
44.447 + * @param s a string to be parsed as a date.
44.448 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
44.449 + * represented by the string argument.
44.450 + * @see java.text.DateFormat
44.451 + * @deprecated As of JDK version 1.1,
44.452 + * replaced by <code>DateFormat.parse(String s)</code>.
44.453 + */
44.454 + @Deprecated
44.455 + public static long parse(String s) {
44.456 + int year = Integer.MIN_VALUE;
44.457 + int mon = -1;
44.458 + int mday = -1;
44.459 + int hour = -1;
44.460 + int min = -1;
44.461 + int sec = -1;
44.462 + int millis = -1;
44.463 + int c = -1;
44.464 + int i = 0;
44.465 + int n = -1;
44.466 + int wst = -1;
44.467 + int tzoffset = -1;
44.468 + int prevc = 0;
44.469 + syntax:
44.470 + {
44.471 + if (s == null)
44.472 + break syntax;
44.473 + int limit = s.length();
44.474 + while (i < limit) {
44.475 + c = s.charAt(i);
44.476 + i++;
44.477 + if (c <= ' ' || c == ',')
44.478 + continue;
44.479 + if (c == '(') { // skip comments
44.480 + int depth = 1;
44.481 + while (i < limit) {
44.482 + c = s.charAt(i);
44.483 + i++;
44.484 + if (c == '(') depth++;
44.485 + else if (c == ')')
44.486 + if (--depth <= 0)
44.487 + break;
44.488 + }
44.489 + continue;
44.490 + }
44.491 + if ('0' <= c && c <= '9') {
44.492 + n = c - '0';
44.493 + while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
44.494 + n = n * 10 + c - '0';
44.495 + i++;
44.496 + }
44.497 + if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
44.498 + // timezone offset
44.499 + if (n < 24)
44.500 + n = n * 60; // EG. "GMT-3"
44.501 + else
44.502 + n = n % 100 + n / 100 * 60; // eg "GMT-0430"
44.503 + if (prevc == '+') // plus means east of GMT
44.504 + n = -n;
44.505 + if (tzoffset != 0 && tzoffset != -1)
44.506 + break syntax;
44.507 + tzoffset = n;
44.508 + } else if (n >= 70)
44.509 + if (year != Integer.MIN_VALUE)
44.510 + break syntax;
44.511 + else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
44.512 + // year = n < 1900 ? n : n - 1900;
44.513 + year = n;
44.514 + else
44.515 + break syntax;
44.516 + else if (c == ':')
44.517 + if (hour < 0)
44.518 + hour = (byte) n;
44.519 + else if (min < 0)
44.520 + min = (byte) n;
44.521 + else
44.522 + break syntax;
44.523 + else if (c == '/')
44.524 + if (mon < 0)
44.525 + mon = (byte) (n - 1);
44.526 + else if (mday < 0)
44.527 + mday = (byte) n;
44.528 + else
44.529 + break syntax;
44.530 + else if (i < limit && c != ',' && c > ' ' && c != '-')
44.531 + break syntax;
44.532 + else if (hour >= 0 && min < 0)
44.533 + min = (byte) n;
44.534 + else if (min >= 0 && sec < 0)
44.535 + sec = (byte) n;
44.536 + else if (mday < 0)
44.537 + mday = (byte) n;
44.538 + // Handle two-digit years < 70 (70-99 handled above).
44.539 + else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
44.540 + year = n;
44.541 + else
44.542 + break syntax;
44.543 + prevc = 0;
44.544 + } else if (c == '/' || c == ':' || c == '+' || c == '-')
44.545 + prevc = c;
44.546 + else {
44.547 + int st = i - 1;
44.548 + while (i < limit) {
44.549 + c = s.charAt(i);
44.550 + if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
44.551 + break;
44.552 + i++;
44.553 + }
44.554 + if (i <= st + 1)
44.555 + break syntax;
44.556 + int k;
44.557 + for (k = wtb.length; --k >= 0;)
44.558 + if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
44.559 + int action = ttb[k];
44.560 + if (action != 0) {
44.561 + if (action == 1) { // pm
44.562 + if (hour > 12 || hour < 1)
44.563 + break syntax;
44.564 + else if (hour < 12)
44.565 + hour += 12;
44.566 + } else if (action == 14) { // am
44.567 + if (hour > 12 || hour < 1)
44.568 + break syntax;
44.569 + else if (hour == 12)
44.570 + hour = 0;
44.571 + } else if (action <= 13) { // month!
44.572 + if (mon < 0)
44.573 + mon = (byte) (action - 2);
44.574 + else
44.575 + break syntax;
44.576 + } else {
44.577 + tzoffset = action - 10000;
44.578 + }
44.579 + }
44.580 + break;
44.581 + }
44.582 + if (k < 0)
44.583 + break syntax;
44.584 + prevc = 0;
44.585 + }
44.586 + }
44.587 + if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
44.588 + break syntax;
44.589 + // Parse 2-digit years within the correct default century.
44.590 + if (year < 100) {
44.591 + synchronized (Date.class) {
44.592 + if (defaultCenturyStart == 0) {
44.593 + defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
44.594 + }
44.595 + }
44.596 + year += (defaultCenturyStart / 100) * 100;
44.597 + if (year < defaultCenturyStart) year += 100;
44.598 + }
44.599 + if (sec < 0)
44.600 + sec = 0;
44.601 + if (min < 0)
44.602 + min = 0;
44.603 + if (hour < 0)
44.604 + hour = 0;
44.605 + BaseCalendar cal = getCalendarSystem(year);
44.606 + if (tzoffset == -1) { // no time zone specified, have to use local
44.607 + BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
44.608 + ldate.setDate(year, mon + 1, mday);
44.609 + ldate.setTimeOfDay(hour, min, sec, 0);
44.610 + return cal.getTime(ldate);
44.611 + }
44.612 + BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
44.613 + udate.setDate(year, mon + 1, mday);
44.614 + udate.setTimeOfDay(hour, min, sec, 0);
44.615 + return cal.getTime(udate) + tzoffset * (60 * 1000);
44.616 + }
44.617 + // syntax error
44.618 + throw new IllegalArgumentException();
44.619 + }
44.620 + private final static String wtb[] = {
44.621 + "am", "pm",
44.622 + "monday", "tuesday", "wednesday", "thursday", "friday",
44.623 + "saturday", "sunday",
44.624 + "january", "february", "march", "april", "may", "june",
44.625 + "july", "august", "september", "october", "november", "december",
44.626 + "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
44.627 + "mst", "mdt", "pst", "pdt"
44.628 + };
44.629 + private final static int ttb[] = {
44.630 + 14, 1, 0, 0, 0, 0, 0, 0, 0,
44.631 + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
44.632 + 10000 + 0, 10000 + 0, 10000 + 0, // GMT/UT/UTC
44.633 + 10000 + 5 * 60, 10000 + 4 * 60, // EST/EDT
44.634 + 10000 + 6 * 60, 10000 + 5 * 60, // CST/CDT
44.635 + 10000 + 7 * 60, 10000 + 6 * 60, // MST/MDT
44.636 + 10000 + 8 * 60, 10000 + 7 * 60 // PST/PDT
44.637 + };
44.638 +
44.639 + /**
44.640 + * Returns a value that is the result of subtracting 1900 from the
44.641 + * year that contains or begins with the instant in time represented
44.642 + * by this <code>Date</code> object, as interpreted in the local
44.643 + * time zone.
44.644 + *
44.645 + * @return the year represented by this date, minus 1900.
44.646 + * @see java.util.Calendar
44.647 + * @deprecated As of JDK version 1.1,
44.648 + * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
44.649 + */
44.650 + @Deprecated
44.651 + public int getYear() {
44.652 + return normalize().getYear() - 1900;
44.653 + }
44.654 +
44.655 + /**
44.656 + * Sets the year of this <tt>Date</tt> object to be the specified
44.657 + * value plus 1900. This <code>Date</code> object is modified so
44.658 + * that it represents a point in time within the specified year,
44.659 + * with the month, date, hour, minute, and second the same as
44.660 + * before, as interpreted in the local time zone. (Of course, if
44.661 + * the date was February 29, for example, and the year is set to a
44.662 + * non-leap year, then the new date will be treated as if it were
44.663 + * on March 1.)
44.664 + *
44.665 + * @param year the year value.
44.666 + * @see java.util.Calendar
44.667 + * @deprecated As of JDK version 1.1,
44.668 + * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
44.669 + */
44.670 + @Deprecated
44.671 + public void setYear(int year) {
44.672 + getCalendarDate().setNormalizedYear(year + 1900);
44.673 + }
44.674 +
44.675 + /**
44.676 + * Returns a number representing the month that contains or begins
44.677 + * with the instant in time represented by this <tt>Date</tt> object.
44.678 + * The value returned is between <code>0</code> and <code>11</code>,
44.679 + * with the value <code>0</code> representing January.
44.680 + *
44.681 + * @return the month represented by this date.
44.682 + * @see java.util.Calendar
44.683 + * @deprecated As of JDK version 1.1,
44.684 + * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
44.685 + */
44.686 + @Deprecated
44.687 + public int getMonth() {
44.688 + return normalize().getMonth() - 1; // adjust 1-based to 0-based
44.689 + }
44.690 +
44.691 + /**
44.692 + * Sets the month of this date to the specified value. This
44.693 + * <tt>Date</tt> object is modified so that it represents a point
44.694 + * in time within the specified month, with the year, date, hour,
44.695 + * minute, and second the same as before, as interpreted in the
44.696 + * local time zone. If the date was October 31, for example, and
44.697 + * the month is set to June, then the new date will be treated as
44.698 + * if it were on July 1, because June has only 30 days.
44.699 + *
44.700 + * @param month the month value between 0-11.
44.701 + * @see java.util.Calendar
44.702 + * @deprecated As of JDK version 1.1,
44.703 + * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
44.704 + */
44.705 + @Deprecated
44.706 + public void setMonth(int month) {
44.707 + int y = 0;
44.708 + if (month >= 12) {
44.709 + y = month / 12;
44.710 + month %= 12;
44.711 + } else if (month < 0) {
44.712 + y = CalendarUtils.floorDivide(month, 12);
44.713 + month = CalendarUtils.mod(month, 12);
44.714 + }
44.715 + BaseCalendar.Date d = getCalendarDate();
44.716 + if (y != 0) {
44.717 + d.setNormalizedYear(d.getNormalizedYear() + y);
44.718 + }
44.719 + d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
44.720 + }
44.721 +
44.722 + /**
44.723 + * Returns the day of the month represented by this <tt>Date</tt> object.
44.724 + * The value returned is between <code>1</code> and <code>31</code>
44.725 + * representing the day of the month that contains or begins with the
44.726 + * instant in time represented by this <tt>Date</tt> object, as
44.727 + * interpreted in the local time zone.
44.728 + *
44.729 + * @return the day of the month represented by this date.
44.730 + * @see java.util.Calendar
44.731 + * @deprecated As of JDK version 1.1,
44.732 + * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
44.733 + * @deprecated
44.734 + */
44.735 + @Deprecated
44.736 + public int getDate() {
44.737 + return normalize().getDayOfMonth();
44.738 + }
44.739 +
44.740 + /**
44.741 + * Sets the day of the month of this <tt>Date</tt> object to the
44.742 + * specified value. This <tt>Date</tt> object is modified so that
44.743 + * it represents a point in time within the specified day of the
44.744 + * month, with the year, month, hour, minute, and second the same
44.745 + * as before, as interpreted in the local time zone. If the date
44.746 + * was April 30, for example, and the date is set to 31, then it
44.747 + * will be treated as if it were on May 1, because April has only
44.748 + * 30 days.
44.749 + *
44.750 + * @param date the day of the month value between 1-31.
44.751 + * @see java.util.Calendar
44.752 + * @deprecated As of JDK version 1.1,
44.753 + * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
44.754 + */
44.755 + @Deprecated
44.756 + public void setDate(int date) {
44.757 + getCalendarDate().setDayOfMonth(date);
44.758 + }
44.759 +
44.760 + /**
44.761 + * Returns the day of the week represented by this date. The
44.762 + * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
44.763 + * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
44.764 + * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
44.765 + * represents the day of the week that contains or begins with
44.766 + * the instant in time represented by this <tt>Date</tt> object,
44.767 + * as interpreted in the local time zone.
44.768 + *
44.769 + * @return the day of the week represented by this date.
44.770 + * @see java.util.Calendar
44.771 + * @deprecated As of JDK version 1.1,
44.772 + * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
44.773 + */
44.774 + @Deprecated
44.775 + public int getDay() {
44.776 + return normalize().getDayOfWeek() - gcal.SUNDAY;
44.777 + }
44.778 +
44.779 + /**
44.780 + * Returns the hour represented by this <tt>Date</tt> object. The
44.781 + * returned value is a number (<tt>0</tt> through <tt>23</tt>)
44.782 + * representing the hour within the day that contains or begins
44.783 + * with the instant in time represented by this <tt>Date</tt>
44.784 + * object, as interpreted in the local time zone.
44.785 + *
44.786 + * @return the hour represented by this date.
44.787 + * @see java.util.Calendar
44.788 + * @deprecated As of JDK version 1.1,
44.789 + * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
44.790 + */
44.791 + @Deprecated
44.792 + public int getHours() {
44.793 + return normalize().getHours();
44.794 + }
44.795 +
44.796 + /**
44.797 + * Sets the hour of this <tt>Date</tt> object to the specified value.
44.798 + * This <tt>Date</tt> object is modified so that it represents a point
44.799 + * in time within the specified hour of the day, with the year, month,
44.800 + * date, minute, and second the same as before, as interpreted in the
44.801 + * local time zone.
44.802 + *
44.803 + * @param hours the hour value.
44.804 + * @see java.util.Calendar
44.805 + * @deprecated As of JDK version 1.1,
44.806 + * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
44.807 + */
44.808 + @Deprecated
44.809 + public void setHours(int hours) {
44.810 + getCalendarDate().setHours(hours);
44.811 + }
44.812 +
44.813 + /**
44.814 + * Returns the number of minutes past the hour represented by this date,
44.815 + * as interpreted in the local time zone.
44.816 + * The value returned is between <code>0</code> and <code>59</code>.
44.817 + *
44.818 + * @return the number of minutes past the hour represented by this date.
44.819 + * @see java.util.Calendar
44.820 + * @deprecated As of JDK version 1.1,
44.821 + * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
44.822 + */
44.823 + @Deprecated
44.824 + public int getMinutes() {
44.825 + return normalize().getMinutes();
44.826 + }
44.827 +
44.828 + /**
44.829 + * Sets the minutes of this <tt>Date</tt> object to the specified value.
44.830 + * This <tt>Date</tt> object is modified so that it represents a point
44.831 + * in time within the specified minute of the hour, with the year, month,
44.832 + * date, hour, and second the same as before, as interpreted in the
44.833 + * local time zone.
44.834 + *
44.835 + * @param minutes the value of the minutes.
44.836 + * @see java.util.Calendar
44.837 + * @deprecated As of JDK version 1.1,
44.838 + * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
44.839 + */
44.840 + @Deprecated
44.841 + public void setMinutes(int minutes) {
44.842 + getCalendarDate().setMinutes(minutes);
44.843 + }
44.844 +
44.845 + /**
44.846 + * Returns the number of seconds past the minute represented by this date.
44.847 + * The value returned is between <code>0</code> and <code>61</code>. The
44.848 + * values <code>60</code> and <code>61</code> can only occur on those
44.849 + * Java Virtual Machines that take leap seconds into account.
44.850 + *
44.851 + * @return the number of seconds past the minute represented by this date.
44.852 + * @see java.util.Calendar
44.853 + * @deprecated As of JDK version 1.1,
44.854 + * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
44.855 + */
44.856 + @Deprecated
44.857 + public int getSeconds() {
44.858 + return normalize().getSeconds();
44.859 + }
44.860 +
44.861 + /**
44.862 + * Sets the seconds of this <tt>Date</tt> to the specified value.
44.863 + * This <tt>Date</tt> object is modified so that it represents a
44.864 + * point in time within the specified second of the minute, with
44.865 + * the year, month, date, hour, and minute the same as before, as
44.866 + * interpreted in the local time zone.
44.867 + *
44.868 + * @param seconds the seconds value.
44.869 + * @see java.util.Calendar
44.870 + * @deprecated As of JDK version 1.1,
44.871 + * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
44.872 + */
44.873 + @Deprecated
44.874 + public void setSeconds(int seconds) {
44.875 + getCalendarDate().setSeconds(seconds);
44.876 + }
44.877 +
44.878 + /**
44.879 + * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
44.880 + * represented by this <tt>Date</tt> object.
44.881 + *
44.882 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
44.883 + * represented by this date.
44.884 + */
44.885 + public long getTime() {
44.886 + return getTimeImpl();
44.887 + }
44.888 +
44.889 + private final long getTimeImpl() {
44.890 + if (cdate != null && !cdate.isNormalized()) {
44.891 + normalize();
44.892 + }
44.893 + return fastTime;
44.894 + }
44.895 +
44.896 + /**
44.897 + * Sets this <code>Date</code> object to represent a point in time that is
44.898 + * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
44.899 + *
44.900 + * @param time the number of milliseconds.
44.901 + */
44.902 + public void setTime(long time) {
44.903 + fastTime = time;
44.904 + cdate = null;
44.905 + }
44.906 +
44.907 + /**
44.908 + * Tests if this date is before the specified date.
44.909 + *
44.910 + * @param when a date.
44.911 + * @return <code>true</code> if and only if the instant of time
44.912 + * represented by this <tt>Date</tt> object is strictly
44.913 + * earlier than the instant represented by <tt>when</tt>;
44.914 + * <code>false</code> otherwise.
44.915 + * @exception NullPointerException if <code>when</code> is null.
44.916 + */
44.917 + public boolean before(Date when) {
44.918 + return getMillisOf(this) < getMillisOf(when);
44.919 + }
44.920 +
44.921 + /**
44.922 + * Tests if this date is after the specified date.
44.923 + *
44.924 + * @param when a date.
44.925 + * @return <code>true</code> if and only if the instant represented
44.926 + * by this <tt>Date</tt> object is strictly later than the
44.927 + * instant represented by <tt>when</tt>;
44.928 + * <code>false</code> otherwise.
44.929 + * @exception NullPointerException if <code>when</code> is null.
44.930 + */
44.931 + public boolean after(Date when) {
44.932 + return getMillisOf(this) > getMillisOf(when);
44.933 + }
44.934 +
44.935 + /**
44.936 + * Compares two dates for equality.
44.937 + * The result is <code>true</code> if and only if the argument is
44.938 + * not <code>null</code> and is a <code>Date</code> object that
44.939 + * represents the same point in time, to the millisecond, as this object.
44.940 + * <p>
44.941 + * Thus, two <code>Date</code> objects are equal if and only if the
44.942 + * <code>getTime</code> method returns the same <code>long</code>
44.943 + * value for both.
44.944 + *
44.945 + * @param obj the object to compare with.
44.946 + * @return <code>true</code> if the objects are the same;
44.947 + * <code>false</code> otherwise.
44.948 + * @see java.util.Date#getTime()
44.949 + */
44.950 + public boolean equals(Object obj) {
44.951 + return obj instanceof Date && getTime() == ((Date) obj).getTime();
44.952 + }
44.953 +
44.954 + /**
44.955 + * Returns the millisecond value of this <code>Date</code> object
44.956 + * without affecting its internal state.
44.957 + */
44.958 + static final long getMillisOf(Date date) {
44.959 + if (date.cdate == null || date.cdate.isNormalized()) {
44.960 + return date.fastTime;
44.961 + }
44.962 + BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
44.963 + return gcal.getTime(d);
44.964 + }
44.965 +
44.966 + /**
44.967 + * Compares two Dates for ordering.
44.968 + *
44.969 + * @param anotherDate the <code>Date</code> to be compared.
44.970 + * @return the value <code>0</code> if the argument Date is equal to
44.971 + * this Date; a value less than <code>0</code> if this Date
44.972 + * is before the Date argument; and a value greater than
44.973 + * <code>0</code> if this Date is after the Date argument.
44.974 + * @since 1.2
44.975 + * @exception NullPointerException if <code>anotherDate</code> is null.
44.976 + */
44.977 + public int compareTo(Date anotherDate) {
44.978 + long thisTime = getMillisOf(this);
44.979 + long anotherTime = getMillisOf(anotherDate);
44.980 + return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
44.981 + }
44.982 +
44.983 + /**
44.984 + * Returns a hash code value for this object. The result is the
44.985 + * exclusive OR of the two halves of the primitive <tt>long</tt>
44.986 + * value returned by the {@link Date#getTime}
44.987 + * method. That is, the hash code is the value of the expression:
44.988 + * <blockquote><pre>
44.989 + * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
44.990 + *
44.991 + * @return a hash code value for this object.
44.992 + */
44.993 + public int hashCode() {
44.994 + long ht = this.getTime();
44.995 + return (int) ht ^ (int) (ht >> 32);
44.996 + }
44.997 +
44.998 + /**
44.999 + * Converts this <code>Date</code> object to a <code>String</code>
44.1000 + * of the form:
44.1001 + * <blockquote><pre>
44.1002 + * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
44.1003 + * where:<ul>
44.1004 + * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
44.1005 + * Thu, Fri, Sat</tt>).
44.1006 + * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
44.1007 + * Jul, Aug, Sep, Oct, Nov, Dec</tt>).
44.1008 + * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
44.1009 + * <tt>31</tt>), as two decimal digits.
44.1010 + * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
44.1011 + * <tt>23</tt>), as two decimal digits.
44.1012 + * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
44.1013 + * <tt>59</tt>), as two decimal digits.
44.1014 + * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
44.1015 + * <tt>61</tt>, as two decimal digits.
44.1016 + * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
44.1017 + * time). Standard time zone abbreviations include those
44.1018 + * recognized by the method <tt>parse</tt>. If time zone
44.1019 + * information is not available, then <tt>zzz</tt> is empty -
44.1020 + * that is, it consists of no characters at all.
44.1021 + * <li><tt>yyyy</tt> is the year, as four decimal digits.
44.1022 + * </ul>
44.1023 + *
44.1024 + * @return a string representation of this date.
44.1025 + * @see java.util.Date#toLocaleString()
44.1026 + * @see java.util.Date#toGMTString()
44.1027 + */
44.1028 + public String toString() {
44.1029 + // "EEE MMM dd HH:mm:ss zzz yyyy";
44.1030 + BaseCalendar.Date date = normalize();
44.1031 + StringBuilder sb = new StringBuilder(28);
44.1032 + int index = date.getDayOfWeek();
44.1033 + if (index == gcal.SUNDAY) {
44.1034 + index = 8;
44.1035 + }
44.1036 + convertToAbbr(sb, wtb[index]).append(' '); // EEE
44.1037 + convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
44.1038 + CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
44.1039 +
44.1040 + CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
44.1041 + CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
44.1042 + CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
44.1043 + TimeZone zi = date.getZone();
44.1044 + if (zi != null) {
44.1045 + sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
44.1046 + } else {
44.1047 + sb.append("GMT");
44.1048 + }
44.1049 + sb.append(' ').append(date.getYear()); // yyyy
44.1050 + return sb.toString();
44.1051 + }
44.1052 +
44.1053 + /**
44.1054 + * Converts the given name to its 3-letter abbreviation (e.g.,
44.1055 + * "monday" -> "Mon") and stored the abbreviation in the given
44.1056 + * <code>StringBuilder</code>.
44.1057 + */
44.1058 + private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
44.1059 + sb.append(Character.toUpperCase(name.charAt(0)));
44.1060 + sb.append(name.charAt(1)).append(name.charAt(2));
44.1061 + return sb;
44.1062 + }
44.1063 +
44.1064 + /**
44.1065 + * Creates a string representation of this <tt>Date</tt> object in an
44.1066 + * implementation-dependent form. The intent is that the form should
44.1067 + * be familiar to the user of the Java application, wherever it may
44.1068 + * happen to be running. The intent is comparable to that of the
44.1069 + * "<code>%c</code>" format supported by the <code>strftime()</code>
44.1070 + * function of ISO C.
44.1071 + *
44.1072 + * @return a string representation of this date, using the locale
44.1073 + * conventions.
44.1074 + * @see java.text.DateFormat
44.1075 + * @see java.util.Date#toString()
44.1076 + * @see java.util.Date#toGMTString()
44.1077 + * @deprecated As of JDK version 1.1,
44.1078 + * replaced by <code>DateFormat.format(Date date)</code>.
44.1079 + */
44.1080 + @Deprecated
44.1081 + public String toLocaleString() {
44.1082 + DateFormat formatter = DateFormat.getDateTimeInstance();
44.1083 + return formatter.format(this);
44.1084 + }
44.1085 +
44.1086 + /**
44.1087 + * Creates a string representation of this <tt>Date</tt> object of
44.1088 + * the form:
44.1089 + * <blockquote<pre>
44.1090 + * d mon yyyy hh:mm:ss GMT</pre></blockquote>
44.1091 + * where:<ul>
44.1092 + * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
44.1093 + * as one or two decimal digits.
44.1094 + * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
44.1095 + * Aug, Sep, Oct, Nov, Dec</tt>).
44.1096 + * <li><i>yyyy</i> is the year, as four decimal digits.
44.1097 + * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
44.1098 + * as two decimal digits.
44.1099 + * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
44.1100 + * <tt>59</tt>), as two decimal digits.
44.1101 + * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
44.1102 + * <tt>61</tt>), as two decimal digits.
44.1103 + * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
44.1104 + * Greenwich Mean Time.
44.1105 + * </ul><p>
44.1106 + * The result does not depend on the local time zone.
44.1107 + *
44.1108 + * @return a string representation of this date, using the Internet GMT
44.1109 + * conventions.
44.1110 + * @see java.text.DateFormat
44.1111 + * @see java.util.Date#toString()
44.1112 + * @see java.util.Date#toLocaleString()
44.1113 + * @deprecated As of JDK version 1.1,
44.1114 + * replaced by <code>DateFormat.format(Date date)</code>, using a
44.1115 + * GMT <code>TimeZone</code>.
44.1116 + */
44.1117 + @Deprecated
44.1118 + public String toGMTString() {
44.1119 + // d MMM yyyy HH:mm:ss 'GMT'
44.1120 + long t = getTime();
44.1121 + BaseCalendar cal = getCalendarSystem(t);
44.1122 + BaseCalendar.Date date =
44.1123 + (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
44.1124 + StringBuilder sb = new StringBuilder(32);
44.1125 + CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
44.1126 + convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
44.1127 + sb.append(date.getYear()).append(' '); // yyyy
44.1128 + CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
44.1129 + CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
44.1130 + CalendarUtils.sprintf0d(sb, date.getSeconds(), 2); // ss
44.1131 + sb.append(" GMT"); // ' GMT'
44.1132 + return sb.toString();
44.1133 + }
44.1134 +
44.1135 + /**
44.1136 + * Returns the offset, measured in minutes, for the local time zone
44.1137 + * relative to UTC that is appropriate for the time represented by
44.1138 + * this <code>Date</code> object.
44.1139 + * <p>
44.1140 + * For example, in Massachusetts, five time zones west of Greenwich:
44.1141 + * <blockquote><pre>
44.1142 + * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
44.1143 + * because on February 14, 1996, standard time (Eastern Standard Time)
44.1144 + * is in use, which is offset five hours from UTC; but:
44.1145 + * <blockquote><pre>
44.1146 + * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
44.1147 + * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
44.1148 + * is in use, which is offset only four hours from UTC.<p>
44.1149 + * This method produces the same result as if it computed:
44.1150 + * <blockquote><pre>
44.1151 + * (this.getTime() - UTC(this.getYear(),
44.1152 + * this.getMonth(),
44.1153 + * this.getDate(),
44.1154 + * this.getHours(),
44.1155 + * this.getMinutes(),
44.1156 + * this.getSeconds())) / (60 * 1000)
44.1157 + * </pre></blockquote>
44.1158 + *
44.1159 + * @return the time-zone offset, in minutes, for the current time zone.
44.1160 + * @see java.util.Calendar#ZONE_OFFSET
44.1161 + * @see java.util.Calendar#DST_OFFSET
44.1162 + * @see java.util.TimeZone#getDefault
44.1163 + * @deprecated As of JDK version 1.1,
44.1164 + * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
44.1165 + * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
44.1166 + */
44.1167 + @Deprecated
44.1168 + public int getTimezoneOffset() {
44.1169 + int zoneOffset;
44.1170 + if (cdate == null) {
44.1171 + TimeZone tz = TimeZone.getDefaultRef();
44.1172 + if (tz instanceof ZoneInfo) {
44.1173 + zoneOffset = ((ZoneInfo)tz).getOffsets(fastTime, null);
44.1174 + } else {
44.1175 + zoneOffset = tz.getOffset(fastTime);
44.1176 + }
44.1177 + } else {
44.1178 + normalize();
44.1179 + zoneOffset = cdate.getZoneOffset();
44.1180 + }
44.1181 + return -zoneOffset/60000; // convert to minutes
44.1182 + }
44.1183 +
44.1184 + private final BaseCalendar.Date getCalendarDate() {
44.1185 + if (cdate == null) {
44.1186 + BaseCalendar cal = getCalendarSystem(fastTime);
44.1187 + cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
44.1188 + TimeZone.getDefaultRef());
44.1189 + }
44.1190 + return cdate;
44.1191 + }
44.1192 +
44.1193 + private final BaseCalendar.Date normalize() {
44.1194 + if (cdate == null) {
44.1195 + BaseCalendar cal = getCalendarSystem(fastTime);
44.1196 + cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
44.1197 + TimeZone.getDefaultRef());
44.1198 + return cdate;
44.1199 + }
44.1200 +
44.1201 + // Normalize cdate with the TimeZone in cdate first. This is
44.1202 + // required for the compatible behavior.
44.1203 + if (!cdate.isNormalized()) {
44.1204 + cdate = normalize(cdate);
44.1205 + }
44.1206 +
44.1207 + // If the default TimeZone has changed, then recalculate the
44.1208 + // fields with the new TimeZone.
44.1209 + TimeZone tz = TimeZone.getDefaultRef();
44.1210 + if (tz != cdate.getZone()) {
44.1211 + cdate.setZone(tz);
44.1212 + CalendarSystem cal = getCalendarSystem(cdate);
44.1213 + cal.getCalendarDate(fastTime, cdate);
44.1214 + }
44.1215 + return cdate;
44.1216 + }
44.1217 +
44.1218 + // fastTime and the returned data are in sync upon return.
44.1219 + private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
44.1220 + int y = date.getNormalizedYear();
44.1221 + int m = date.getMonth();
44.1222 + int d = date.getDayOfMonth();
44.1223 + int hh = date.getHours();
44.1224 + int mm = date.getMinutes();
44.1225 + int ss = date.getSeconds();
44.1226 + int ms = date.getMillis();
44.1227 + TimeZone tz = date.getZone();
44.1228 +
44.1229 + // If the specified year can't be handled using a long value
44.1230 + // in milliseconds, GregorianCalendar is used for full
44.1231 + // compatibility with underflow and overflow. This is required
44.1232 + // by some JCK tests. The limits are based max year values -
44.1233 + // years that can be represented by max values of d, hh, mm,
44.1234 + // ss and ms. Also, let GregorianCalendar handle the default
44.1235 + // cutover year so that we don't need to worry about the
44.1236 + // transition here.
44.1237 + if (y == 1582 || y > 280000000 || y < -280000000) {
44.1238 + if (tz == null) {
44.1239 + tz = TimeZone.getTimeZone("GMT");
44.1240 + }
44.1241 + GregorianCalendar gc = new GregorianCalendar(tz);
44.1242 + gc.clear();
44.1243 + gc.set(gc.MILLISECOND, ms);
44.1244 + gc.set(y, m-1, d, hh, mm, ss);
44.1245 + fastTime = gc.getTimeInMillis();
44.1246 + BaseCalendar cal = getCalendarSystem(fastTime);
44.1247 + date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
44.1248 + return date;
44.1249 + }
44.1250 +
44.1251 + BaseCalendar cal = getCalendarSystem(y);
44.1252 + if (cal != getCalendarSystem(date)) {
44.1253 + date = (BaseCalendar.Date) cal.newCalendarDate(tz);
44.1254 + date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
44.1255 + }
44.1256 + // Perform the GregorianCalendar-style normalization.
44.1257 + fastTime = cal.getTime(date);
44.1258 +
44.1259 + // In case the normalized date requires the other calendar
44.1260 + // system, we need to recalculate it using the other one.
44.1261 + BaseCalendar ncal = getCalendarSystem(fastTime);
44.1262 + if (ncal != cal) {
44.1263 + date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
44.1264 + date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
44.1265 + fastTime = ncal.getTime(date);
44.1266 + }
44.1267 + return date;
44.1268 + }
44.1269 +
44.1270 + /**
44.1271 + * Returns the Gregorian or Julian calendar system to use with the
44.1272 + * given date. Use Gregorian from October 15, 1582.
44.1273 + *
44.1274 + * @param year normalized calendar year (not -1900)
44.1275 + * @return the CalendarSystem to use for the specified date
44.1276 + */
44.1277 + private static final BaseCalendar getCalendarSystem(int year) {
44.1278 + if (year >= 1582) {
44.1279 + return gcal;
44.1280 + }
44.1281 + return getJulianCalendar();
44.1282 + }
44.1283 +
44.1284 + private static final BaseCalendar getCalendarSystem(long utc) {
44.1285 + // Quickly check if the time stamp given by `utc' is the Epoch
44.1286 + // or later. If it's before 1970, we convert the cutover to
44.1287 + // local time to compare.
44.1288 + if (utc >= 0
44.1289 + || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
44.1290 + - TimeZone.getDefaultRef().getOffset(utc)) {
44.1291 + return gcal;
44.1292 + }
44.1293 + return getJulianCalendar();
44.1294 + }
44.1295 +
44.1296 + private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
44.1297 + if (jcal == null) {
44.1298 + return gcal;
44.1299 + }
44.1300 + if (cdate.getEra() != null) {
44.1301 + return jcal;
44.1302 + }
44.1303 + return gcal;
44.1304 + }
44.1305 +
44.1306 + synchronized private static final BaseCalendar getJulianCalendar() {
44.1307 + if (jcal == null) {
44.1308 + jcal = (BaseCalendar) CalendarSystem.forName("julian");
44.1309 + }
44.1310 + return jcal;
44.1311 + }
44.1312 +
44.1313 + /**
44.1314 + * Save the state of this object to a stream (i.e., serialize it).
44.1315 + *
44.1316 + * @serialData The value returned by <code>getTime()</code>
44.1317 + * is emitted (long). This represents the offset from
44.1318 + * January 1, 1970, 00:00:00 GMT in milliseconds.
44.1319 + */
44.1320 + private void writeObject(ObjectOutputStream s)
44.1321 + throws IOException
44.1322 + {
44.1323 + s.writeLong(getTimeImpl());
44.1324 + }
44.1325 +
44.1326 + /**
44.1327 + * Reconstitute this object from a stream (i.e., deserialize it).
44.1328 + */
44.1329 + private void readObject(ObjectInputStream s)
44.1330 + throws IOException, ClassNotFoundException
44.1331 + {
44.1332 + fastTime = s.readLong();
44.1333 + }
44.1334 +}
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/rt/emul/compact/src/main/java/java/util/Locale.java Thu Oct 03 15:43:10 2013 +0200
45.3 @@ -0,0 +1,2560 @@
45.4 +/*
45.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
45.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
45.7 + *
45.8 + * This code is free software; you can redistribute it and/or modify it
45.9 + * under the terms of the GNU General Public License version 2 only, as
45.10 + * published by the Free Software Foundation. Oracle designates this
45.11 + * particular file as subject to the "Classpath" exception as provided
45.12 + * by Oracle in the LICENSE file that accompanied this code.
45.13 + *
45.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
45.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
45.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
45.17 + * version 2 for more details (a copy is included in the LICENSE file that
45.18 + * accompanied this code).
45.19 + *
45.20 + * You should have received a copy of the GNU General Public License version
45.21 + * 2 along with this work; if not, write to the Free Software Foundation,
45.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
45.23 + *
45.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
45.25 + * or visit www.oracle.com if you need additional information or have any
45.26 + * questions.
45.27 + */
45.28 +
45.29 +/*
45.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
45.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
45.32 + *
45.33 + * The original version of this source code and documentation
45.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
45.35 + * subsidiary of IBM. These materials are provided under terms
45.36 + * of a License Agreement between Taligent and Sun. This technology
45.37 + * is protected by multiple US and International patents.
45.38 + *
45.39 + * This notice and attribution to Taligent may not be removed.
45.40 + * Taligent is a registered trademark of Taligent, Inc.
45.41 + *
45.42 + */
45.43 +
45.44 +package java.util;
45.45 +
45.46 +import java.io.IOException;
45.47 +import java.io.ObjectInputStream;
45.48 +import java.io.ObjectOutputStream;
45.49 +import java.io.ObjectStreamField;
45.50 +import java.io.Serializable;
45.51 +import java.security.AccessController;
45.52 +import java.text.MessageFormat;
45.53 +import java.util.spi.LocaleNameProvider;
45.54 +
45.55 +import sun.security.action.GetPropertyAction;
45.56 +import sun.util.LocaleServiceProviderPool;
45.57 +import sun.util.locale.BaseLocale;
45.58 +import sun.util.locale.InternalLocaleBuilder;
45.59 +import sun.util.locale.LanguageTag;
45.60 +import sun.util.locale.LocaleExtensions;
45.61 +import sun.util.locale.LocaleObjectCache;
45.62 +import sun.util.locale.LocaleSyntaxException;
45.63 +import sun.util.locale.LocaleUtils;
45.64 +import sun.util.locale.ParseStatus;
45.65 +import sun.util.locale.UnicodeLocaleExtension;
45.66 +import sun.util.resources.LocaleData;
45.67 +import sun.util.resources.OpenListResourceBundle;
45.68 +
45.69 +/**
45.70 + * A <code>Locale</code> object represents a specific geographical, political,
45.71 + * or cultural region. An operation that requires a <code>Locale</code> to perform
45.72 + * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
45.73 + * to tailor information for the user. For example, displaying a number
45.74 + * is a locale-sensitive operation— the number should be formatted
45.75 + * according to the customs and conventions of the user's native country,
45.76 + * region, or culture.
45.77 + *
45.78 + * <p> The <code>Locale</code> class implements identifiers
45.79 + * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying
45.80 + * Languages"), with support for the LDML (UTS#35, "Unicode Locale
45.81 + * Data Markup Language") BCP 47-compatible extensions for locale data
45.82 + * exchange.
45.83 + *
45.84 + * <p> A <code>Locale</code> object logically consists of the fields
45.85 + * described below.
45.86 + *
45.87 + * <dl>
45.88 + * <dt><a name="def_language"/><b>language</b></dt>
45.89 + *
45.90 + * <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
45.91 + * language subtags up to 8 alpha letters (for future enhancements).
45.92 + * When a language has both an alpha-2 code and an alpha-3 code, the
45.93 + * alpha-2 code must be used. You can find a full list of valid
45.94 + * language codes in the IANA Language Subtag Registry (search for
45.95 + * "Type: language"). The language field is case insensitive, but
45.96 + * <code>Locale</code> always canonicalizes to lower case.</dd><br>
45.97 + *
45.98 + * <dd>Well-formed language values have the form
45.99 + * <code>[a-zA-Z]{2,8}</code>. Note that this is not the the full
45.100 + * BCP47 language production, since it excludes extlang. They are
45.101 + * not needed since modern three-letter language codes replace
45.102 + * them.</dd><br>
45.103 + *
45.104 + * <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd><br>
45.105 + *
45.106 + * <dt><a name="def_script"/><b>script</b></dt>
45.107 + *
45.108 + * <dd>ISO 15924 alpha-4 script code. You can find a full list of
45.109 + * valid script codes in the IANA Language Subtag Registry (search
45.110 + * for "Type: script"). The script field is case insensitive, but
45.111 + * <code>Locale</code> always canonicalizes to title case (the first
45.112 + * letter is upper case and the rest of the letters are lower
45.113 + * case).</dd><br>
45.114 + *
45.115 + * <dd>Well-formed script values have the form
45.116 + * <code>[a-zA-Z]{4}</code></dd><br>
45.117 + *
45.118 + * <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd><br>
45.119 + *
45.120 + * <dt><a name="def_region"/><b>country (region)</b></dt>
45.121 + *
45.122 + * <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
45.123 + * You can find a full list of valid country and region codes in the
45.124 + * IANA Language Subtag Registry (search for "Type: region"). The
45.125 + * country (region) field is case insensitive, but
45.126 + * <code>Locale</code> always canonicalizes to upper case.</dd><br>
45.127 + *
45.128 + * <dd>Well-formed country/region values have
45.129 + * the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd><br>
45.130 + *
45.131 + * <dd>Example: "US" (United States), "FR" (France), "029"
45.132 + * (Caribbean)</dd><br>
45.133 + *
45.134 + * <dt><a name="def_variant"/><b>variant</b></dt>
45.135 + *
45.136 + * <dd>Any arbitrary value used to indicate a variation of a
45.137 + * <code>Locale</code>. Where there are two or more variant values
45.138 + * each indicating its own semantics, these values should be ordered
45.139 + * by importance, with most important first, separated by
45.140 + * underscore('_'). The variant field is case sensitive.</dd><br>
45.141 + *
45.142 + * <dd>Note: IETF BCP 47 places syntactic restrictions on variant
45.143 + * subtags. Also BCP 47 subtags are strictly used to indicate
45.144 + * additional variations that define a language or its dialects that
45.145 + * are not covered by any combinations of language, script and
45.146 + * region subtags. You can find a full list of valid variant codes
45.147 + * in the IANA Language Subtag Registry (search for "Type: variant").
45.148 + *
45.149 + * <p>However, the variant field in <code>Locale</code> has
45.150 + * historically been used for any kind of variation, not just
45.151 + * language variations. For example, some supported variants
45.152 + * available in Java SE Runtime Environments indicate alternative
45.153 + * cultural behaviors such as calendar type or number script. In
45.154 + * BCP 47 this kind of information, which does not identify the
45.155 + * language, is supported by extension subtags or private use
45.156 + * subtags.</dd><br>
45.157 + *
45.158 + * <dd>Well-formed variant values have the form <code>SUBTAG
45.159 + * (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
45.160 + * [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
45.161 + * uses hyphen ('-') as a delimiter, this is more lenient).</dd><br>
45.162 + *
45.163 + * <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd><br>
45.164 + *
45.165 + * <dt><a name="def_extensions"/><b>extensions</b></dt>
45.166 + *
45.167 + * <dd>A map from single character keys to string values, indicating
45.168 + * extensions apart from language identification. The extensions in
45.169 + * <code>Locale</code> implement the semantics and syntax of BCP 47
45.170 + * extension subtags and private use subtags. The extensions are
45.171 + * case insensitive, but <code>Locale</code> canonicalizes all
45.172 + * extension keys and values to lower case. Note that extensions
45.173 + * cannot have empty values.</dd><br>
45.174 + *
45.175 + * <dd>Well-formed keys are single characters from the set
45.176 + * <code>[0-9a-zA-Z]</code>. Well-formed values have the form
45.177 + * <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
45.178 + * <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
45.179 + * <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
45.180 + * single-character subtags).</dd><br>
45.181 + *
45.182 + * <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
45.183 + * key="x"/value="java-1-7"</dd>
45.184 + * </dl>
45.185 + *
45.186 + * <b>Note:</b> Although BCP 47 requires field values to be registered
45.187 + * in the IANA Language Subtag Registry, the <code>Locale</code> class
45.188 + * does not provide any validation features. The <code>Builder</code>
45.189 + * only checks if an individual field satisfies the syntactic
45.190 + * requirement (is well-formed), but does not validate the value
45.191 + * itself. See {@link Builder} for details.
45.192 + *
45.193 + * <h4><a name="def_locale_extension">Unicode locale/language extension</h4>
45.194 + *
45.195 + * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
45.196 + * attributes and keywords to override or refine the default behavior
45.197 + * associated with a locale. A keyword is represented by a pair of
45.198 + * key and type. For example, "nu-thai" indicates that Thai local
45.199 + * digits (value:"thai") should be used for formatting numbers
45.200 + * (key:"nu").
45.201 + *
45.202 + * <p>The keywords are mapped to a BCP 47 extension value using the
45.203 + * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}). The above
45.204 + * example, "nu-thai", becomes the extension "u-nu-thai".code
45.205 + *
45.206 + * <p>Thus, when a <code>Locale</code> object contains Unicode locale
45.207 + * attributes and keywords,
45.208 + * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
45.209 + * String representing this information, for example, "nu-thai". The
45.210 + * <code>Locale</code> class also provides {@link
45.211 + * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
45.212 + * {@link #getUnicodeLocaleType} which allow you to access Unicode
45.213 + * locale attributes and key/type pairs directly. When represented as
45.214 + * a string, the Unicode Locale Extension lists attributes
45.215 + * alphabetically, followed by key/type sequences with keys listed
45.216 + * alphabetically (the order of subtags comprising a key's type is
45.217 + * fixed when the type is defined)
45.218 + *
45.219 + * <p>A well-formed locale key has the form
45.220 + * <code>[0-9a-zA-Z]{2}</code>. A well-formed locale type has the
45.221 + * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
45.222 + * can be empty, or a series of subtags 3-8 alphanums in length). A
45.223 + * well-formed locale attribute has the form
45.224 + * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
45.225 + * form as a locale type subtag).
45.226 + *
45.227 + * <p>The Unicode locale extension specifies optional behavior in
45.228 + * locale-sensitive services. Although the LDML specification defines
45.229 + * various keys and values, actual locale-sensitive service
45.230 + * implementations in a Java Runtime Environment might not support any
45.231 + * particular Unicode locale attributes or key/type pairs.
45.232 + *
45.233 + * <h4>Creating a Locale</h4>
45.234 + *
45.235 + * <p>There are several different ways to create a <code>Locale</code>
45.236 + * object.
45.237 + *
45.238 + * <h5>Builder</h5>
45.239 + *
45.240 + * <p>Using {@link Builder} you can construct a <code>Locale</code> object
45.241 + * that conforms to BCP 47 syntax.
45.242 + *
45.243 + * <h5>Constructors</h5>
45.244 + *
45.245 + * <p>The <code>Locale</code> class provides three constructors:
45.246 + * <blockquote>
45.247 + * <pre>
45.248 + * {@link #Locale(String language)}
45.249 + * {@link #Locale(String language, String country)}
45.250 + * {@link #Locale(String language, String country, String variant)}
45.251 + * </pre>
45.252 + * </blockquote>
45.253 + * These constructors allow you to create a <code>Locale</code> object
45.254 + * with language, country and variant, but you cannot specify
45.255 + * script or extensions.
45.256 + *
45.257 + * <h5>Factory Methods</h5>
45.258 + *
45.259 + * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
45.260 + * object for a well-formed BCP 47 language tag.
45.261 + *
45.262 + * <h5>Locale Constants</h5>
45.263 + *
45.264 + * <p>The <code>Locale</code> class provides a number of convenient constants
45.265 + * that you can use to create <code>Locale</code> objects for commonly used
45.266 + * locales. For example, the following creates a <code>Locale</code> object
45.267 + * for the United States:
45.268 + * <blockquote>
45.269 + * <pre>
45.270 + * Locale.US
45.271 + * </pre>
45.272 + * </blockquote>
45.273 + *
45.274 + * <h4>Use of Locale</h4>
45.275 + *
45.276 + * <p>Once you've created a <code>Locale</code> you can query it for information
45.277 + * about itself. Use <code>getCountry</code> to get the country (or region)
45.278 + * code and <code>getLanguage</code> to get the language code.
45.279 + * You can use <code>getDisplayCountry</code> to get the
45.280 + * name of the country suitable for displaying to the user. Similarly,
45.281 + * you can use <code>getDisplayLanguage</code> to get the name of
45.282 + * the language suitable for displaying to the user. Interestingly,
45.283 + * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
45.284 + * and have two versions: one that uses the default locale and one
45.285 + * that uses the locale specified as an argument.
45.286 + *
45.287 + * <p>The Java Platform provides a number of classes that perform locale-sensitive
45.288 + * operations. For example, the <code>NumberFormat</code> class formats
45.289 + * numbers, currency, and percentages in a locale-sensitive manner. Classes
45.290 + * such as <code>NumberFormat</code> have several convenience methods
45.291 + * for creating a default object of that type. For example, the
45.292 + * <code>NumberFormat</code> class provides these three convenience methods
45.293 + * for creating a default <code>NumberFormat</code> object:
45.294 + * <blockquote>
45.295 + * <pre>
45.296 + * NumberFormat.getInstance()
45.297 + * NumberFormat.getCurrencyInstance()
45.298 + * NumberFormat.getPercentInstance()
45.299 + * </pre>
45.300 + * </blockquote>
45.301 + * Each of these methods has two variants; one with an explicit locale
45.302 + * and one without; the latter uses the default locale:
45.303 + * <blockquote>
45.304 + * <pre>
45.305 + * NumberFormat.getInstance(myLocale)
45.306 + * NumberFormat.getCurrencyInstance(myLocale)
45.307 + * NumberFormat.getPercentInstance(myLocale)
45.308 + * </pre>
45.309 + * </blockquote>
45.310 + * A <code>Locale</code> is the mechanism for identifying the kind of object
45.311 + * (<code>NumberFormat</code>) that you would like to get. The locale is
45.312 + * <STRONG>just</STRONG> a mechanism for identifying objects,
45.313 + * <STRONG>not</STRONG> a container for the objects themselves.
45.314 + *
45.315 + * <h4>Compatibility</h4>
45.316 + *
45.317 + * <p>In order to maintain compatibility with existing usage, Locale's
45.318 + * constructors retain their behavior prior to the Java Runtime
45.319 + * Environment version 1.7. The same is largely true for the
45.320 + * <code>toString</code> method. Thus Locale objects can continue to
45.321 + * be used as they were. In particular, clients who parse the output
45.322 + * of toString into language, country, and variant fields can continue
45.323 + * to do so (although this is strongly discouraged), although the
45.324 + * variant field will have additional information in it if script or
45.325 + * extensions are present.
45.326 + *
45.327 + * <p>In addition, BCP 47 imposes syntax restrictions that are not
45.328 + * imposed by Locale's constructors. This means that conversions
45.329 + * between some Locales and BCP 47 language tags cannot be made without
45.330 + * losing information. Thus <code>toLanguageTag</code> cannot
45.331 + * represent the state of locales whose language, country, or variant
45.332 + * do not conform to BCP 47.
45.333 + *
45.334 + * <p>Because of these issues, it is recommended that clients migrate
45.335 + * away from constructing non-conforming locales and use the
45.336 + * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
45.337 + * Clients desiring a string representation of the complete locale can
45.338 + * then always rely on <code>toLanguageTag</code> for this purpose.
45.339 + *
45.340 + * <h5><a name="special_cases_constructor"/>Special cases</h5>
45.341 + *
45.342 + * <p>For compatibility reasons, two
45.343 + * non-conforming locales are treated as special cases. These are
45.344 + * <b><tt>ja_JP_JP</tt></b> and <b><tt>th_TH_TH</tt></b>. These are ill-formed
45.345 + * in BCP 47 since the variants are too short. To ease migration to BCP 47,
45.346 + * these are treated specially during construction. These two cases (and only
45.347 + * these) cause a constructor to generate an extension, all other values behave
45.348 + * exactly as they did prior to Java 7.
45.349 + *
45.350 + * <p>Java has used <tt>ja_JP_JP</tt> to represent Japanese as used in
45.351 + * Japan together with the Japanese Imperial calendar. This is now
45.352 + * representable using a Unicode locale extension, by specifying the
45.353 + * Unicode locale key <tt>ca</tt> (for "calendar") and type
45.354 + * <tt>japanese</tt>. When the Locale constructor is called with the
45.355 + * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
45.356 + * automatically added.
45.357 + *
45.358 + * <p>Java has used <tt>th_TH_TH</tt> to represent Thai as used in
45.359 + * Thailand together with Thai digits. This is also now representable using
45.360 + * a Unicode locale extension, by specifying the Unicode locale key
45.361 + * <tt>nu</tt> (for "number") and value <tt>thai</tt>. When the Locale
45.362 + * constructor is called with the arguments "th", "TH", "TH", the
45.363 + * extension "u-nu-thai" is automatically added.
45.364 + *
45.365 + * <h5>Serialization</h5>
45.366 + *
45.367 + * <p>During serialization, writeObject writes all fields to the output
45.368 + * stream, including extensions.
45.369 + *
45.370 + * <p>During deserialization, readResolve adds extensions as described
45.371 + * in <a href="#special_cases_constructor">Special Cases</a>, only
45.372 + * for the two cases th_TH_TH and ja_JP_JP.
45.373 + *
45.374 + * <h5>Legacy language codes</h5>
45.375 + *
45.376 + * <p>Locale's constructor has always converted three language codes to
45.377 + * their earlier, obsoleted forms: <tt>he</tt> maps to <tt>iw</tt>,
45.378 + * <tt>yi</tt> maps to <tt>ji</tt>, and <tt>id</tt> maps to
45.379 + * <tt>in</tt>. This continues to be the case, in order to not break
45.380 + * backwards compatibility.
45.381 + *
45.382 + * <p>The APIs added in 1.7 map between the old and new language codes,
45.383 + * maintaining the old codes internal to Locale (so that
45.384 + * <code>getLanguage</code> and <code>toString</code> reflect the old
45.385 + * code), but using the new codes in the BCP 47 language tag APIs (so
45.386 + * that <code>toLanguageTag</code> reflects the new one). This
45.387 + * preserves the equivalence between Locales no matter which code or
45.388 + * API is used to construct them. Java's default resource bundle
45.389 + * lookup mechanism also implements this mapping, so that resources
45.390 + * can be named using either convention, see {@link ResourceBundle.Control}.
45.391 + *
45.392 + * <h5>Three-letter language/country(region) codes</h5>
45.393 + *
45.394 + * <p>The Locale constructors have always specified that the language
45.395 + * and the country param be two characters in length, although in
45.396 + * practice they have accepted any length. The specification has now
45.397 + * been relaxed to allow language codes of two to eight characters and
45.398 + * country (region) codes of two to three characters, and in
45.399 + * particular, three-letter language codes and three-digit region
45.400 + * codes as specified in the IANA Language Subtag Registry. For
45.401 + * compatibility, the implementation still does not impose a length
45.402 + * constraint.
45.403 + *
45.404 + * @see Builder
45.405 + * @see ResourceBundle
45.406 + * @see java.text.Format
45.407 + * @see java.text.NumberFormat
45.408 + * @see java.text.Collator
45.409 + * @author Mark Davis
45.410 + * @since 1.1
45.411 + */
45.412 +public final class Locale implements Cloneable, Serializable {
45.413 +
45.414 + static private final Cache LOCALECACHE = new Cache();
45.415 +
45.416 + /** Useful constant for language.
45.417 + */
45.418 + static public final Locale ENGLISH = createConstant("en", "");
45.419 +
45.420 + /** Useful constant for language.
45.421 + */
45.422 + static public final Locale FRENCH = createConstant("fr", "");
45.423 +
45.424 + /** Useful constant for language.
45.425 + */
45.426 + static public final Locale GERMAN = createConstant("de", "");
45.427 +
45.428 + /** Useful constant for language.
45.429 + */
45.430 + static public final Locale ITALIAN = createConstant("it", "");
45.431 +
45.432 + /** Useful constant for language.
45.433 + */
45.434 + static public final Locale JAPANESE = createConstant("ja", "");
45.435 +
45.436 + /** Useful constant for language.
45.437 + */
45.438 + static public final Locale KOREAN = createConstant("ko", "");
45.439 +
45.440 + /** Useful constant for language.
45.441 + */
45.442 + static public final Locale CHINESE = createConstant("zh", "");
45.443 +
45.444 + /** Useful constant for language.
45.445 + */
45.446 + static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
45.447 +
45.448 + /** Useful constant for language.
45.449 + */
45.450 + static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
45.451 +
45.452 + /** Useful constant for country.
45.453 + */
45.454 + static public final Locale FRANCE = createConstant("fr", "FR");
45.455 +
45.456 + /** Useful constant for country.
45.457 + */
45.458 + static public final Locale GERMANY = createConstant("de", "DE");
45.459 +
45.460 + /** Useful constant for country.
45.461 + */
45.462 + static public final Locale ITALY = createConstant("it", "IT");
45.463 +
45.464 + /** Useful constant for country.
45.465 + */
45.466 + static public final Locale JAPAN = createConstant("ja", "JP");
45.467 +
45.468 + /** Useful constant for country.
45.469 + */
45.470 + static public final Locale KOREA = createConstant("ko", "KR");
45.471 +
45.472 + /** Useful constant for country.
45.473 + */
45.474 + static public final Locale CHINA = SIMPLIFIED_CHINESE;
45.475 +
45.476 + /** Useful constant for country.
45.477 + */
45.478 + static public final Locale PRC = SIMPLIFIED_CHINESE;
45.479 +
45.480 + /** Useful constant for country.
45.481 + */
45.482 + static public final Locale TAIWAN = TRADITIONAL_CHINESE;
45.483 +
45.484 + /** Useful constant for country.
45.485 + */
45.486 + static public final Locale UK = createConstant("en", "GB");
45.487 +
45.488 + /** Useful constant for country.
45.489 + */
45.490 + static public final Locale US = createConstant("en", "US");
45.491 +
45.492 + /** Useful constant for country.
45.493 + */
45.494 + static public final Locale CANADA = createConstant("en", "CA");
45.495 +
45.496 + /** Useful constant for country.
45.497 + */
45.498 + static public final Locale CANADA_FRENCH = createConstant("fr", "CA");
45.499 +
45.500 + /**
45.501 + * Useful constant for the root locale. The root locale is the locale whose
45.502 + * language, country, and variant are empty ("") strings. This is regarded
45.503 + * as the base locale of all locales, and is used as the language/country
45.504 + * neutral locale for the locale sensitive operations.
45.505 + *
45.506 + * @since 1.6
45.507 + */
45.508 + static public final Locale ROOT = createConstant("", "");
45.509 +
45.510 + /**
45.511 + * The key for the private use extension ('x').
45.512 + *
45.513 + * @see #getExtension(char)
45.514 + * @see Builder#setExtension(char, String)
45.515 + * @since 1.7
45.516 + */
45.517 + static public final char PRIVATE_USE_EXTENSION = 'x';
45.518 +
45.519 + /**
45.520 + * The key for Unicode locale extension ('u').
45.521 + *
45.522 + * @see #getExtension(char)
45.523 + * @see Builder#setExtension(char, String)
45.524 + * @since 1.7
45.525 + */
45.526 + static public final char UNICODE_LOCALE_EXTENSION = 'u';
45.527 +
45.528 + /** serialization ID
45.529 + */
45.530 + static final long serialVersionUID = 9149081749638150636L;
45.531 +
45.532 + /**
45.533 + * Display types for retrieving localized names from the name providers.
45.534 + */
45.535 + private static final int DISPLAY_LANGUAGE = 0;
45.536 + private static final int DISPLAY_COUNTRY = 1;
45.537 + private static final int DISPLAY_VARIANT = 2;
45.538 + private static final int DISPLAY_SCRIPT = 3;
45.539 +
45.540 + /**
45.541 + * Private constructor used by getInstance method
45.542 + */
45.543 + private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
45.544 + this.baseLocale = baseLocale;
45.545 + this.localeExtensions = extensions;
45.546 + }
45.547 +
45.548 + /**
45.549 + * Construct a locale from language, country and variant.
45.550 + * This constructor normalizes the language value to lowercase and
45.551 + * the country value to uppercase.
45.552 + * <p>
45.553 + * <b>Note:</b>
45.554 + * <ul>
45.555 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
45.556 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
45.557 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
45.558 + * API on Locale will return only the OLD codes.
45.559 + * <li>For backward compatibility reasons, this constructor does not make
45.560 + * any syntactic checks on the input.
45.561 + * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
45.562 + * see <a href="#special_cases_constructor">Special Cases</a> for more information.
45.563 + * </ul>
45.564 + *
45.565 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
45.566 + * up to 8 characters in length. See the <code>Locale</code> class description about
45.567 + * valid language values.
45.568 + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
45.569 + * See the <code>Locale</code> class description about valid country values.
45.570 + * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
45.571 + * See the <code>Locale</code> class description for the details.
45.572 + * @exception NullPointerException thrown if any argument is null.
45.573 + */
45.574 + public Locale(String language, String country, String variant) {
45.575 + if (language== null || country == null || variant == null) {
45.576 + throw new NullPointerException();
45.577 + }
45.578 + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
45.579 + localeExtensions = getCompatibilityExtensions(language, "", country, variant);
45.580 + }
45.581 +
45.582 + /**
45.583 + * Construct a locale from language and country.
45.584 + * This constructor normalizes the language value to lowercase and
45.585 + * the country value to uppercase.
45.586 + * <p>
45.587 + * <b>Note:</b>
45.588 + * <ul>
45.589 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
45.590 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
45.591 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
45.592 + * API on Locale will return only the OLD codes.
45.593 + * <li>For backward compatibility reasons, this constructor does not make
45.594 + * any syntactic checks on the input.
45.595 + * </ul>
45.596 + *
45.597 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
45.598 + * up to 8 characters in length. See the <code>Locale</code> class description about
45.599 + * valid language values.
45.600 + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
45.601 + * See the <code>Locale</code> class description about valid country values.
45.602 + * @exception NullPointerException thrown if either argument is null.
45.603 + */
45.604 + public Locale(String language, String country) {
45.605 + this(language, country, "");
45.606 + }
45.607 +
45.608 + /**
45.609 + * Construct a locale from a language code.
45.610 + * This constructor normalizes the language value to lowercase.
45.611 + * <p>
45.612 + * <b>Note:</b>
45.613 + * <ul>
45.614 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
45.615 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
45.616 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
45.617 + * API on Locale will return only the OLD codes.
45.618 + * <li>For backward compatibility reasons, this constructor does not make
45.619 + * any syntactic checks on the input.
45.620 + * </ul>
45.621 + *
45.622 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
45.623 + * up to 8 characters in length. See the <code>Locale</code> class description about
45.624 + * valid language values.
45.625 + * @exception NullPointerException thrown if argument is null.
45.626 + * @since 1.4
45.627 + */
45.628 + public Locale(String language) {
45.629 + this(language, "", "");
45.630 + }
45.631 +
45.632 + /**
45.633 + * This method must be called only for creating the Locale.*
45.634 + * constants due to making shortcuts.
45.635 + */
45.636 + private static Locale createConstant(String lang, String country) {
45.637 + BaseLocale base = BaseLocale.createInstance(lang, country);
45.638 + return getInstance(base, null);
45.639 + }
45.640 +
45.641 + /**
45.642 + * Returns a <code>Locale</code> constructed from the given
45.643 + * <code>language</code>, <code>country</code> and
45.644 + * <code>variant</code>. If the same <code>Locale</code> instance
45.645 + * is available in the cache, then that instance is
45.646 + * returned. Otherwise, a new <code>Locale</code> instance is
45.647 + * created and cached.
45.648 + *
45.649 + * @param language lowercase 2 to 8 language code.
45.650 + * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code.
45.651 + * @param variant vendor and browser specific code. See class description.
45.652 + * @return the <code>Locale</code> instance requested
45.653 + * @exception NullPointerException if any argument is null.
45.654 + */
45.655 + static Locale getInstance(String language, String country, String variant) {
45.656 + return getInstance(language, "", country, variant, null);
45.657 + }
45.658 +
45.659 + static Locale getInstance(String language, String script, String country,
45.660 + String variant, LocaleExtensions extensions) {
45.661 + if (language== null || script == null || country == null || variant == null) {
45.662 + throw new NullPointerException();
45.663 + }
45.664 +
45.665 + if (extensions == null) {
45.666 + extensions = getCompatibilityExtensions(language, script, country, variant);
45.667 + }
45.668 +
45.669 + BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant);
45.670 + return getInstance(baseloc, extensions);
45.671 + }
45.672 +
45.673 + static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
45.674 + LocaleKey key = new LocaleKey(baseloc, extensions);
45.675 + return LOCALECACHE.get(key);
45.676 + }
45.677 +
45.678 + private static class Cache extends LocaleObjectCache<LocaleKey, Locale> {
45.679 + private Cache() {
45.680 + }
45.681 +
45.682 + @Override
45.683 + protected Locale createObject(LocaleKey key) {
45.684 + return new Locale(key.base, key.exts);
45.685 + }
45.686 + }
45.687 +
45.688 + private static final class LocaleKey {
45.689 + private final BaseLocale base;
45.690 + private final LocaleExtensions exts;
45.691 + private final int hash;
45.692 +
45.693 + private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) {
45.694 + base = baseLocale;
45.695 + exts = extensions;
45.696 +
45.697 + // Calculate the hash value here because it's always used.
45.698 + int h = base.hashCode();
45.699 + if (exts != null) {
45.700 + h ^= exts.hashCode();
45.701 + }
45.702 + hash = h;
45.703 + }
45.704 +
45.705 + @Override
45.706 + public boolean equals(Object obj) {
45.707 + if (this == obj) {
45.708 + return true;
45.709 + }
45.710 + if (!(obj instanceof LocaleKey)) {
45.711 + return false;
45.712 + }
45.713 + LocaleKey other = (LocaleKey)obj;
45.714 + if (hash != other.hash || !base.equals(other.base)) {
45.715 + return false;
45.716 + }
45.717 + if (exts == null) {
45.718 + return other.exts == null;
45.719 + }
45.720 + return exts.equals(other.exts);
45.721 + }
45.722 +
45.723 + @Override
45.724 + public int hashCode() {
45.725 + return hash;
45.726 + }
45.727 + }
45.728 +
45.729 + /**
45.730 + * Gets the current value of the default locale for this instance
45.731 + * of the Java Virtual Machine.
45.732 + * <p>
45.733 + * The Java Virtual Machine sets the default locale during startup
45.734 + * based on the host environment. It is used by many locale-sensitive
45.735 + * methods if no locale is explicitly specified.
45.736 + * It can be changed using the
45.737 + * {@link #setDefault(java.util.Locale) setDefault} method.
45.738 + *
45.739 + * @return the default locale for this instance of the Java Virtual Machine
45.740 + */
45.741 + public static Locale getDefault() {
45.742 + // do not synchronize this method - see 4071298
45.743 + // it's OK if more than one default locale happens to be created
45.744 + if (defaultLocale == null) {
45.745 + initDefault();
45.746 + }
45.747 + return defaultLocale;
45.748 + }
45.749 +
45.750 + /**
45.751 + * Gets the current value of the default locale for the specified Category
45.752 + * for this instance of the Java Virtual Machine.
45.753 + * <p>
45.754 + * The Java Virtual Machine sets the default locale during startup based
45.755 + * on the host environment. It is used by many locale-sensitive methods
45.756 + * if no locale is explicitly specified. It can be changed using the
45.757 + * setDefault(Locale.Category, Locale) method.
45.758 + *
45.759 + * @param category - the specified category to get the default locale
45.760 + * @throws NullPointerException - if category is null
45.761 + * @return the default locale for the specified Category for this instance
45.762 + * of the Java Virtual Machine
45.763 + * @see #setDefault(Locale.Category, Locale)
45.764 + * @since 1.7
45.765 + */
45.766 + public static Locale getDefault(Locale.Category category) {
45.767 + // do not synchronize this method - see 4071298
45.768 + // it's OK if more than one default locale happens to be created
45.769 + switch (category) {
45.770 + case DISPLAY:
45.771 + if (defaultDisplayLocale == null) {
45.772 + initDefault(category);
45.773 + }
45.774 + return defaultDisplayLocale;
45.775 + case FORMAT:
45.776 + if (defaultFormatLocale == null) {
45.777 + initDefault(category);
45.778 + }
45.779 + return defaultFormatLocale;
45.780 + default:
45.781 + assert false: "Unknown Category";
45.782 + }
45.783 + return getDefault();
45.784 + }
45.785 +
45.786 + private static void initDefault() {
45.787 + String language, region, script, country, variant;
45.788 + language = AccessController.doPrivileged(
45.789 + new GetPropertyAction("user.language", "en"));
45.790 + // for compatibility, check for old user.region property
45.791 + region = AccessController.doPrivileged(
45.792 + new GetPropertyAction("user.region"));
45.793 + if (region != null) {
45.794 + // region can be of form country, country_variant, or _variant
45.795 + int i = region.indexOf('_');
45.796 + if (i >= 0) {
45.797 + country = region.substring(0, i);
45.798 + variant = region.substring(i + 1);
45.799 + } else {
45.800 + country = region;
45.801 + variant = "";
45.802 + }
45.803 + script = "";
45.804 + } else {
45.805 + script = AccessController.doPrivileged(
45.806 + new GetPropertyAction("user.script", ""));
45.807 + country = AccessController.doPrivileged(
45.808 + new GetPropertyAction("user.country", ""));
45.809 + variant = AccessController.doPrivileged(
45.810 + new GetPropertyAction("user.variant", ""));
45.811 + }
45.812 + defaultLocale = getInstance(language, script, country, variant, null);
45.813 + }
45.814 +
45.815 + private static void initDefault(Locale.Category category) {
45.816 + // make sure defaultLocale is initialized
45.817 + if (defaultLocale == null) {
45.818 + initDefault();
45.819 + }
45.820 +
45.821 + Locale defaultCategoryLocale = getInstance(
45.822 + AccessController.doPrivileged(
45.823 + new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
45.824 + AccessController.doPrivileged(
45.825 + new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
45.826 + AccessController.doPrivileged(
45.827 + new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
45.828 + AccessController.doPrivileged(
45.829 + new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
45.830 + null);
45.831 +
45.832 + switch (category) {
45.833 + case DISPLAY:
45.834 + defaultDisplayLocale = defaultCategoryLocale;
45.835 + break;
45.836 + case FORMAT:
45.837 + defaultFormatLocale = defaultCategoryLocale;
45.838 + break;
45.839 + }
45.840 + }
45.841 +
45.842 + /**
45.843 + * Sets the default locale for this instance of the Java Virtual Machine.
45.844 + * This does not affect the host locale.
45.845 + * <p>
45.846 + * If there is a security manager, its <code>checkPermission</code>
45.847 + * method is called with a <code>PropertyPermission("user.language", "write")</code>
45.848 + * permission before the default locale is changed.
45.849 + * <p>
45.850 + * The Java Virtual Machine sets the default locale during startup
45.851 + * based on the host environment. It is used by many locale-sensitive
45.852 + * methods if no locale is explicitly specified.
45.853 + * <p>
45.854 + * Since changing the default locale may affect many different areas
45.855 + * of functionality, this method should only be used if the caller
45.856 + * is prepared to reinitialize locale-sensitive code running
45.857 + * within the same Java Virtual Machine.
45.858 + * <p>
45.859 + * By setting the default locale with this method, all of the default
45.860 + * locales for each Category are also set to the specified default locale.
45.861 + *
45.862 + * @throws SecurityException
45.863 + * if a security manager exists and its
45.864 + * <code>checkPermission</code> method doesn't allow the operation.
45.865 + * @throws NullPointerException if <code>newLocale</code> is null
45.866 + * @param newLocale the new default locale
45.867 + * @see SecurityManager#checkPermission
45.868 + * @see java.util.PropertyPermission
45.869 + */
45.870 + public static synchronized void setDefault(Locale newLocale) {
45.871 + setDefault(Category.DISPLAY, newLocale);
45.872 + setDefault(Category.FORMAT, newLocale);
45.873 + defaultLocale = newLocale;
45.874 + }
45.875 +
45.876 + /**
45.877 + * Sets the default locale for the specified Category for this instance
45.878 + * of the Java Virtual Machine. This does not affect the host locale.
45.879 + * <p>
45.880 + * If there is a security manager, its checkPermission method is called
45.881 + * with a PropertyPermission("user.language", "write") permission before
45.882 + * the default locale is changed.
45.883 + * <p>
45.884 + * The Java Virtual Machine sets the default locale during startup based
45.885 + * on the host environment. It is used by many locale-sensitive methods
45.886 + * if no locale is explicitly specified.
45.887 + * <p>
45.888 + * Since changing the default locale may affect many different areas of
45.889 + * functionality, this method should only be used if the caller is
45.890 + * prepared to reinitialize locale-sensitive code running within the
45.891 + * same Java Virtual Machine.
45.892 + * <p>
45.893 + *
45.894 + * @param category - the specified category to set the default locale
45.895 + * @param newLocale - the new default locale
45.896 + * @throws SecurityException - if a security manager exists and its
45.897 + * checkPermission method doesn't allow the operation.
45.898 + * @throws NullPointerException - if category and/or newLocale is null
45.899 + * @see SecurityManager#checkPermission(java.security.Permission)
45.900 + * @see PropertyPermission
45.901 + * @see #getDefault(Locale.Category)
45.902 + * @since 1.7
45.903 + */
45.904 + public static synchronized void setDefault(Locale.Category category,
45.905 + Locale newLocale) {
45.906 + if (category == null)
45.907 + throw new NullPointerException("Category cannot be NULL");
45.908 + if (newLocale == null)
45.909 + throw new NullPointerException("Can't set default locale to NULL");
45.910 +
45.911 + SecurityManager sm = System.getSecurityManager();
45.912 + if (sm != null) sm.checkPermission(new PropertyPermission
45.913 + ("user.language", "write"));
45.914 + switch (category) {
45.915 + case DISPLAY:
45.916 + defaultDisplayLocale = newLocale;
45.917 + break;
45.918 + case FORMAT:
45.919 + defaultFormatLocale = newLocale;
45.920 + break;
45.921 + default:
45.922 + assert false: "Unknown Category";
45.923 + }
45.924 + }
45.925 +
45.926 + /**
45.927 + * Returns an array of all installed locales.
45.928 + * The returned array represents the union of locales supported
45.929 + * by the Java runtime environment and by installed
45.930 + * {@link java.util.spi.LocaleServiceProvider LocaleServiceProvider}
45.931 + * implementations. It must contain at least a <code>Locale</code>
45.932 + * instance equal to {@link java.util.Locale#US Locale.US}.
45.933 + *
45.934 + * @return An array of installed locales.
45.935 + */
45.936 + public static Locale[] getAvailableLocales() {
45.937 + return LocaleServiceProviderPool.getAllAvailableLocales();
45.938 + }
45.939 +
45.940 + /**
45.941 + * Returns a list of all 2-letter country codes defined in ISO 3166.
45.942 + * Can be used to create Locales.
45.943 + * <p>
45.944 + * <b>Note:</b> The <code>Locale</code> class also supports other codes for
45.945 + * country (region), such as 3-letter numeric UN M.49 area codes.
45.946 + * Therefore, the list returned by this method does not contain ALL valid
45.947 + * codes that can be used to create Locales.
45.948 + */
45.949 + public static String[] getISOCountries() {
45.950 + if (isoCountries == null) {
45.951 + isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
45.952 + }
45.953 + String[] result = new String[isoCountries.length];
45.954 + System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
45.955 + return result;
45.956 + }
45.957 +
45.958 + /**
45.959 + * Returns a list of all 2-letter language codes defined in ISO 639.
45.960 + * Can be used to create Locales.
45.961 + * <p>
45.962 + * <b>Note:</b>
45.963 + * <ul>
45.964 + * <li>ISO 639 is not a stable standard— some languages' codes have changed.
45.965 + * The list this function returns includes both the new and the old codes for the
45.966 + * languages whose codes have changed.
45.967 + * <li>The <code>Locale</code> class also supports language codes up to
45.968 + * 8 characters in length. Therefore, the list returned by this method does
45.969 + * not contain ALL valid codes that can be used to create Locales.
45.970 + * </ul>
45.971 + */
45.972 + public static String[] getISOLanguages() {
45.973 + if (isoLanguages == null) {
45.974 + isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
45.975 + }
45.976 + String[] result = new String[isoLanguages.length];
45.977 + System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
45.978 + return result;
45.979 + }
45.980 +
45.981 + private static final String[] getISO2Table(String table) {
45.982 + int len = table.length() / 5;
45.983 + String[] isoTable = new String[len];
45.984 + for (int i = 0, j = 0; i < len; i++, j += 5) {
45.985 + isoTable[i] = table.substring(j, j + 2);
45.986 + }
45.987 + return isoTable;
45.988 + }
45.989 +
45.990 + /**
45.991 + * Returns the language code of this Locale.
45.992 + *
45.993 + * <p><b>Note:</b> ISO 639 is not a stable standard— some languages' codes have changed.
45.994 + * Locale's constructor recognizes both the new and the old codes for the languages
45.995 + * whose codes have changed, but this function always returns the old code. If you
45.996 + * want to check for a specific language whose code has changed, don't do
45.997 + * <pre>
45.998 + * if (locale.getLanguage().equals("he")) // BAD!
45.999 + * ...
45.1000 + * </pre>
45.1001 + * Instead, do
45.1002 + * <pre>
45.1003 + * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
45.1004 + * ...
45.1005 + * </pre>
45.1006 + * @return The language code, or the empty string if none is defined.
45.1007 + * @see #getDisplayLanguage
45.1008 + */
45.1009 + public String getLanguage() {
45.1010 + return baseLocale.getLanguage();
45.1011 + }
45.1012 +
45.1013 + /**
45.1014 + * Returns the script for this locale, which should
45.1015 + * either be the empty string or an ISO 15924 4-letter script
45.1016 + * code. The first letter is uppercase and the rest are
45.1017 + * lowercase, for example, 'Latn', 'Cyrl'.
45.1018 + *
45.1019 + * @return The script code, or the empty string if none is defined.
45.1020 + * @see #getDisplayScript
45.1021 + * @since 1.7
45.1022 + */
45.1023 + public String getScript() {
45.1024 + return baseLocale.getScript();
45.1025 + }
45.1026 +
45.1027 + /**
45.1028 + * Returns the country/region code for this locale, which should
45.1029 + * either be the empty string, an uppercase ISO 3166 2-letter code,
45.1030 + * or a UN M.49 3-digit code.
45.1031 + *
45.1032 + * @return The country/region code, or the empty string if none is defined.
45.1033 + * @see #getDisplayCountry
45.1034 + */
45.1035 + public String getCountry() {
45.1036 + return baseLocale.getRegion();
45.1037 + }
45.1038 +
45.1039 + /**
45.1040 + * Returns the variant code for this locale.
45.1041 + *
45.1042 + * @return The variant code, or the empty string if none is defined.
45.1043 + * @see #getDisplayVariant
45.1044 + */
45.1045 + public String getVariant() {
45.1046 + return baseLocale.getVariant();
45.1047 + }
45.1048 +
45.1049 + /**
45.1050 + * Returns the extension (or private use) value associated with
45.1051 + * the specified key, or null if there is no extension
45.1052 + * associated with the key. To be well-formed, the key must be one
45.1053 + * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
45.1054 + * for example 'z' and 'Z' represent the same extension.
45.1055 + *
45.1056 + * @param key the extension key
45.1057 + * @return The extension, or null if this locale defines no
45.1058 + * extension for the specified key.
45.1059 + * @throws IllegalArgumentException if key is not well-formed
45.1060 + * @see #PRIVATE_USE_EXTENSION
45.1061 + * @see #UNICODE_LOCALE_EXTENSION
45.1062 + * @since 1.7
45.1063 + */
45.1064 + public String getExtension(char key) {
45.1065 + if (!LocaleExtensions.isValidKey(key)) {
45.1066 + throw new IllegalArgumentException("Ill-formed extension key: " + key);
45.1067 + }
45.1068 + return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key);
45.1069 + }
45.1070 +
45.1071 + /**
45.1072 + * Returns the set of extension keys associated with this locale, or the
45.1073 + * empty set if it has no extensions. The returned set is unmodifiable.
45.1074 + * The keys will all be lower-case.
45.1075 + *
45.1076 + * @return The set of extension keys, or the empty set if this locale has
45.1077 + * no extensions.
45.1078 + * @since 1.7
45.1079 + */
45.1080 + public Set<Character> getExtensionKeys() {
45.1081 + if (localeExtensions == null) {
45.1082 + return Collections.emptySet();
45.1083 + }
45.1084 + return localeExtensions.getKeys();
45.1085 + }
45.1086 +
45.1087 + /**
45.1088 + * Returns the set of unicode locale attributes associated with
45.1089 + * this locale, or the empty set if it has no attributes. The
45.1090 + * returned set is unmodifiable.
45.1091 + *
45.1092 + * @return The set of attributes.
45.1093 + * @since 1.7
45.1094 + */
45.1095 + public Set<String> getUnicodeLocaleAttributes() {
45.1096 + if (localeExtensions == null) {
45.1097 + return Collections.emptySet();
45.1098 + }
45.1099 + return localeExtensions.getUnicodeLocaleAttributes();
45.1100 + }
45.1101 +
45.1102 + /**
45.1103 + * Returns the Unicode locale type associated with the specified Unicode locale key
45.1104 + * for this locale. Returns the empty string for keys that are defined with no type.
45.1105 + * Returns null if the key is not defined. Keys are case-insensitive. The key must
45.1106 + * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
45.1107 + * thrown.
45.1108 + *
45.1109 + * @param key the Unicode locale key
45.1110 + * @return The Unicode locale type associated with the key, or null if the
45.1111 + * locale does not define the key.
45.1112 + * @throws IllegalArgumentException if the key is not well-formed
45.1113 + * @throws NullPointerException if <code>key</code> is null
45.1114 + * @since 1.7
45.1115 + */
45.1116 + public String getUnicodeLocaleType(String key) {
45.1117 + if (!UnicodeLocaleExtension.isKey(key)) {
45.1118 + throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
45.1119 + }
45.1120 + return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key);
45.1121 + }
45.1122 +
45.1123 + /**
45.1124 + * Returns the set of Unicode locale keys defined by this locale, or the empty set if
45.1125 + * this locale has none. The returned set is immutable. Keys are all lower case.
45.1126 + *
45.1127 + * @return The set of Unicode locale keys, or the empty set if this locale has
45.1128 + * no Unicode locale keywords.
45.1129 + * @since 1.7
45.1130 + */
45.1131 + public Set<String> getUnicodeLocaleKeys() {
45.1132 + if (localeExtensions == null) {
45.1133 + return Collections.emptySet();
45.1134 + }
45.1135 + return localeExtensions.getUnicodeLocaleKeys();
45.1136 + }
45.1137 +
45.1138 + /**
45.1139 + * Package locale method returning the Locale's BaseLocale,
45.1140 + * used by ResourceBundle
45.1141 + * @return base locale of this Locale
45.1142 + */
45.1143 + BaseLocale getBaseLocale() {
45.1144 + return baseLocale;
45.1145 + }
45.1146 +
45.1147 + /**
45.1148 + * Package private method returning the Locale's LocaleExtensions,
45.1149 + * used by ResourceBundle.
45.1150 + * @return locale exnteions of this Locale,
45.1151 + * or {@code null} if no extensions are defined
45.1152 + */
45.1153 + LocaleExtensions getLocaleExtensions() {
45.1154 + return localeExtensions;
45.1155 + }
45.1156 +
45.1157 + /**
45.1158 + * Returns a string representation of this <code>Locale</code>
45.1159 + * object, consisting of language, country, variant, script,
45.1160 + * and extensions as below:
45.1161 + * <p><blockquote>
45.1162 + * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions
45.1163 + * </blockquote>
45.1164 + *
45.1165 + * Language is always lower case, country is always upper case, script is always title
45.1166 + * case, and extensions are always lower case. Extensions and private use subtags
45.1167 + * will be in canonical order as explained in {@link #toLanguageTag}.
45.1168 + *
45.1169 + * <p>When the locale has neither script nor extensions, the result is the same as in
45.1170 + * Java 6 and prior.
45.1171 + *
45.1172 + * <p>If both the language and country fields are missing, this function will return
45.1173 + * the empty string, even if the variant, script, or extensions field is present (you
45.1174 + * can't have a locale with just a variant, the variant must accompany a well-formed
45.1175 + * language or country code).
45.1176 + *
45.1177 + * <p>If script or extensions are present and variant is missing, no underscore is
45.1178 + * added before the "#".
45.1179 + *
45.1180 + * <p>This behavior is designed to support debugging and to be compatible with
45.1181 + * previous uses of <code>toString</code> that expected language, country, and variant
45.1182 + * fields only. To represent a Locale as a String for interchange purposes, use
45.1183 + * {@link #toLanguageTag}.
45.1184 + *
45.1185 + * <p>Examples: <ul><tt>
45.1186 + * <li>en
45.1187 + * <li>de_DE
45.1188 + * <li>_GB
45.1189 + * <li>en_US_WIN
45.1190 + * <li>de__POSIX
45.1191 + * <li>zh_CN_#Hans
45.1192 + * <li>zh_TW_#Hant-x-java
45.1193 + * <li>th_TH_TH_#u-nu-thai</tt></ul>
45.1194 + *
45.1195 + * @return A string representation of the Locale, for debugging.
45.1196 + * @see #getDisplayName
45.1197 + * @see #toLanguageTag
45.1198 + */
45.1199 + @Override
45.1200 + public final String toString() {
45.1201 + boolean l = (baseLocale.getLanguage().length() != 0);
45.1202 + boolean s = (baseLocale.getScript().length() != 0);
45.1203 + boolean r = (baseLocale.getRegion().length() != 0);
45.1204 + boolean v = (baseLocale.getVariant().length() != 0);
45.1205 + boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
45.1206 +
45.1207 + StringBuilder result = new StringBuilder(baseLocale.getLanguage());
45.1208 + if (r || (l && (v || s || e))) {
45.1209 + result.append('_')
45.1210 + .append(baseLocale.getRegion()); // This may just append '_'
45.1211 + }
45.1212 + if (v && (l || r)) {
45.1213 + result.append('_')
45.1214 + .append(baseLocale.getVariant());
45.1215 + }
45.1216 +
45.1217 + if (s && (l || r)) {
45.1218 + result.append("_#")
45.1219 + .append(baseLocale.getScript());
45.1220 + }
45.1221 +
45.1222 + if (e && (l || r)) {
45.1223 + result.append('_');
45.1224 + if (!s) {
45.1225 + result.append('#');
45.1226 + }
45.1227 + result.append(localeExtensions.getID());
45.1228 + }
45.1229 +
45.1230 + return result.toString();
45.1231 + }
45.1232 +
45.1233 + /**
45.1234 + * Returns a well-formed IETF BCP 47 language tag representing
45.1235 + * this locale.
45.1236 + *
45.1237 + * <p>If this <code>Locale</code> has a language, country, or
45.1238 + * variant that does not satisfy the IETF BCP 47 language tag
45.1239 + * syntax requirements, this method handles these fields as
45.1240 + * described below:
45.1241 + *
45.1242 + * <p><b>Language:</b> If language is empty, or not <a
45.1243 + * href="#def_language" >well-formed</a> (for example "a" or
45.1244 + * "e2"), it will be emitted as "und" (Undetermined).
45.1245 + *
45.1246 + * <p><b>Country:</b> If country is not <a
45.1247 + * href="#def_region">well-formed</a> (for example "12" or "USA"),
45.1248 + * it will be omitted.
45.1249 + *
45.1250 + * <p><b>Variant:</b> If variant <b>is</b> <a
45.1251 + * href="#def_variant">well-formed</a>, each sub-segment
45.1252 + * (delimited by '-' or '_') is emitted as a subtag. Otherwise:
45.1253 + * <ul>
45.1254 + *
45.1255 + * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>
45.1256 + * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
45.1257 + * ill-formed sub-segment and all following will be appended to
45.1258 + * the private use subtag. The first appended subtag will be
45.1259 + * "lvariant", followed by the sub-segments in order, separated by
45.1260 + * hyphen. For example, "x-lvariant-WIN",
45.1261 + * "Oracle-x-lvariant-JDK-Standard-Edition".
45.1262 + *
45.1263 + * <li>if any sub-segment does not match
45.1264 + * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated
45.1265 + * and the problematic sub-segment and all following sub-segments
45.1266 + * will be omitted. If the remainder is non-empty, it will be
45.1267 + * emitted as a private use subtag as above (even if the remainder
45.1268 + * turns out to be well-formed). For example,
45.1269 + * "Solaris_isjustthecoolestthing" is emitted as
45.1270 + * "x-lvariant-Solaris", not as "solaris".</li></ul>
45.1271 + *
45.1272 + * <p><b>Special Conversions:</b> Java supports some old locale
45.1273 + * representations, including deprecated ISO language codes,
45.1274 + * for compatibility. This method performs the following
45.1275 + * conversions:
45.1276 + * <ul>
45.1277 + *
45.1278 + * <li>Deprecated ISO language codes "iw", "ji", and "in" are
45.1279 + * converted to "he", "yi", and "id", respectively.
45.1280 + *
45.1281 + * <li>A locale with language "no", country "NO", and variant
45.1282 + * "NY", representing Norwegian Nynorsk (Norway), is converted
45.1283 + * to a language tag "nn-NO".</li></ul>
45.1284 + *
45.1285 + * <p><b>Note:</b> Although the language tag created by this
45.1286 + * method is well-formed (satisfies the syntax requirements
45.1287 + * defined by the IETF BCP 47 specification), it is not
45.1288 + * necessarily a valid BCP 47 language tag. For example,
45.1289 + * <pre>
45.1290 + * new Locale("xx", "YY").toLanguageTag();</pre>
45.1291 + *
45.1292 + * will return "xx-YY", but the language subtag "xx" and the
45.1293 + * region subtag "YY" are invalid because they are not registered
45.1294 + * in the IANA Language Subtag Registry.
45.1295 + *
45.1296 + * @return a BCP47 language tag representing the locale
45.1297 + * @see #forLanguageTag(String)
45.1298 + * @since 1.7
45.1299 + */
45.1300 + public String toLanguageTag() {
45.1301 + LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
45.1302 + StringBuilder buf = new StringBuilder();
45.1303 +
45.1304 + String subtag = tag.getLanguage();
45.1305 + if (subtag.length() > 0) {
45.1306 + buf.append(LanguageTag.canonicalizeLanguage(subtag));
45.1307 + }
45.1308 +
45.1309 + subtag = tag.getScript();
45.1310 + if (subtag.length() > 0) {
45.1311 + buf.append(LanguageTag.SEP);
45.1312 + buf.append(LanguageTag.canonicalizeScript(subtag));
45.1313 + }
45.1314 +
45.1315 + subtag = tag.getRegion();
45.1316 + if (subtag.length() > 0) {
45.1317 + buf.append(LanguageTag.SEP);
45.1318 + buf.append(LanguageTag.canonicalizeRegion(subtag));
45.1319 + }
45.1320 +
45.1321 + List<String>subtags = tag.getVariants();
45.1322 + for (String s : subtags) {
45.1323 + buf.append(LanguageTag.SEP);
45.1324 + // preserve casing
45.1325 + buf.append(s);
45.1326 + }
45.1327 +
45.1328 + subtags = tag.getExtensions();
45.1329 + for (String s : subtags) {
45.1330 + buf.append(LanguageTag.SEP);
45.1331 + buf.append(LanguageTag.canonicalizeExtension(s));
45.1332 + }
45.1333 +
45.1334 + subtag = tag.getPrivateuse();
45.1335 + if (subtag.length() > 0) {
45.1336 + if (buf.length() > 0) {
45.1337 + buf.append(LanguageTag.SEP);
45.1338 + }
45.1339 + buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
45.1340 + // preserve casing
45.1341 + buf.append(subtag);
45.1342 + }
45.1343 +
45.1344 + return buf.toString();
45.1345 + }
45.1346 +
45.1347 + /**
45.1348 + * Returns a locale for the specified IETF BCP 47 language tag string.
45.1349 + *
45.1350 + * <p>If the specified language tag contains any ill-formed subtags,
45.1351 + * the first such subtag and all following subtags are ignored. Compare
45.1352 + * to {@link Locale.Builder#setLanguageTag} which throws an exception
45.1353 + * in this case.
45.1354 + *
45.1355 + * <p>The following <b>conversions</b> are performed:<ul>
45.1356 + *
45.1357 + * <li>The language code "und" is mapped to language "".
45.1358 + *
45.1359 + * <li>The language codes "he", "yi", and "id" are mapped to "iw",
45.1360 + * "ji", and "in" respectively. (This is the same canonicalization
45.1361 + * that's done in Locale's constructors.)
45.1362 + *
45.1363 + * <li>The portion of a private use subtag prefixed by "lvariant",
45.1364 + * if any, is removed and appended to the variant field in the
45.1365 + * result locale (without case normalization). If it is then
45.1366 + * empty, the private use subtag is discarded:
45.1367 + *
45.1368 + * <pre>
45.1369 + * Locale loc;
45.1370 + * loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");
45.1371 + * loc.getVariant(); // returns "POSIX"
45.1372 + * loc.getExtension('x'); // returns null
45.1373 + *
45.1374 + * loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
45.1375 + * loc.getVariant(); // returns "POSIX_Abc_Def"
45.1376 + * loc.getExtension('x'); // returns "urp"
45.1377 + * </pre>
45.1378 + *
45.1379 + * <li>When the languageTag argument contains an extlang subtag,
45.1380 + * the first such subtag is used as the language, and the primary
45.1381 + * language subtag and other extlang subtags are ignored:
45.1382 + *
45.1383 + * <pre>
45.1384 + * Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
45.1385 + * Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
45.1386 + * </pre>
45.1387 + *
45.1388 + * <li>Case is normalized except for variant tags, which are left
45.1389 + * unchanged. Language is normalized to lower case, script to
45.1390 + * title case, country to upper case, and extensions to lower
45.1391 + * case.
45.1392 + *
45.1393 + * <li>If, after processing, the locale would exactly match either
45.1394 + * ja_JP_JP or th_TH_TH with no extensions, the appropriate
45.1395 + * extensions are added as though the constructor had been called:
45.1396 + *
45.1397 + * <pre>
45.1398 + * Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();
45.1399 + * // returns "ja-JP-u-ca-japanese-x-lvariant-JP"
45.1400 + * Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();
45.1401 + * // returns "th-TH-u-nu-thai-x-lvariant-TH"
45.1402 + * <pre></ul>
45.1403 + *
45.1404 + * <p>This implements the 'Language-Tag' production of BCP47, and
45.1405 + * so supports grandfathered (regular and irregular) as well as
45.1406 + * private use language tags. Stand alone private use tags are
45.1407 + * represented as empty language and extension 'x-whatever',
45.1408 + * and grandfathered tags are converted to their canonical replacements
45.1409 + * where they exist.
45.1410 + *
45.1411 + * <p>Grandfathered tags with canonical replacements are as follows:
45.1412 + *
45.1413 + * <table>
45.1414 + * <tbody align="center">
45.1415 + * <tr><th>grandfathered tag</th><th> </th><th>modern replacement</th></tr>
45.1416 + * <tr><td>art-lojban</td><td> </td><td>jbo</td></tr>
45.1417 + * <tr><td>i-ami</td><td> </td><td>ami</td></tr>
45.1418 + * <tr><td>i-bnn</td><td> </td><td>bnn</td></tr>
45.1419 + * <tr><td>i-hak</td><td> </td><td>hak</td></tr>
45.1420 + * <tr><td>i-klingon</td><td> </td><td>tlh</td></tr>
45.1421 + * <tr><td>i-lux</td><td> </td><td>lb</td></tr>
45.1422 + * <tr><td>i-navajo</td><td> </td><td>nv</td></tr>
45.1423 + * <tr><td>i-pwn</td><td> </td><td>pwn</td></tr>
45.1424 + * <tr><td>i-tao</td><td> </td><td>tao</td></tr>
45.1425 + * <tr><td>i-tay</td><td> </td><td>tay</td></tr>
45.1426 + * <tr><td>i-tsu</td><td> </td><td>tsu</td></tr>
45.1427 + * <tr><td>no-bok</td><td> </td><td>nb</td></tr>
45.1428 + * <tr><td>no-nyn</td><td> </td><td>nn</td></tr>
45.1429 + * <tr><td>sgn-BE-FR</td><td> </td><td>sfb</td></tr>
45.1430 + * <tr><td>sgn-BE-NL</td><td> </td><td>vgt</td></tr>
45.1431 + * <tr><td>sgn-CH-DE</td><td> </td><td>sgg</td></tr>
45.1432 + * <tr><td>zh-guoyu</td><td> </td><td>cmn</td></tr>
45.1433 + * <tr><td>zh-hakka</td><td> </td><td>hak</td></tr>
45.1434 + * <tr><td>zh-min-nan</td><td> </td><td>nan</td></tr>
45.1435 + * <tr><td>zh-xiang</td><td> </td><td>hsn</td></tr>
45.1436 + * </tbody>
45.1437 + * </table>
45.1438 + *
45.1439 + * <p>Grandfathered tags with no modern replacement will be
45.1440 + * converted as follows:
45.1441 + *
45.1442 + * <table>
45.1443 + * <tbody align="center">
45.1444 + * <tr><th>grandfathered tag</th><th> </th><th>converts to</th></tr>
45.1445 + * <tr><td>cel-gaulish</td><td> </td><td>xtg-x-cel-gaulish</td></tr>
45.1446 + * <tr><td>en-GB-oed</td><td> </td><td>en-GB-x-oed</td></tr>
45.1447 + * <tr><td>i-default</td><td> </td><td>en-x-i-default</td></tr>
45.1448 + * <tr><td>i-enochian</td><td> </td><td>und-x-i-enochian</td></tr>
45.1449 + * <tr><td>i-mingo</td><td> </td><td>see-x-i-mingo</td></tr>
45.1450 + * <tr><td>zh-min</td><td> </td><td>nan-x-zh-min</td></tr>
45.1451 + * </tbody>
45.1452 + * </table>
45.1453 + *
45.1454 + * <p>For a list of all grandfathered tags, see the
45.1455 + * IANA Language Subtag Registry (search for "Type: grandfathered").
45.1456 + *
45.1457 + * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
45.1458 + * and <code>forLanguageTag</code> will round-trip.
45.1459 + *
45.1460 + * @param languageTag the language tag
45.1461 + * @return The locale that best represents the language tag.
45.1462 + * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
45.1463 + * @see #toLanguageTag()
45.1464 + * @see java.util.Locale.Builder#setLanguageTag(String)
45.1465 + * @since 1.7
45.1466 + */
45.1467 + public static Locale forLanguageTag(String languageTag) {
45.1468 + LanguageTag tag = LanguageTag.parse(languageTag, null);
45.1469 + InternalLocaleBuilder bldr = new InternalLocaleBuilder();
45.1470 + bldr.setLanguageTag(tag);
45.1471 + BaseLocale base = bldr.getBaseLocale();
45.1472 + LocaleExtensions exts = bldr.getLocaleExtensions();
45.1473 + if (exts == null && base.getVariant().length() > 0) {
45.1474 + exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
45.1475 + base.getRegion(), base.getVariant());
45.1476 + }
45.1477 + return getInstance(base, exts);
45.1478 + }
45.1479 +
45.1480 + /**
45.1481 + * Returns a three-letter abbreviation of this locale's language.
45.1482 + * If the language matches an ISO 639-1 two-letter code, the
45.1483 + * corresponding ISO 639-2/T three-letter lowercase code is
45.1484 + * returned. The ISO 639-2 language codes can be found on-line,
45.1485 + * see "Codes for the Representation of Names of Languages Part 2:
45.1486 + * Alpha-3 Code". If the locale specifies a three-letter
45.1487 + * language, the language is returned as is. If the locale does
45.1488 + * not specify a language the empty string is returned.
45.1489 + *
45.1490 + * @return A three-letter abbreviation of this locale's language.
45.1491 + * @exception MissingResourceException Throws MissingResourceException if
45.1492 + * three-letter language abbreviation is not available for this locale.
45.1493 + */
45.1494 + public String getISO3Language() throws MissingResourceException {
45.1495 + String lang = baseLocale.getLanguage();
45.1496 + if (lang.length() == 3) {
45.1497 + return lang;
45.1498 + }
45.1499 +
45.1500 + String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
45.1501 + if (language3 == null) {
45.1502 + throw new MissingResourceException("Couldn't find 3-letter language code for "
45.1503 + + lang, "FormatData_" + toString(), "ShortLanguage");
45.1504 + }
45.1505 + return language3;
45.1506 + }
45.1507 +
45.1508 + /**
45.1509 + * Returns a three-letter abbreviation for this locale's country.
45.1510 + * If the country matches an ISO 3166-1 alpha-2 code, the
45.1511 + * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
45.1512 + * If the locale doesn't specify a country, this will be the empty
45.1513 + * string.
45.1514 + *
45.1515 + * <p>The ISO 3166-1 codes can be found on-line.
45.1516 + *
45.1517 + * @return A three-letter abbreviation of this locale's country.
45.1518 + * @exception MissingResourceException Throws MissingResourceException if the
45.1519 + * three-letter country abbreviation is not available for this locale.
45.1520 + */
45.1521 + public String getISO3Country() throws MissingResourceException {
45.1522 + String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
45.1523 + if (country3 == null) {
45.1524 + throw new MissingResourceException("Couldn't find 3-letter country code for "
45.1525 + + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
45.1526 + }
45.1527 + return country3;
45.1528 + }
45.1529 +
45.1530 + private static final String getISO3Code(String iso2Code, String table) {
45.1531 + int codeLength = iso2Code.length();
45.1532 + if (codeLength == 0) {
45.1533 + return "";
45.1534 + }
45.1535 +
45.1536 + int tableLength = table.length();
45.1537 + int index = tableLength;
45.1538 + if (codeLength == 2) {
45.1539 + char c1 = iso2Code.charAt(0);
45.1540 + char c2 = iso2Code.charAt(1);
45.1541 + for (index = 0; index < tableLength; index += 5) {
45.1542 + if (table.charAt(index) == c1
45.1543 + && table.charAt(index + 1) == c2) {
45.1544 + break;
45.1545 + }
45.1546 + }
45.1547 + }
45.1548 + return index < tableLength ? table.substring(index + 2, index + 5) : null;
45.1549 + }
45.1550 +
45.1551 + /**
45.1552 + * Returns a name for the locale's language that is appropriate for display to the
45.1553 + * user.
45.1554 + * If possible, the name returned will be localized for the default locale.
45.1555 + * For example, if the locale is fr_FR and the default locale
45.1556 + * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
45.1557 + * the default locale is fr_FR, getDisplayLanguage() will return "anglais".
45.1558 + * If the name returned cannot be localized for the default locale,
45.1559 + * (say, we don't have a Japanese name for Croatian),
45.1560 + * this function falls back on the English name, and uses the ISO code as a last-resort
45.1561 + * value. If the locale doesn't specify a language, this function returns the empty string.
45.1562 + */
45.1563 + public final String getDisplayLanguage() {
45.1564 + return getDisplayLanguage(getDefault(Category.DISPLAY));
45.1565 + }
45.1566 +
45.1567 + /**
45.1568 + * Returns a name for the locale's language that is appropriate for display to the
45.1569 + * user.
45.1570 + * If possible, the name returned will be localized according to inLocale.
45.1571 + * For example, if the locale is fr_FR and inLocale
45.1572 + * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
45.1573 + * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
45.1574 + * If the name returned cannot be localized according to inLocale,
45.1575 + * (say, we don't have a Japanese name for Croatian),
45.1576 + * this function falls back on the English name, and finally
45.1577 + * on the ISO code as a last-resort value. If the locale doesn't specify a language,
45.1578 + * this function returns the empty string.
45.1579 + *
45.1580 + * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
45.1581 + */
45.1582 + public String getDisplayLanguage(Locale inLocale) {
45.1583 + return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
45.1584 + }
45.1585 +
45.1586 + /**
45.1587 + * Returns a name for the the locale's script that is appropriate for display to
45.1588 + * the user. If possible, the name will be localized for the default locale. Returns
45.1589 + * the empty string if this locale doesn't specify a script code.
45.1590 + *
45.1591 + * @return the display name of the script code for the current default locale
45.1592 + * @since 1.7
45.1593 + */
45.1594 + public String getDisplayScript() {
45.1595 + return getDisplayScript(getDefault());
45.1596 + }
45.1597 +
45.1598 + /**
45.1599 + * Returns a name for the locale's script that is appropriate
45.1600 + * for display to the user. If possible, the name will be
45.1601 + * localized for the given locale. Returns the empty string if
45.1602 + * this locale doesn't specify a script code.
45.1603 + *
45.1604 + * @return the display name of the script code for the current default locale
45.1605 + * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
45.1606 + * @since 1.7
45.1607 + */
45.1608 + public String getDisplayScript(Locale inLocale) {
45.1609 + return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
45.1610 + }
45.1611 +
45.1612 + /**
45.1613 + * Returns a name for the locale's country that is appropriate for display to the
45.1614 + * user.
45.1615 + * If possible, the name returned will be localized for the default locale.
45.1616 + * For example, if the locale is fr_FR and the default locale
45.1617 + * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
45.1618 + * the default locale is fr_FR, getDisplayCountry() will return "Etats-Unis".
45.1619 + * If the name returned cannot be localized for the default locale,
45.1620 + * (say, we don't have a Japanese name for Croatia),
45.1621 + * this function falls back on the English name, and uses the ISO code as a last-resort
45.1622 + * value. If the locale doesn't specify a country, this function returns the empty string.
45.1623 + */
45.1624 + public final String getDisplayCountry() {
45.1625 + return getDisplayCountry(getDefault(Category.DISPLAY));
45.1626 + }
45.1627 +
45.1628 + /**
45.1629 + * Returns a name for the locale's country that is appropriate for display to the
45.1630 + * user.
45.1631 + * If possible, the name returned will be localized according to inLocale.
45.1632 + * For example, if the locale is fr_FR and inLocale
45.1633 + * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
45.1634 + * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
45.1635 + * If the name returned cannot be localized according to inLocale.
45.1636 + * (say, we don't have a Japanese name for Croatia),
45.1637 + * this function falls back on the English name, and finally
45.1638 + * on the ISO code as a last-resort value. If the locale doesn't specify a country,
45.1639 + * this function returns the empty string.
45.1640 + *
45.1641 + * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
45.1642 + */
45.1643 + public String getDisplayCountry(Locale inLocale) {
45.1644 + return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
45.1645 + }
45.1646 +
45.1647 + private String getDisplayString(String code, Locale inLocale, int type) {
45.1648 + if (code.length() == 0) {
45.1649 + return "";
45.1650 + }
45.1651 +
45.1652 + if (inLocale == null) {
45.1653 + throw new NullPointerException();
45.1654 + }
45.1655 +
45.1656 + try {
45.1657 + OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
45.1658 + String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
45.1659 + String result = null;
45.1660 +
45.1661 + // Check whether a provider can provide an implementation that's closer
45.1662 + // to the requested locale than what the Java runtime itself can provide.
45.1663 + LocaleServiceProviderPool pool =
45.1664 + LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
45.1665 + if (pool.hasProviders()) {
45.1666 + result = pool.getLocalizedObject(
45.1667 + LocaleNameGetter.INSTANCE,
45.1668 + inLocale, bundle, key,
45.1669 + type, code);
45.1670 + }
45.1671 +
45.1672 + if (result == null) {
45.1673 + result = bundle.getString(key);
45.1674 + }
45.1675 +
45.1676 + if (result != null) {
45.1677 + return result;
45.1678 + }
45.1679 + }
45.1680 + catch (Exception e) {
45.1681 + // just fall through
45.1682 + }
45.1683 + return code;
45.1684 + }
45.1685 +
45.1686 + /**
45.1687 + * Returns a name for the locale's variant code that is appropriate for display to the
45.1688 + * user. If possible, the name will be localized for the default locale. If the locale
45.1689 + * doesn't specify a variant code, this function returns the empty string.
45.1690 + */
45.1691 + public final String getDisplayVariant() {
45.1692 + return getDisplayVariant(getDefault(Category.DISPLAY));
45.1693 + }
45.1694 +
45.1695 + /**
45.1696 + * Returns a name for the locale's variant code that is appropriate for display to the
45.1697 + * user. If possible, the name will be localized for inLocale. If the locale
45.1698 + * doesn't specify a variant code, this function returns the empty string.
45.1699 + *
45.1700 + * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
45.1701 + */
45.1702 + public String getDisplayVariant(Locale inLocale) {
45.1703 + if (baseLocale.getVariant().length() == 0)
45.1704 + return "";
45.1705 +
45.1706 + OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
45.1707 +
45.1708 + String names[] = getDisplayVariantArray(bundle, inLocale);
45.1709 +
45.1710 + // Get the localized patterns for formatting a list, and use
45.1711 + // them to format the list.
45.1712 + String listPattern = null;
45.1713 + String listCompositionPattern = null;
45.1714 + try {
45.1715 + listPattern = bundle.getString("ListPattern");
45.1716 + listCompositionPattern = bundle.getString("ListCompositionPattern");
45.1717 + } catch (MissingResourceException e) {
45.1718 + }
45.1719 + return formatList(names, listPattern, listCompositionPattern);
45.1720 + }
45.1721 +
45.1722 + /**
45.1723 + * Returns a name for the locale that is appropriate for display to the
45.1724 + * user. This will be the values returned by getDisplayLanguage(),
45.1725 + * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
45.1726 + * into a single string. The the non-empty values are used in order,
45.1727 + * with the second and subsequent names in parentheses. For example:
45.1728 + * <blockquote>
45.1729 + * language (script, country, variant)<br>
45.1730 + * language (country)<br>
45.1731 + * language (variant)<br>
45.1732 + * script (country)<br>
45.1733 + * country<br>
45.1734 + * </blockquote>
45.1735 + * depending on which fields are specified in the locale. If the
45.1736 + * language, sacript, country, and variant fields are all empty,
45.1737 + * this function returns the empty string.
45.1738 + */
45.1739 + public final String getDisplayName() {
45.1740 + return getDisplayName(getDefault(Category.DISPLAY));
45.1741 + }
45.1742 +
45.1743 + /**
45.1744 + * Returns a name for the locale that is appropriate for display
45.1745 + * to the user. This will be the values returned by
45.1746 + * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
45.1747 + * and getDisplayVariant() assembled into a single string.
45.1748 + * The non-empty values are used in order,
45.1749 + * with the second and subsequent names in parentheses. For example:
45.1750 + * <blockquote>
45.1751 + * language (script, country, variant)<br>
45.1752 + * language (country)<br>
45.1753 + * language (variant)<br>
45.1754 + * script (country)<br>
45.1755 + * country<br>
45.1756 + * </blockquote>
45.1757 + * depending on which fields are specified in the locale. If the
45.1758 + * language, script, country, and variant fields are all empty,
45.1759 + * this function returns the empty string.
45.1760 + *
45.1761 + * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
45.1762 + */
45.1763 + public String getDisplayName(Locale inLocale) {
45.1764 + OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
45.1765 +
45.1766 + String languageName = getDisplayLanguage(inLocale);
45.1767 + String scriptName = getDisplayScript(inLocale);
45.1768 + String countryName = getDisplayCountry(inLocale);
45.1769 + String[] variantNames = getDisplayVariantArray(bundle, inLocale);
45.1770 +
45.1771 + // Get the localized patterns for formatting a display name.
45.1772 + String displayNamePattern = null;
45.1773 + String listPattern = null;
45.1774 + String listCompositionPattern = null;
45.1775 + try {
45.1776 + displayNamePattern = bundle.getString("DisplayNamePattern");
45.1777 + listPattern = bundle.getString("ListPattern");
45.1778 + listCompositionPattern = bundle.getString("ListCompositionPattern");
45.1779 + } catch (MissingResourceException e) {
45.1780 + }
45.1781 +
45.1782 + // The display name consists of a main name, followed by qualifiers.
45.1783 + // Typically, the format is "MainName (Qualifier, Qualifier)" but this
45.1784 + // depends on what pattern is stored in the display locale.
45.1785 + String mainName = null;
45.1786 + String[] qualifierNames = null;
45.1787 +
45.1788 + // The main name is the language, or if there is no language, the script,
45.1789 + // then if no script, the country. If there is no language/script/country
45.1790 + // (an anomalous situation) then the display name is simply the variant's
45.1791 + // display name.
45.1792 + if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
45.1793 + if (variantNames.length == 0) {
45.1794 + return "";
45.1795 + } else {
45.1796 + return formatList(variantNames, listPattern, listCompositionPattern);
45.1797 + }
45.1798 + }
45.1799 + ArrayList<String> names = new ArrayList<>(4);
45.1800 + if (languageName.length() != 0) {
45.1801 + names.add(languageName);
45.1802 + }
45.1803 + if (scriptName.length() != 0) {
45.1804 + names.add(scriptName);
45.1805 + }
45.1806 + if (countryName.length() != 0) {
45.1807 + names.add(countryName);
45.1808 + }
45.1809 + if (variantNames.length != 0) {
45.1810 + for (String var : variantNames) {
45.1811 + names.add(var);
45.1812 + }
45.1813 + }
45.1814 +
45.1815 + // The first one in the main name
45.1816 + mainName = names.get(0);
45.1817 +
45.1818 + // Others are qualifiers
45.1819 + int numNames = names.size();
45.1820 + qualifierNames = (numNames > 1) ?
45.1821 + names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
45.1822 +
45.1823 + // Create an array whose first element is the number of remaining
45.1824 + // elements. This serves as a selector into a ChoiceFormat pattern from
45.1825 + // the resource. The second and third elements are the main name and
45.1826 + // the qualifier; if there are no qualifiers, the third element is
45.1827 + // unused by the format pattern.
45.1828 + Object[] displayNames = {
45.1829 + new Integer(qualifierNames.length != 0 ? 2 : 1),
45.1830 + mainName,
45.1831 + // We could also just call formatList() and have it handle the empty
45.1832 + // list case, but this is more efficient, and we want it to be
45.1833 + // efficient since all the language-only locales will not have any
45.1834 + // qualifiers.
45.1835 + qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
45.1836 + };
45.1837 +
45.1838 + if (displayNamePattern != null) {
45.1839 + return new MessageFormat(displayNamePattern).format(displayNames);
45.1840 + }
45.1841 + else {
45.1842 + // If we cannot get the message format pattern, then we use a simple
45.1843 + // hard-coded pattern. This should not occur in practice unless the
45.1844 + // installation is missing some core files (FormatData etc.).
45.1845 + StringBuilder result = new StringBuilder();
45.1846 + result.append((String)displayNames[1]);
45.1847 + if (displayNames.length > 2) {
45.1848 + result.append(" (");
45.1849 + result.append((String)displayNames[2]);
45.1850 + result.append(')');
45.1851 + }
45.1852 + return result.toString();
45.1853 + }
45.1854 + }
45.1855 +
45.1856 + /**
45.1857 + * Overrides Cloneable.
45.1858 + */
45.1859 + public Object clone()
45.1860 + {
45.1861 + try {
45.1862 + Locale that = (Locale)super.clone();
45.1863 + return that;
45.1864 + } catch (CloneNotSupportedException e) {
45.1865 + throw new InternalError();
45.1866 + }
45.1867 + }
45.1868 +
45.1869 + /**
45.1870 + * Override hashCode.
45.1871 + * Since Locales are often used in hashtables, caches the value
45.1872 + * for speed.
45.1873 + */
45.1874 + @Override
45.1875 + public int hashCode() {
45.1876 + int hc = hashCodeValue;
45.1877 + if (hc == 0) {
45.1878 + hc = baseLocale.hashCode();
45.1879 + if (localeExtensions != null) {
45.1880 + hc ^= localeExtensions.hashCode();
45.1881 + }
45.1882 + hashCodeValue = hc;
45.1883 + }
45.1884 + return hc;
45.1885 + }
45.1886 +
45.1887 + // Overrides
45.1888 +
45.1889 + /**
45.1890 + * Returns true if this Locale is equal to another object. A Locale is
45.1891 + * deemed equal to another Locale with identical language, script, country,
45.1892 + * variant and extensions, and unequal to all other objects.
45.1893 + *
45.1894 + * @return true if this Locale is equal to the specified object.
45.1895 + */
45.1896 + @Override
45.1897 + public boolean equals(Object obj) {
45.1898 + if (this == obj) // quick check
45.1899 + return true;
45.1900 + if (!(obj instanceof Locale))
45.1901 + return false;
45.1902 + BaseLocale otherBase = ((Locale)obj).baseLocale;
45.1903 + if (!baseLocale.equals(otherBase)) {
45.1904 + return false;
45.1905 + }
45.1906 + if (localeExtensions == null) {
45.1907 + return ((Locale)obj).localeExtensions == null;
45.1908 + }
45.1909 + return localeExtensions.equals(((Locale)obj).localeExtensions);
45.1910 + }
45.1911 +
45.1912 + // ================= privates =====================================
45.1913 +
45.1914 + private transient BaseLocale baseLocale;
45.1915 + private transient LocaleExtensions localeExtensions;
45.1916 +
45.1917 + /**
45.1918 + * Calculated hashcode
45.1919 + */
45.1920 + private transient volatile int hashCodeValue = 0;
45.1921 +
45.1922 + private static Locale defaultLocale = null;
45.1923 + private static Locale defaultDisplayLocale = null;
45.1924 + private static Locale defaultFormatLocale = null;
45.1925 +
45.1926 + /**
45.1927 + * Return an array of the display names of the variant.
45.1928 + * @param bundle the ResourceBundle to use to get the display names
45.1929 + * @return an array of display names, possible of zero length.
45.1930 + */
45.1931 + private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) {
45.1932 + // Split the variant name into tokens separated by '_'.
45.1933 + StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
45.1934 + String[] names = new String[tokenizer.countTokens()];
45.1935 +
45.1936 + // For each variant token, lookup the display name. If
45.1937 + // not found, use the variant name itself.
45.1938 + for (int i=0; i<names.length; ++i) {
45.1939 + names[i] = getDisplayString(tokenizer.nextToken(),
45.1940 + inLocale, DISPLAY_VARIANT);
45.1941 + }
45.1942 +
45.1943 + return names;
45.1944 + }
45.1945 +
45.1946 + /**
45.1947 + * Format a list using given pattern strings.
45.1948 + * If either of the patterns is null, then a the list is
45.1949 + * formatted by concatenation with the delimiter ','.
45.1950 + * @param stringList the list of strings to be formatted.
45.1951 + * @param listPattern should create a MessageFormat taking 0-3 arguments
45.1952 + * and formatting them into a list.
45.1953 + * @param listCompositionPattern should take 2 arguments
45.1954 + * and is used by composeList.
45.1955 + * @return a string representing the list.
45.1956 + */
45.1957 + private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
45.1958 + // If we have no list patterns, compose the list in a simple,
45.1959 + // non-localized way.
45.1960 + if (listPattern == null || listCompositionPattern == null) {
45.1961 + StringBuffer result = new StringBuffer();
45.1962 + for (int i=0; i<stringList.length; ++i) {
45.1963 + if (i>0) result.append(',');
45.1964 + result.append(stringList[i]);
45.1965 + }
45.1966 + return result.toString();
45.1967 + }
45.1968 +
45.1969 + // Compose the list down to three elements if necessary
45.1970 + if (stringList.length > 3) {
45.1971 + MessageFormat format = new MessageFormat(listCompositionPattern);
45.1972 + stringList = composeList(format, stringList);
45.1973 + }
45.1974 +
45.1975 + // Rebuild the argument list with the list length as the first element
45.1976 + Object[] args = new Object[stringList.length + 1];
45.1977 + System.arraycopy(stringList, 0, args, 1, stringList.length);
45.1978 + args[0] = new Integer(stringList.length);
45.1979 +
45.1980 + // Format it using the pattern in the resource
45.1981 + MessageFormat format = new MessageFormat(listPattern);
45.1982 + return format.format(args);
45.1983 + }
45.1984 +
45.1985 + /**
45.1986 + * Given a list of strings, return a list shortened to three elements.
45.1987 + * Shorten it by applying the given format to the first two elements
45.1988 + * recursively.
45.1989 + * @param format a format which takes two arguments
45.1990 + * @param list a list of strings
45.1991 + * @return if the list is three elements or shorter, the same list;
45.1992 + * otherwise, a new list of three elements.
45.1993 + */
45.1994 + private static String[] composeList(MessageFormat format, String[] list) {
45.1995 + if (list.length <= 3) return list;
45.1996 +
45.1997 + // Use the given format to compose the first two elements into one
45.1998 + String[] listItems = { list[0], list[1] };
45.1999 + String newItem = format.format(listItems);
45.2000 +
45.2001 + // Form a new list one element shorter
45.2002 + String[] newList = new String[list.length-1];
45.2003 + System.arraycopy(list, 2, newList, 1, newList.length-1);
45.2004 + newList[0] = newItem;
45.2005 +
45.2006 + // Recurse
45.2007 + return composeList(format, newList);
45.2008 + }
45.2009 +
45.2010 + /**
45.2011 + * @serialField language String
45.2012 + * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
45.2013 + * @serialField country String
45.2014 + * country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
45.2015 + * @serialField variant String
45.2016 + * variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
45.2017 + * @serialField hashcode int
45.2018 + * deprecated, for forward compatibility only
45.2019 + * @serialField script String
45.2020 + * script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
45.2021 + * @serialField extensions String
45.2022 + * canonical representation of extensions, that is,
45.2023 + * BCP47 extensions in alphabetical order followed by
45.2024 + * BCP47 private use subtags, all in lower case letters
45.2025 + * separated by HYPHEN-MINUS characters.
45.2026 + * (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
45.2027 + * <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
45.2028 + */
45.2029 + private static final ObjectStreamField[] serialPersistentFields = {
45.2030 + new ObjectStreamField("language", String.class),
45.2031 + new ObjectStreamField("country", String.class),
45.2032 + new ObjectStreamField("variant", String.class),
45.2033 + new ObjectStreamField("hashcode", int.class),
45.2034 + new ObjectStreamField("script", String.class),
45.2035 + new ObjectStreamField("extensions", String.class),
45.2036 + };
45.2037 +
45.2038 + /**
45.2039 + * Serializes this <code>Locale</code> to the specified <code>ObjectOutputStream</code>.
45.2040 + * @param out the <code>ObjectOutputStream</code> to write
45.2041 + * @throws IOException
45.2042 + * @since 1.7
45.2043 + */
45.2044 + private void writeObject(ObjectOutputStream out) throws IOException {
45.2045 + ObjectOutputStream.PutField fields = out.putFields();
45.2046 + fields.put("language", baseLocale.getLanguage());
45.2047 + fields.put("script", baseLocale.getScript());
45.2048 + fields.put("country", baseLocale.getRegion());
45.2049 + fields.put("variant", baseLocale.getVariant());
45.2050 + fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID());
45.2051 + fields.put("hashcode", -1); // place holder just for backward support
45.2052 + out.writeFields();
45.2053 + }
45.2054 +
45.2055 + /**
45.2056 + * Deserializes this <code>Locale</code>.
45.2057 + * @param in the <code>ObjectInputStream</code> to read
45.2058 + * @throws IOException
45.2059 + * @throws ClassNotFoundException
45.2060 + * @throws IllformdLocaleException
45.2061 + * @since 1.7
45.2062 + */
45.2063 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
45.2064 + ObjectInputStream.GetField fields = in.readFields();
45.2065 + String language = (String)fields.get("language", "");
45.2066 + String script = (String)fields.get("script", "");
45.2067 + String country = (String)fields.get("country", "");
45.2068 + String variant = (String)fields.get("variant", "");
45.2069 + String extStr = (String)fields.get("extensions", "");
45.2070 + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
45.2071 + if (extStr.length() > 0) {
45.2072 + try {
45.2073 + InternalLocaleBuilder bldr = new InternalLocaleBuilder();
45.2074 + bldr.setExtensions(extStr);
45.2075 + localeExtensions = bldr.getLocaleExtensions();
45.2076 + } catch (LocaleSyntaxException e) {
45.2077 + throw new IllformedLocaleException(e.getMessage());
45.2078 + }
45.2079 + } else {
45.2080 + localeExtensions = null;
45.2081 + }
45.2082 + }
45.2083 +
45.2084 + /**
45.2085 + * Returns a cached <code>Locale</code> instance equivalent to
45.2086 + * the deserialized <code>Locale</code>. When serialized
45.2087 + * language, country and variant fields read from the object data stream
45.2088 + * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
45.2089 + * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
45.2090 + * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
45.2091 + * type is "thai"). See <a href="Locale.html#special_cases_constructor"/>Special Cases</a>
45.2092 + * for more information.
45.2093 + *
45.2094 + * @return an instance of <code>Locale</code> equivalent to
45.2095 + * the deserialized <code>Locale</code>.
45.2096 + * @throws java.io.ObjectStreamException
45.2097 + */
45.2098 + private Object readResolve() throws java.io.ObjectStreamException {
45.2099 + return getInstance(baseLocale.getLanguage(), baseLocale.getScript(),
45.2100 + baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
45.2101 + }
45.2102 +
45.2103 + private static volatile String[] isoLanguages = null;
45.2104 +
45.2105 + private static volatile String[] isoCountries = null;
45.2106 +
45.2107 + private static String convertOldISOCodes(String language) {
45.2108 + // we accept both the old and the new ISO codes for the languages whose ISO
45.2109 + // codes have changed, but we always store the OLD code, for backward compatibility
45.2110 + language = LocaleUtils.toLowerString(language).intern();
45.2111 + if (language == "he") {
45.2112 + return "iw";
45.2113 + } else if (language == "yi") {
45.2114 + return "ji";
45.2115 + } else if (language == "id") {
45.2116 + return "in";
45.2117 + } else {
45.2118 + return language;
45.2119 + }
45.2120 + }
45.2121 +
45.2122 + private static LocaleExtensions getCompatibilityExtensions(String language,
45.2123 + String script,
45.2124 + String country,
45.2125 + String variant) {
45.2126 + LocaleExtensions extensions = null;
45.2127 + // Special cases for backward compatibility support
45.2128 + if (LocaleUtils.caseIgnoreMatch(language, "ja")
45.2129 + && script.length() == 0
45.2130 + && LocaleUtils.caseIgnoreMatch(country, "jp")
45.2131 + && "JP".equals(variant)) {
45.2132 + // ja_JP_JP -> u-ca-japanese (calendar = japanese)
45.2133 + extensions = LocaleExtensions.CALENDAR_JAPANESE;
45.2134 + } else if (LocaleUtils.caseIgnoreMatch(language, "th")
45.2135 + && script.length() == 0
45.2136 + && LocaleUtils.caseIgnoreMatch(country, "th")
45.2137 + && "TH".equals(variant)) {
45.2138 + // th_TH_TH -> u-nu-thai (numbersystem = thai)
45.2139 + extensions = LocaleExtensions.NUMBER_THAI;
45.2140 + }
45.2141 + return extensions;
45.2142 + }
45.2143 +
45.2144 + /**
45.2145 + * Obtains a localized locale names from a LocaleNameProvider
45.2146 + * implementation.
45.2147 + */
45.2148 + private static class LocaleNameGetter
45.2149 + implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
45.2150 + private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
45.2151 +
45.2152 + public String getObject(LocaleNameProvider localeNameProvider,
45.2153 + Locale locale,
45.2154 + String key,
45.2155 + Object... params) {
45.2156 + assert params.length == 2;
45.2157 + int type = (Integer)params[0];
45.2158 + String code = (String)params[1];
45.2159 +
45.2160 + switch(type) {
45.2161 + case DISPLAY_LANGUAGE:
45.2162 + return localeNameProvider.getDisplayLanguage(code, locale);
45.2163 + case DISPLAY_COUNTRY:
45.2164 + return localeNameProvider.getDisplayCountry(code, locale);
45.2165 + case DISPLAY_VARIANT:
45.2166 + return localeNameProvider.getDisplayVariant(code, locale);
45.2167 + case DISPLAY_SCRIPT:
45.2168 + return localeNameProvider.getDisplayScript(code, locale);
45.2169 + default:
45.2170 + assert false; // shouldn't happen
45.2171 + }
45.2172 +
45.2173 + return null;
45.2174 + }
45.2175 + }
45.2176 +
45.2177 + /**
45.2178 + * Enum for locale categories. These locale categories are used to get/set
45.2179 + * the default locale for the specific functionality represented by the
45.2180 + * category.
45.2181 + *
45.2182 + * @see #getDefault(Locale.Category)
45.2183 + * @see #setDefault(Locale.Category, Locale)
45.2184 + * @since 1.7
45.2185 + */
45.2186 + public enum Category {
45.2187 +
45.2188 + /**
45.2189 + * Category used to represent the default locale for
45.2190 + * displaying user interfaces.
45.2191 + */
45.2192 + DISPLAY("user.language.display",
45.2193 + "user.script.display",
45.2194 + "user.country.display",
45.2195 + "user.variant.display"),
45.2196 +
45.2197 + /**
45.2198 + * Category used to represent the default locale for
45.2199 + * formatting dates, numbers, and/or currencies.
45.2200 + */
45.2201 + FORMAT("user.language.format",
45.2202 + "user.script.format",
45.2203 + "user.country.format",
45.2204 + "user.variant.format");
45.2205 +
45.2206 + Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
45.2207 + this.languageKey = languageKey;
45.2208 + this.scriptKey = scriptKey;
45.2209 + this.countryKey = countryKey;
45.2210 + this.variantKey = variantKey;
45.2211 + }
45.2212 +
45.2213 + final String languageKey;
45.2214 + final String scriptKey;
45.2215 + final String countryKey;
45.2216 + final String variantKey;
45.2217 + }
45.2218 +
45.2219 + /**
45.2220 + * <code>Builder</code> is used to build instances of <code>Locale</code>
45.2221 + * from values configured by the setters. Unlike the <code>Locale</code>
45.2222 + * constructors, the <code>Builder</code> checks if a value configured by a
45.2223 + * setter satisfies the syntax requirements defined by the <code>Locale</code>
45.2224 + * class. A <code>Locale</code> object created by a <code>Builder</code> is
45.2225 + * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
45.2226 + * without losing information.
45.2227 + *
45.2228 + * <p><b>Note:</b> The <code>Locale</code> class does not provide any
45.2229 + * syntactic restrictions on variant, while BCP 47 requires each variant
45.2230 + * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
45.2231 + * alphanumerics. The method <code>setVariant</code> throws
45.2232 + * <code>IllformedLocaleException</code> for a variant that does not satisfy
45.2233 + * this restriction. If it is necessary to support such a variant, use a
45.2234 + * Locale constructor. However, keep in mind that a <code>Locale</code>
45.2235 + * object created this way might lose the variant information when
45.2236 + * transformed to a BCP 47 language tag.
45.2237 + *
45.2238 + * <p>The following example shows how to create a <code>Locale</code> object
45.2239 + * with the <code>Builder</code>.
45.2240 + * <blockquote>
45.2241 + * <pre>
45.2242 + * Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
45.2243 + * </pre>
45.2244 + * </blockquote>
45.2245 + *
45.2246 + * <p>Builders can be reused; <code>clear()</code> resets all
45.2247 + * fields to their default values.
45.2248 + *
45.2249 + * @see Locale#forLanguageTag
45.2250 + * @since 1.7
45.2251 + */
45.2252 + public static final class Builder {
45.2253 + private final InternalLocaleBuilder localeBuilder;
45.2254 +
45.2255 + /**
45.2256 + * Constructs an empty Builder. The default value of all
45.2257 + * fields, extensions, and private use information is the
45.2258 + * empty string.
45.2259 + */
45.2260 + public Builder() {
45.2261 + localeBuilder = new InternalLocaleBuilder();
45.2262 + }
45.2263 +
45.2264 + /**
45.2265 + * Resets the <code>Builder</code> to match the provided
45.2266 + * <code>locale</code>. Existing state is discarded.
45.2267 + *
45.2268 + * <p>All fields of the locale must be well-formed, see {@link Locale}.
45.2269 + *
45.2270 + * <p>Locales with any ill-formed fields cause
45.2271 + * <code>IllformedLocaleException</code> to be thrown, except for the
45.2272 + * following three cases which are accepted for compatibility
45.2273 + * reasons:<ul>
45.2274 + * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"
45.2275 + * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"
45.2276 + * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>
45.2277 + *
45.2278 + * @param locale the locale
45.2279 + * @return This builder.
45.2280 + * @throws IllformedLocaleException if <code>locale</code> has
45.2281 + * any ill-formed fields.
45.2282 + * @throws NullPointerException if <code>locale</code> is null.
45.2283 + */
45.2284 + public Builder setLocale(Locale locale) {
45.2285 + try {
45.2286 + localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);
45.2287 + } catch (LocaleSyntaxException e) {
45.2288 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2289 + }
45.2290 + return this;
45.2291 + }
45.2292 +
45.2293 + /**
45.2294 + * Resets the Builder to match the provided IETF BCP 47
45.2295 + * language tag. Discards the existing state. Null and the
45.2296 + * empty string cause the builder to be reset, like {@link
45.2297 + * #clear}. Grandfathered tags (see {@link
45.2298 + * Locale#forLanguageTag}) are converted to their canonical
45.2299 + * form before being processed. Otherwise, the language tag
45.2300 + * must be well-formed (see {@link Locale}) or an exception is
45.2301 + * thrown (unlike <code>Locale.forLanguageTag</code>, which
45.2302 + * just discards ill-formed and following portions of the
45.2303 + * tag).
45.2304 + *
45.2305 + * @param languageTag the language tag
45.2306 + * @return This builder.
45.2307 + * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed
45.2308 + * @see Locale#forLanguageTag(String)
45.2309 + */
45.2310 + public Builder setLanguageTag(String languageTag) {
45.2311 + ParseStatus sts = new ParseStatus();
45.2312 + LanguageTag tag = LanguageTag.parse(languageTag, sts);
45.2313 + if (sts.isError()) {
45.2314 + throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
45.2315 + }
45.2316 + localeBuilder.setLanguageTag(tag);
45.2317 + return this;
45.2318 + }
45.2319 +
45.2320 + /**
45.2321 + * Sets the language. If <code>language</code> is the empty string or
45.2322 + * null, the language in this <code>Builder</code> is removed. Otherwise,
45.2323 + * the language must be <a href="./Locale.html#def_language">well-formed</a>
45.2324 + * or an exception is thrown.
45.2325 + *
45.2326 + * <p>The typical language value is a two or three-letter language
45.2327 + * code as defined in ISO639.
45.2328 + *
45.2329 + * @param language the language
45.2330 + * @return This builder.
45.2331 + * @throws IllformedLocaleException if <code>language</code> is ill-formed
45.2332 + */
45.2333 + public Builder setLanguage(String language) {
45.2334 + try {
45.2335 + localeBuilder.setLanguage(language);
45.2336 + } catch (LocaleSyntaxException e) {
45.2337 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2338 + }
45.2339 + return this;
45.2340 + }
45.2341 +
45.2342 + /**
45.2343 + * Sets the script. If <code>script</code> is null or the empty string,
45.2344 + * the script in this <code>Builder</code> is removed.
45.2345 + * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an
45.2346 + * exception is thrown.
45.2347 + *
45.2348 + * <p>The typical script value is a four-letter script code as defined by ISO 15924.
45.2349 + *
45.2350 + * @param script the script
45.2351 + * @return This builder.
45.2352 + * @throws IllformedLocaleException if <code>script</code> is ill-formed
45.2353 + */
45.2354 + public Builder setScript(String script) {
45.2355 + try {
45.2356 + localeBuilder.setScript(script);
45.2357 + } catch (LocaleSyntaxException e) {
45.2358 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2359 + }
45.2360 + return this;
45.2361 + }
45.2362 +
45.2363 + /**
45.2364 + * Sets the region. If region is null or the empty string, the region
45.2365 + * in this <code>Builder</code> is removed. Otherwise,
45.2366 + * the region must be <a href="./Locale.html#def_region">well-formed</a> or an
45.2367 + * exception is thrown.
45.2368 + *
45.2369 + * <p>The typical region value is a two-letter ISO 3166 code or a
45.2370 + * three-digit UN M.49 area code.
45.2371 + *
45.2372 + * <p>The country value in the <code>Locale</code> created by the
45.2373 + * <code>Builder</code> is always normalized to upper case.
45.2374 + *
45.2375 + * @param region the region
45.2376 + * @return This builder.
45.2377 + * @throws IllformedLocaleException if <code>region</code> is ill-formed
45.2378 + */
45.2379 + public Builder setRegion(String region) {
45.2380 + try {
45.2381 + localeBuilder.setRegion(region);
45.2382 + } catch (LocaleSyntaxException e) {
45.2383 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2384 + }
45.2385 + return this;
45.2386 + }
45.2387 +
45.2388 + /**
45.2389 + * Sets the variant. If variant is null or the empty string, the
45.2390 + * variant in this <code>Builder</code> is removed. Otherwise, it
45.2391 + * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>
45.2392 + * subtags, or an exception is thrown.
45.2393 + *
45.2394 + * <p><b>Note:</b> This method checks if <code>variant</code>
45.2395 + * satisfies the IETF BCP 47 variant subtag's syntax requirements,
45.2396 + * and normalizes the value to lowercase letters. However,
45.2397 + * the <code>Locale</code> class does not impose any syntactic
45.2398 + * restriction on variant, and the variant value in
45.2399 + * <code>Locale</code> is case sensitive. To set such a variant,
45.2400 + * use a Locale constructor.
45.2401 + *
45.2402 + * @param variant the variant
45.2403 + * @return This builder.
45.2404 + * @throws IllformedLocaleException if <code>variant</code> is ill-formed
45.2405 + */
45.2406 + public Builder setVariant(String variant) {
45.2407 + try {
45.2408 + localeBuilder.setVariant(variant);
45.2409 + } catch (LocaleSyntaxException e) {
45.2410 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2411 + }
45.2412 + return this;
45.2413 + }
45.2414 +
45.2415 + /**
45.2416 + * Sets the extension for the given key. If the value is null or the
45.2417 + * empty string, the extension is removed. Otherwise, the extension
45.2418 + * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception
45.2419 + * is thrown.
45.2420 + *
45.2421 + * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION
45.2422 + * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
45.2423 + * Setting a value for this key replaces any existing Unicode locale key/type
45.2424 + * pairs with those defined in the extension.
45.2425 + *
45.2426 + * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION
45.2427 + * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
45.2428 + * well-formed, the value for this key needs only to have subtags of one to
45.2429 + * eight alphanumeric characters, not two to eight as in the general case.
45.2430 + *
45.2431 + * @param key the extension key
45.2432 + * @param value the extension value
45.2433 + * @return This builder.
45.2434 + * @throws IllformedLocaleException if <code>key</code> is illegal
45.2435 + * or <code>value</code> is ill-formed
45.2436 + * @see #setUnicodeLocaleKeyword(String, String)
45.2437 + */
45.2438 + public Builder setExtension(char key, String value) {
45.2439 + try {
45.2440 + localeBuilder.setExtension(key, value);
45.2441 + } catch (LocaleSyntaxException e) {
45.2442 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2443 + }
45.2444 + return this;
45.2445 + }
45.2446 +
45.2447 + /**
45.2448 + * Sets the Unicode locale keyword type for the given key. If the type
45.2449 + * is null, the Unicode keyword is removed. Otherwise, the key must be
45.2450 + * non-null and both key and type must be <a
45.2451 + * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
45.2452 + * is thrown.
45.2453 + *
45.2454 + * <p>Keys and types are converted to lower case.
45.2455 + *
45.2456 + * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}
45.2457 + * replaces all Unicode locale keywords with those defined in the
45.2458 + * extension.
45.2459 + *
45.2460 + * @param key the Unicode locale key
45.2461 + * @param type the Unicode locale type
45.2462 + * @return This builder.
45.2463 + * @throws IllformedLocaleException if <code>key</code> or <code>type</code>
45.2464 + * is ill-formed
45.2465 + * @throws NullPointerException if <code>key</code> is null
45.2466 + * @see #setExtension(char, String)
45.2467 + */
45.2468 + public Builder setUnicodeLocaleKeyword(String key, String type) {
45.2469 + try {
45.2470 + localeBuilder.setUnicodeLocaleKeyword(key, type);
45.2471 + } catch (LocaleSyntaxException e) {
45.2472 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2473 + }
45.2474 + return this;
45.2475 + }
45.2476 +
45.2477 + /**
45.2478 + * Adds a unicode locale attribute, if not already present, otherwise
45.2479 + * has no effect. The attribute must not be null and must be <a
45.2480 + * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
45.2481 + * is thrown.
45.2482 + *
45.2483 + * @param attribute the attribute
45.2484 + * @return This builder.
45.2485 + * @throws NullPointerException if <code>attribute</code> is null
45.2486 + * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
45.2487 + * @see #setExtension(char, String)
45.2488 + */
45.2489 + public Builder addUnicodeLocaleAttribute(String attribute) {
45.2490 + try {
45.2491 + localeBuilder.addUnicodeLocaleAttribute(attribute);
45.2492 + } catch (LocaleSyntaxException e) {
45.2493 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2494 + }
45.2495 + return this;
45.2496 + }
45.2497 +
45.2498 + /**
45.2499 + * Removes a unicode locale attribute, if present, otherwise has no
45.2500 + * effect. The attribute must not be null and must be <a
45.2501 + * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
45.2502 + * is thrown.
45.2503 + *
45.2504 + * <p>Attribute comparision for removal is case-insensitive.
45.2505 + *
45.2506 + * @param attribute the attribute
45.2507 + * @return This builder.
45.2508 + * @throws NullPointerException if <code>attribute</code> is null
45.2509 + * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
45.2510 + * @see #setExtension(char, String)
45.2511 + */
45.2512 + public Builder removeUnicodeLocaleAttribute(String attribute) {
45.2513 + try {
45.2514 + localeBuilder.removeUnicodeLocaleAttribute(attribute);
45.2515 + } catch (LocaleSyntaxException e) {
45.2516 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
45.2517 + }
45.2518 + return this;
45.2519 + }
45.2520 +
45.2521 + /**
45.2522 + * Resets the builder to its initial, empty state.
45.2523 + *
45.2524 + * @return This builder.
45.2525 + */
45.2526 + public Builder clear() {
45.2527 + localeBuilder.clear();
45.2528 + return this;
45.2529 + }
45.2530 +
45.2531 + /**
45.2532 + * Resets the extensions to their initial, empty state.
45.2533 + * Language, script, region and variant are unchanged.
45.2534 + *
45.2535 + * @return This builder.
45.2536 + * @see #setExtension(char, String)
45.2537 + */
45.2538 + public Builder clearExtensions() {
45.2539 + localeBuilder.clearExtensions();
45.2540 + return this;
45.2541 + }
45.2542 +
45.2543 + /**
45.2544 + * Returns an instance of <code>Locale</code> created from the fields set
45.2545 + * on this builder.
45.2546 + *
45.2547 + * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
45.2548 + * when constructing a Locale. (Grandfathered tags are handled in
45.2549 + * {@link #setLanguageTag}.)
45.2550 + *
45.2551 + * @return A Locale.
45.2552 + */
45.2553 + public Locale build() {
45.2554 + BaseLocale baseloc = localeBuilder.getBaseLocale();
45.2555 + LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
45.2556 + if (extensions == null && baseloc.getVariant().length() > 0) {
45.2557 + extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
45.2558 + baseloc.getRegion(), baseloc.getVariant());
45.2559 + }
45.2560 + return Locale.getInstance(baseloc, extensions);
45.2561 + }
45.2562 + }
45.2563 +}
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/rt/emul/compact/src/main/java/java/util/MissingResourceException.java Thu Oct 03 15:43:10 2013 +0200
46.3 @@ -0,0 +1,124 @@
46.4 +/*
46.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
46.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
46.7 + *
46.8 + * This code is free software; you can redistribute it and/or modify it
46.9 + * under the terms of the GNU General Public License version 2 only, as
46.10 + * published by the Free Software Foundation. Oracle designates this
46.11 + * particular file as subject to the "Classpath" exception as provided
46.12 + * by Oracle in the LICENSE file that accompanied this code.
46.13 + *
46.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
46.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
46.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
46.17 + * version 2 for more details (a copy is included in the LICENSE file that
46.18 + * accompanied this code).
46.19 + *
46.20 + * You should have received a copy of the GNU General Public License version
46.21 + * 2 along with this work; if not, write to the Free Software Foundation,
46.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
46.23 + *
46.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
46.25 + * or visit www.oracle.com if you need additional information or have any
46.26 + * questions.
46.27 + */
46.28 +
46.29 +/*
46.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
46.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
46.32 + *
46.33 + * The original version of this source code and documentation
46.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
46.35 + * subsidiary of IBM. These materials are provided under terms
46.36 + * of a License Agreement between Taligent and Sun. This technology
46.37 + * is protected by multiple US and International patents.
46.38 + *
46.39 + * This notice and attribution to Taligent may not be removed.
46.40 + * Taligent is a registered trademark of Taligent, Inc.
46.41 + *
46.42 + */
46.43 +
46.44 +package java.util;
46.45 +
46.46 +/**
46.47 + * Signals that a resource is missing.
46.48 + * @see java.lang.Exception
46.49 + * @see ResourceBundle
46.50 + * @author Mark Davis
46.51 + * @since JDK1.1
46.52 + */
46.53 +public
46.54 +class MissingResourceException extends RuntimeException {
46.55 +
46.56 + /**
46.57 + * Constructs a MissingResourceException with the specified information.
46.58 + * A detail message is a String that describes this particular exception.
46.59 + * @param s the detail message
46.60 + * @param className the name of the resource class
46.61 + * @param key the key for the missing resource.
46.62 + */
46.63 + public MissingResourceException(String s, String className, String key) {
46.64 + super(s);
46.65 + this.className = className;
46.66 + this.key = key;
46.67 + }
46.68 +
46.69 + /**
46.70 + * Constructs a <code>MissingResourceException</code> with
46.71 + * <code>message</code>, <code>className</code>, <code>key</code>,
46.72 + * and <code>cause</code>. This constructor is package private for
46.73 + * use by <code>ResourceBundle.getBundle</code>.
46.74 + *
46.75 + * @param message
46.76 + * the detail message
46.77 + * @param className
46.78 + * the name of the resource class
46.79 + * @param key
46.80 + * the key for the missing resource.
46.81 + * @param cause
46.82 + * the cause (which is saved for later retrieval by the
46.83 + * {@link Throwable.getCause()} method). (A null value is
46.84 + * permitted, and indicates that the cause is nonexistent
46.85 + * or unknown.)
46.86 + */
46.87 + MissingResourceException(String message, String className, String key, Throwable cause) {
46.88 + super(message, cause);
46.89 + this.className = className;
46.90 + this.key = key;
46.91 + }
46.92 +
46.93 + /**
46.94 + * Gets parameter passed by constructor.
46.95 + *
46.96 + * @return the name of the resource class
46.97 + */
46.98 + public String getClassName() {
46.99 + return className;
46.100 + }
46.101 +
46.102 + /**
46.103 + * Gets parameter passed by constructor.
46.104 + *
46.105 + * @return the key for the missing resource
46.106 + */
46.107 + public String getKey() {
46.108 + return key;
46.109 + }
46.110 +
46.111 + //============ privates ============
46.112 +
46.113 + // serialization compatibility with JDK1.1
46.114 + private static final long serialVersionUID = -4876345176062000401L;
46.115 +
46.116 + /**
46.117 + * The class name of the resource bundle requested by the user.
46.118 + * @serial
46.119 + */
46.120 + private String className;
46.121 +
46.122 + /**
46.123 + * The name of the specific resource requested by the user.
46.124 + * @serial
46.125 + */
46.126 + private String key;
46.127 +}
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/rt/emul/compact/src/main/java/java/util/Properties.java Thu Oct 03 15:43:10 2013 +0200
47.3 @@ -0,0 +1,1114 @@
47.4 +/*
47.5 + * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
47.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
47.7 + *
47.8 + * This code is free software; you can redistribute it and/or modify it
47.9 + * under the terms of the GNU General Public License version 2 only, as
47.10 + * published by the Free Software Foundation. Oracle designates this
47.11 + * particular file as subject to the "Classpath" exception as provided
47.12 + * by Oracle in the LICENSE file that accompanied this code.
47.13 + *
47.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
47.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
47.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
47.17 + * version 2 for more details (a copy is included in the LICENSE file that
47.18 + * accompanied this code).
47.19 + *
47.20 + * You should have received a copy of the GNU General Public License version
47.21 + * 2 along with this work; if not, write to the Free Software Foundation,
47.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
47.23 + *
47.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
47.25 + * or visit www.oracle.com if you need additional information or have any
47.26 + * questions.
47.27 + */
47.28 +
47.29 +package java.util;
47.30 +
47.31 +import java.io.IOException;
47.32 +import java.io.PrintStream;
47.33 +import java.io.PrintWriter;
47.34 +import java.io.InputStream;
47.35 +import java.io.OutputStream;
47.36 +import java.io.Reader;
47.37 +import java.io.Writer;
47.38 +import java.io.OutputStreamWriter;
47.39 +import java.io.BufferedWriter;
47.40 +
47.41 +/**
47.42 + * The <code>Properties</code> class represents a persistent set of
47.43 + * properties. The <code>Properties</code> can be saved to a stream
47.44 + * or loaded from a stream. Each key and its corresponding value in
47.45 + * the property list is a string.
47.46 + * <p>
47.47 + * A property list can contain another property list as its
47.48 + * "defaults"; this second property list is searched if
47.49 + * the property key is not found in the original property list.
47.50 + * <p>
47.51 + * Because <code>Properties</code> inherits from <code>Hashtable</code>, the
47.52 + * <code>put</code> and <code>putAll</code> methods can be applied to a
47.53 + * <code>Properties</code> object. Their use is strongly discouraged as they
47.54 + * allow the caller to insert entries whose keys or values are not
47.55 + * <code>Strings</code>. The <code>setProperty</code> method should be used
47.56 + * instead. If the <code>store</code> or <code>save</code> method is called
47.57 + * on a "compromised" <code>Properties</code> object that contains a
47.58 + * non-<code>String</code> key or value, the call will fail. Similarly,
47.59 + * the call to the <code>propertyNames</code> or <code>list</code> method
47.60 + * will fail if it is called on a "compromised" <code>Properties</code>
47.61 + * object that contains a non-<code>String</code> key.
47.62 + *
47.63 + * <p>
47.64 + * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
47.65 + * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
47.66 + * methods load and store properties from and to a character based stream
47.67 + * in a simple line-oriented format specified below.
47.68 + *
47.69 + * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
47.70 + * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
47.71 + * methods work the same way as the load(Reader)/store(Writer, String) pair, except
47.72 + * the input/output stream is encoded in ISO 8859-1 character encoding.
47.73 + * Characters that cannot be directly represented in this encoding can be written using
47.74 + * Unicode escapes as defined in section 3.3 of
47.75 + * <cite>The Java™ Language Specification</cite>;
47.76 + * only a single 'u' character is allowed in an escape
47.77 + * sequence. The native2ascii tool can be used to convert property files to and
47.78 + * from other character encodings.
47.79 + *
47.80 + * <p> The {@link #loadFromXML(InputStream)} and {@link
47.81 + * #storeToXML(OutputStream, String, String)} methods load and store properties
47.82 + * in a simple XML format. By default the UTF-8 character encoding is used,
47.83 + * however a specific encoding may be specified if required. An XML properties
47.84 + * document has the following DOCTYPE declaration:
47.85 + *
47.86 + * <pre>
47.87 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
47.88 + * </pre>
47.89 + * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
47.90 + * <i>not</i> accessed when exporting or importing properties; it merely
47.91 + * serves as a string to uniquely identify the DTD, which is:
47.92 + * <pre>
47.93 + * <?xml version="1.0" encoding="UTF-8"?>
47.94 + *
47.95 + * <!-- DTD for properties -->
47.96 + *
47.97 + * <!ELEMENT properties ( comment?, entry* ) >
47.98 + *
47.99 + * <!ATTLIST properties version CDATA #FIXED "1.0">
47.100 + *
47.101 + * <!ELEMENT comment (#PCDATA) >
47.102 + *
47.103 + * <!ELEMENT entry (#PCDATA) >
47.104 + *
47.105 + * <!ATTLIST entry key CDATA #REQUIRED>
47.106 + * </pre>
47.107 + *
47.108 + * <p>This class is thread-safe: multiple threads can share a single
47.109 + * <tt>Properties</tt> object without the need for external synchronization.
47.110 + *
47.111 + * @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
47.112 + * @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
47.113 + *
47.114 + * @author Arthur van Hoff
47.115 + * @author Michael McCloskey
47.116 + * @author Xueming Shen
47.117 + * @since JDK1.0
47.118 + */
47.119 +public
47.120 +class Properties extends Hashtable<Object,Object> {
47.121 + /**
47.122 + * use serialVersionUID from JDK 1.1.X for interoperability
47.123 + */
47.124 + private static final long serialVersionUID = 4112578634029874840L;
47.125 +
47.126 + /**
47.127 + * A property list that contains default values for any keys not
47.128 + * found in this property list.
47.129 + *
47.130 + * @serial
47.131 + */
47.132 + protected Properties defaults;
47.133 +
47.134 + /**
47.135 + * Creates an empty property list with no default values.
47.136 + */
47.137 + public Properties() {
47.138 + this(null);
47.139 + }
47.140 +
47.141 + /**
47.142 + * Creates an empty property list with the specified defaults.
47.143 + *
47.144 + * @param defaults the defaults.
47.145 + */
47.146 + public Properties(Properties defaults) {
47.147 + this.defaults = defaults;
47.148 + }
47.149 +
47.150 + /**
47.151 + * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
47.152 + * parallelism with the <tt>getProperty</tt> method. Enforces use of
47.153 + * strings for property keys and values. The value returned is the
47.154 + * result of the <tt>Hashtable</tt> call to <code>put</code>.
47.155 + *
47.156 + * @param key the key to be placed into this property list.
47.157 + * @param value the value corresponding to <tt>key</tt>.
47.158 + * @return the previous value of the specified key in this property
47.159 + * list, or <code>null</code> if it did not have one.
47.160 + * @see #getProperty
47.161 + * @since 1.2
47.162 + */
47.163 + public synchronized Object setProperty(String key, String value) {
47.164 + return put(key, value);
47.165 + }
47.166 +
47.167 +
47.168 + /**
47.169 + * Reads a property list (key and element pairs) from the input
47.170 + * character stream in a simple line-oriented format.
47.171 + * <p>
47.172 + * Properties are processed in terms of lines. There are two
47.173 + * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
47.174 + * A natural line is defined as a line of
47.175 + * characters that is terminated either by a set of line terminator
47.176 + * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>)
47.177 + * or by the end of the stream. A natural line may be either a blank line,
47.178 + * a comment line, or hold all or some of a key-element pair. A logical
47.179 + * line holds all the data of a key-element pair, which may be spread
47.180 + * out across several adjacent natural lines by escaping
47.181 + * the line terminator sequence with a backslash character
47.182 + * <code>\</code>. Note that a comment line cannot be extended
47.183 + * in this manner; every natural line that is a comment must have
47.184 + * its own comment indicator, as described below. Lines are read from
47.185 + * input until the end of the stream is reached.
47.186 + *
47.187 + * <p>
47.188 + * A natural line that contains only white space characters is
47.189 + * considered blank and is ignored. A comment line has an ASCII
47.190 + * <code>'#'</code> or <code>'!'</code> as its first non-white
47.191 + * space character; comment lines are also ignored and do not
47.192 + * encode key-element information. In addition to line
47.193 + * terminators, this format considers the characters space
47.194 + * (<code>' '</code>, <code>'\u0020'</code>), tab
47.195 + * (<code>'\t'</code>, <code>'\u0009'</code>), and form feed
47.196 + * (<code>'\f'</code>, <code>'\u000C'</code>) to be white
47.197 + * space.
47.198 + *
47.199 + * <p>
47.200 + * If a logical line is spread across several natural lines, the
47.201 + * backslash escaping the line terminator sequence, the line
47.202 + * terminator sequence, and any white space at the start of the
47.203 + * following line have no affect on the key or element values.
47.204 + * The remainder of the discussion of key and element parsing
47.205 + * (when loading) will assume all the characters constituting
47.206 + * the key and element appear on a single natural line after
47.207 + * line continuation characters have been removed. Note that
47.208 + * it is <i>not</i> sufficient to only examine the character
47.209 + * preceding a line terminator sequence to decide if the line
47.210 + * terminator is escaped; there must be an odd number of
47.211 + * contiguous backslashes for the line terminator to be escaped.
47.212 + * Since the input is processed from left to right, a
47.213 + * non-zero even number of 2<i>n</i> contiguous backslashes
47.214 + * before a line terminator (or elsewhere) encodes <i>n</i>
47.215 + * backslashes after escape processing.
47.216 + *
47.217 + * <p>
47.218 + * The key contains all of the characters in the line starting
47.219 + * with the first non-white space character and up to, but not
47.220 + * including, the first unescaped <code>'='</code>,
47.221 + * <code>':'</code>, or white space character other than a line
47.222 + * terminator. All of these key termination characters may be
47.223 + * included in the key by escaping them with a preceding backslash
47.224 + * character; for example,<p>
47.225 + *
47.226 + * <code>\:\=</code><p>
47.227 + *
47.228 + * would be the two-character key <code>":="</code>. Line
47.229 + * terminator characters can be included using <code>\r</code> and
47.230 + * <code>\n</code> escape sequences. Any white space after the
47.231 + * key is skipped; if the first non-white space character after
47.232 + * the key is <code>'='</code> or <code>':'</code>, then it is
47.233 + * ignored and any white space characters after it are also
47.234 + * skipped. All remaining characters on the line become part of
47.235 + * the associated element string; if there are no remaining
47.236 + * characters, the element is the empty string
47.237 + * <code>""</code>. Once the raw character sequences
47.238 + * constituting the key and element are identified, escape
47.239 + * processing is performed as described above.
47.240 + *
47.241 + * <p>
47.242 + * As an example, each of the following three lines specifies the key
47.243 + * <code>"Truth"</code> and the associated element value
47.244 + * <code>"Beauty"</code>:
47.245 + * <p>
47.246 + * <pre>
47.247 + * Truth = Beauty
47.248 + * Truth:Beauty
47.249 + * Truth :Beauty
47.250 + * </pre>
47.251 + * As another example, the following three lines specify a single
47.252 + * property:
47.253 + * <p>
47.254 + * <pre>
47.255 + * fruits apple, banana, pear, \
47.256 + * cantaloupe, watermelon, \
47.257 + * kiwi, mango
47.258 + * </pre>
47.259 + * The key is <code>"fruits"</code> and the associated element is:
47.260 + * <p>
47.261 + * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
47.262 + * Note that a space appears before each <code>\</code> so that a space
47.263 + * will appear after each comma in the final result; the <code>\</code>,
47.264 + * line terminator, and leading white space on the continuation line are
47.265 + * merely discarded and are <i>not</i> replaced by one or more other
47.266 + * characters.
47.267 + * <p>
47.268 + * As a third example, the line:
47.269 + * <p>
47.270 + * <pre>cheeses
47.271 + * </pre>
47.272 + * specifies that the key is <code>"cheeses"</code> and the associated
47.273 + * element is the empty string <code>""</code>.<p>
47.274 + * <p>
47.275 + *
47.276 + * <a name="unicodeescapes"></a>
47.277 + * Characters in keys and elements can be represented in escape
47.278 + * sequences similar to those used for character and string literals
47.279 + * (see sections 3.3 and 3.10.6 of
47.280 + * <cite>The Java™ Language Specification</cite>).
47.281 + *
47.282 + * The differences from the character escape sequences and Unicode
47.283 + * escapes used for characters and strings are:
47.284 + *
47.285 + * <ul>
47.286 + * <li> Octal escapes are not recognized.
47.287 + *
47.288 + * <li> The character sequence <code>\b</code> does <i>not</i>
47.289 + * represent a backspace character.
47.290 + *
47.291 + * <li> The method does not treat a backslash character,
47.292 + * <code>\</code>, before a non-valid escape character as an
47.293 + * error; the backslash is silently dropped. For example, in a
47.294 + * Java string the sequence <code>"\z"</code> would cause a
47.295 + * compile time error. In contrast, this method silently drops
47.296 + * the backslash. Therefore, this method treats the two character
47.297 + * sequence <code>"\b"</code> as equivalent to the single
47.298 + * character <code>'b'</code>.
47.299 + *
47.300 + * <li> Escapes are not necessary for single and double quotes;
47.301 + * however, by the rule above, single and double quote characters
47.302 + * preceded by a backslash still yield single and double quote
47.303 + * characters, respectively.
47.304 + *
47.305 + * <li> Only a single 'u' character is allowed in a Uniocde escape
47.306 + * sequence.
47.307 + *
47.308 + * </ul>
47.309 + * <p>
47.310 + * The specified stream remains open after this method returns.
47.311 + *
47.312 + * @param reader the input character stream.
47.313 + * @throws IOException if an error occurred when reading from the
47.314 + * input stream.
47.315 + * @throws IllegalArgumentException if a malformed Unicode escape
47.316 + * appears in the input.
47.317 + * @since 1.6
47.318 + */
47.319 + public synchronized void load(Reader reader) throws IOException {
47.320 + load0(new LineReader(reader));
47.321 + }
47.322 +
47.323 + /**
47.324 + * Reads a property list (key and element pairs) from the input
47.325 + * byte stream. The input stream is in a simple line-oriented
47.326 + * format as specified in
47.327 + * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
47.328 + * the ISO 8859-1 character encoding; that is each byte is one Latin1
47.329 + * character. Characters not in Latin1, and certain special characters,
47.330 + * are represented in keys and elements using Unicode escapes as defined in
47.331 + * section 3.3 of
47.332 + * <cite>The Java™ Language Specification</cite>.
47.333 + * <p>
47.334 + * The specified stream remains open after this method returns.
47.335 + *
47.336 + * @param inStream the input stream.
47.337 + * @exception IOException if an error occurred when reading from the
47.338 + * input stream.
47.339 + * @throws IllegalArgumentException if the input stream contains a
47.340 + * malformed Unicode escape sequence.
47.341 + * @since 1.2
47.342 + */
47.343 + public synchronized void load(InputStream inStream) throws IOException {
47.344 + load0(new LineReader(inStream));
47.345 + }
47.346 +
47.347 + private void load0 (LineReader lr) throws IOException {
47.348 + char[] convtBuf = new char[1024];
47.349 + int limit;
47.350 + int keyLen;
47.351 + int valueStart;
47.352 + char c;
47.353 + boolean hasSep;
47.354 + boolean precedingBackslash;
47.355 +
47.356 + while ((limit = lr.readLine()) >= 0) {
47.357 + c = 0;
47.358 + keyLen = 0;
47.359 + valueStart = limit;
47.360 + hasSep = false;
47.361 +
47.362 + //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
47.363 + precedingBackslash = false;
47.364 + while (keyLen < limit) {
47.365 + c = lr.lineBuf[keyLen];
47.366 + //need check if escaped.
47.367 + if ((c == '=' || c == ':') && !precedingBackslash) {
47.368 + valueStart = keyLen + 1;
47.369 + hasSep = true;
47.370 + break;
47.371 + } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
47.372 + valueStart = keyLen + 1;
47.373 + break;
47.374 + }
47.375 + if (c == '\\') {
47.376 + precedingBackslash = !precedingBackslash;
47.377 + } else {
47.378 + precedingBackslash = false;
47.379 + }
47.380 + keyLen++;
47.381 + }
47.382 + while (valueStart < limit) {
47.383 + c = lr.lineBuf[valueStart];
47.384 + if (c != ' ' && c != '\t' && c != '\f') {
47.385 + if (!hasSep && (c == '=' || c == ':')) {
47.386 + hasSep = true;
47.387 + } else {
47.388 + break;
47.389 + }
47.390 + }
47.391 + valueStart++;
47.392 + }
47.393 + String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
47.394 + String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
47.395 + put(key, value);
47.396 + }
47.397 + }
47.398 +
47.399 + /* Read in a "logical line" from an InputStream/Reader, skip all comment
47.400 + * and blank lines and filter out those leading whitespace characters
47.401 + * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
47.402 + * Method returns the char length of the "logical line" and stores
47.403 + * the line in "lineBuf".
47.404 + */
47.405 + class LineReader {
47.406 + public LineReader(InputStream inStream) {
47.407 + this.inStream = inStream;
47.408 + inByteBuf = new byte[8192];
47.409 + }
47.410 +
47.411 + public LineReader(Reader reader) {
47.412 + this.reader = reader;
47.413 + inCharBuf = new char[8192];
47.414 + }
47.415 +
47.416 + byte[] inByteBuf;
47.417 + char[] inCharBuf;
47.418 + char[] lineBuf = new char[1024];
47.419 + int inLimit = 0;
47.420 + int inOff = 0;
47.421 + InputStream inStream;
47.422 + Reader reader;
47.423 +
47.424 + int readLine() throws IOException {
47.425 + int len = 0;
47.426 + char c = 0;
47.427 +
47.428 + boolean skipWhiteSpace = true;
47.429 + boolean isCommentLine = false;
47.430 + boolean isNewLine = true;
47.431 + boolean appendedLineBegin = false;
47.432 + boolean precedingBackslash = false;
47.433 + boolean skipLF = false;
47.434 +
47.435 + while (true) {
47.436 + if (inOff >= inLimit) {
47.437 + inLimit = (inStream==null)?reader.read(inCharBuf)
47.438 + :inStream.read(inByteBuf);
47.439 + inOff = 0;
47.440 + if (inLimit <= 0) {
47.441 + if (len == 0 || isCommentLine) {
47.442 + return -1;
47.443 + }
47.444 + return len;
47.445 + }
47.446 + }
47.447 + if (inStream != null) {
47.448 + //The line below is equivalent to calling a
47.449 + //ISO8859-1 decoder.
47.450 + c = (char) (0xff & inByteBuf[inOff++]);
47.451 + } else {
47.452 + c = inCharBuf[inOff++];
47.453 + }
47.454 + if (skipLF) {
47.455 + skipLF = false;
47.456 + if (c == '\n') {
47.457 + continue;
47.458 + }
47.459 + }
47.460 + if (skipWhiteSpace) {
47.461 + if (c == ' ' || c == '\t' || c == '\f') {
47.462 + continue;
47.463 + }
47.464 + if (!appendedLineBegin && (c == '\r' || c == '\n')) {
47.465 + continue;
47.466 + }
47.467 + skipWhiteSpace = false;
47.468 + appendedLineBegin = false;
47.469 + }
47.470 + if (isNewLine) {
47.471 + isNewLine = false;
47.472 + if (c == '#' || c == '!') {
47.473 + isCommentLine = true;
47.474 + continue;
47.475 + }
47.476 + }
47.477 +
47.478 + if (c != '\n' && c != '\r') {
47.479 + lineBuf[len++] = c;
47.480 + if (len == lineBuf.length) {
47.481 + int newLength = lineBuf.length * 2;
47.482 + if (newLength < 0) {
47.483 + newLength = Integer.MAX_VALUE;
47.484 + }
47.485 + char[] buf = new char[newLength];
47.486 + System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
47.487 + lineBuf = buf;
47.488 + }
47.489 + //flip the preceding backslash flag
47.490 + if (c == '\\') {
47.491 + precedingBackslash = !precedingBackslash;
47.492 + } else {
47.493 + precedingBackslash = false;
47.494 + }
47.495 + }
47.496 + else {
47.497 + // reached EOL
47.498 + if (isCommentLine || len == 0) {
47.499 + isCommentLine = false;
47.500 + isNewLine = true;
47.501 + skipWhiteSpace = true;
47.502 + len = 0;
47.503 + continue;
47.504 + }
47.505 + if (inOff >= inLimit) {
47.506 + inLimit = (inStream==null)
47.507 + ?reader.read(inCharBuf)
47.508 + :inStream.read(inByteBuf);
47.509 + inOff = 0;
47.510 + if (inLimit <= 0) {
47.511 + return len;
47.512 + }
47.513 + }
47.514 + if (precedingBackslash) {
47.515 + len -= 1;
47.516 + //skip the leading whitespace characters in following line
47.517 + skipWhiteSpace = true;
47.518 + appendedLineBegin = true;
47.519 + precedingBackslash = false;
47.520 + if (c == '\r') {
47.521 + skipLF = true;
47.522 + }
47.523 + } else {
47.524 + return len;
47.525 + }
47.526 + }
47.527 + }
47.528 + }
47.529 + }
47.530 +
47.531 + /*
47.532 + * Converts encoded \uxxxx to unicode chars
47.533 + * and changes special saved chars to their original forms
47.534 + */
47.535 + private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
47.536 + if (convtBuf.length < len) {
47.537 + int newLen = len * 2;
47.538 + if (newLen < 0) {
47.539 + newLen = Integer.MAX_VALUE;
47.540 + }
47.541 + convtBuf = new char[newLen];
47.542 + }
47.543 + char aChar;
47.544 + char[] out = convtBuf;
47.545 + int outLen = 0;
47.546 + int end = off + len;
47.547 +
47.548 + while (off < end) {
47.549 + aChar = in[off++];
47.550 + if (aChar == '\\') {
47.551 + aChar = in[off++];
47.552 + if(aChar == 'u') {
47.553 + // Read the xxxx
47.554 + int value=0;
47.555 + for (int i=0; i<4; i++) {
47.556 + aChar = in[off++];
47.557 + switch (aChar) {
47.558 + case '0': case '1': case '2': case '3': case '4':
47.559 + case '5': case '6': case '7': case '8': case '9':
47.560 + value = (value << 4) + aChar - '0';
47.561 + break;
47.562 + case 'a': case 'b': case 'c':
47.563 + case 'd': case 'e': case 'f':
47.564 + value = (value << 4) + 10 + aChar - 'a';
47.565 + break;
47.566 + case 'A': case 'B': case 'C':
47.567 + case 'D': case 'E': case 'F':
47.568 + value = (value << 4) + 10 + aChar - 'A';
47.569 + break;
47.570 + default:
47.571 + throw new IllegalArgumentException(
47.572 + "Malformed \\uxxxx encoding.");
47.573 + }
47.574 + }
47.575 + out[outLen++] = (char)value;
47.576 + } else {
47.577 + if (aChar == 't') aChar = '\t';
47.578 + else if (aChar == 'r') aChar = '\r';
47.579 + else if (aChar == 'n') aChar = '\n';
47.580 + else if (aChar == 'f') aChar = '\f';
47.581 + out[outLen++] = aChar;
47.582 + }
47.583 + } else {
47.584 + out[outLen++] = aChar;
47.585 + }
47.586 + }
47.587 + return new String (out, 0, outLen);
47.588 + }
47.589 +
47.590 + /*
47.591 + * Converts unicodes to encoded \uxxxx and escapes
47.592 + * special characters with a preceding slash
47.593 + */
47.594 + private String saveConvert(String theString,
47.595 + boolean escapeSpace,
47.596 + boolean escapeUnicode) {
47.597 + int len = theString.length();
47.598 + int bufLen = len * 2;
47.599 + if (bufLen < 0) {
47.600 + bufLen = Integer.MAX_VALUE;
47.601 + }
47.602 + StringBuffer outBuffer = new StringBuffer(bufLen);
47.603 +
47.604 + for(int x=0; x<len; x++) {
47.605 + char aChar = theString.charAt(x);
47.606 + // Handle common case first, selecting largest block that
47.607 + // avoids the specials below
47.608 + if ((aChar > 61) && (aChar < 127)) {
47.609 + if (aChar == '\\') {
47.610 + outBuffer.append('\\'); outBuffer.append('\\');
47.611 + continue;
47.612 + }
47.613 + outBuffer.append(aChar);
47.614 + continue;
47.615 + }
47.616 + switch(aChar) {
47.617 + case ' ':
47.618 + if (x == 0 || escapeSpace)
47.619 + outBuffer.append('\\');
47.620 + outBuffer.append(' ');
47.621 + break;
47.622 + case '\t':outBuffer.append('\\'); outBuffer.append('t');
47.623 + break;
47.624 + case '\n':outBuffer.append('\\'); outBuffer.append('n');
47.625 + break;
47.626 + case '\r':outBuffer.append('\\'); outBuffer.append('r');
47.627 + break;
47.628 + case '\f':outBuffer.append('\\'); outBuffer.append('f');
47.629 + break;
47.630 + case '=': // Fall through
47.631 + case ':': // Fall through
47.632 + case '#': // Fall through
47.633 + case '!':
47.634 + outBuffer.append('\\'); outBuffer.append(aChar);
47.635 + break;
47.636 + default:
47.637 + if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
47.638 + outBuffer.append('\\');
47.639 + outBuffer.append('u');
47.640 + outBuffer.append(toHex((aChar >> 12) & 0xF));
47.641 + outBuffer.append(toHex((aChar >> 8) & 0xF));
47.642 + outBuffer.append(toHex((aChar >> 4) & 0xF));
47.643 + outBuffer.append(toHex( aChar & 0xF));
47.644 + } else {
47.645 + outBuffer.append(aChar);
47.646 + }
47.647 + }
47.648 + }
47.649 + return outBuffer.toString();
47.650 + }
47.651 +
47.652 + private static void writeComments(BufferedWriter bw, String comments)
47.653 + throws IOException {
47.654 + bw.write("#");
47.655 + int len = comments.length();
47.656 + int current = 0;
47.657 + int last = 0;
47.658 + char[] uu = new char[6];
47.659 + uu[0] = '\\';
47.660 + uu[1] = 'u';
47.661 + while (current < len) {
47.662 + char c = comments.charAt(current);
47.663 + if (c > '\u00ff' || c == '\n' || c == '\r') {
47.664 + if (last != current)
47.665 + bw.write(comments.substring(last, current));
47.666 + if (c > '\u00ff') {
47.667 + uu[2] = toHex((c >> 12) & 0xf);
47.668 + uu[3] = toHex((c >> 8) & 0xf);
47.669 + uu[4] = toHex((c >> 4) & 0xf);
47.670 + uu[5] = toHex( c & 0xf);
47.671 + bw.write(new String(uu));
47.672 + } else {
47.673 + bw.newLine();
47.674 + if (c == '\r' &&
47.675 + current != len - 1 &&
47.676 + comments.charAt(current + 1) == '\n') {
47.677 + current++;
47.678 + }
47.679 + if (current == len - 1 ||
47.680 + (comments.charAt(current + 1) != '#' &&
47.681 + comments.charAt(current + 1) != '!'))
47.682 + bw.write("#");
47.683 + }
47.684 + last = current + 1;
47.685 + }
47.686 + current++;
47.687 + }
47.688 + if (last != current)
47.689 + bw.write(comments.substring(last, current));
47.690 + bw.newLine();
47.691 + }
47.692 +
47.693 + /**
47.694 + * Calls the <code>store(OutputStream out, String comments)</code> method
47.695 + * and suppresses IOExceptions that were thrown.
47.696 + *
47.697 + * @deprecated This method does not throw an IOException if an I/O error
47.698 + * occurs while saving the property list. The preferred way to save a
47.699 + * properties list is via the <code>store(OutputStream out,
47.700 + * String comments)</code> method or the
47.701 + * <code>storeToXML(OutputStream os, String comment)</code> method.
47.702 + *
47.703 + * @param out an output stream.
47.704 + * @param comments a description of the property list.
47.705 + * @exception ClassCastException if this <code>Properties</code> object
47.706 + * contains any keys or values that are not
47.707 + * <code>Strings</code>.
47.708 + */
47.709 + @Deprecated
47.710 + public void save(OutputStream out, String comments) {
47.711 + try {
47.712 + store(out, comments);
47.713 + } catch (IOException e) {
47.714 + }
47.715 + }
47.716 +
47.717 + /**
47.718 + * Writes this property list (key and element pairs) in this
47.719 + * <code>Properties</code> table to the output character stream in a
47.720 + * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
47.721 + * method.
47.722 + * <p>
47.723 + * Properties from the defaults table of this <code>Properties</code>
47.724 + * table (if any) are <i>not</i> written out by this method.
47.725 + * <p>
47.726 + * If the comments argument is not null, then an ASCII <code>#</code>
47.727 + * character, the comments string, and a line separator are first written
47.728 + * to the output stream. Thus, the <code>comments</code> can serve as an
47.729 + * identifying comment. Any one of a line feed ('\n'), a carriage
47.730 + * return ('\r'), or a carriage return followed immediately by a line feed
47.731 + * in comments is replaced by a line separator generated by the <code>Writer</code>
47.732 + * and if the next character in comments is not character <code>#</code> or
47.733 + * character <code>!</code> then an ASCII <code>#</code> is written out
47.734 + * after that line separator.
47.735 + * <p>
47.736 + * Next, a comment line is always written, consisting of an ASCII
47.737 + * <code>#</code> character, the current date and time (as if produced
47.738 + * by the <code>toString</code> method of <code>Date</code> for the
47.739 + * current time), and a line separator as generated by the <code>Writer</code>.
47.740 + * <p>
47.741 + * Then every entry in this <code>Properties</code> table is
47.742 + * written out, one per line. For each entry the key string is
47.743 + * written, then an ASCII <code>=</code>, then the associated
47.744 + * element string. For the key, all space characters are
47.745 + * written with a preceding <code>\</code> character. For the
47.746 + * element, leading space characters, but not embedded or trailing
47.747 + * space characters, are written with a preceding <code>\</code>
47.748 + * character. The key and element characters <code>#</code>,
47.749 + * <code>!</code>, <code>=</code>, and <code>:</code> are written
47.750 + * with a preceding backslash to ensure that they are properly loaded.
47.751 + * <p>
47.752 + * After the entries have been written, the output stream is flushed.
47.753 + * The output stream remains open after this method returns.
47.754 + * <p>
47.755 + *
47.756 + * @param writer an output character stream writer.
47.757 + * @param comments a description of the property list.
47.758 + * @exception IOException if writing this property list to the specified
47.759 + * output stream throws an <tt>IOException</tt>.
47.760 + * @exception ClassCastException if this <code>Properties</code> object
47.761 + * contains any keys or values that are not <code>Strings</code>.
47.762 + * @exception NullPointerException if <code>writer</code> is null.
47.763 + * @since 1.6
47.764 + */
47.765 + public void store(Writer writer, String comments)
47.766 + throws IOException
47.767 + {
47.768 + store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
47.769 + : new BufferedWriter(writer),
47.770 + comments,
47.771 + false);
47.772 + }
47.773 +
47.774 + /**
47.775 + * Writes this property list (key and element pairs) in this
47.776 + * <code>Properties</code> table to the output stream in a format suitable
47.777 + * for loading into a <code>Properties</code> table using the
47.778 + * {@link #load(InputStream) load(InputStream)} method.
47.779 + * <p>
47.780 + * Properties from the defaults table of this <code>Properties</code>
47.781 + * table (if any) are <i>not</i> written out by this method.
47.782 + * <p>
47.783 + * This method outputs the comments, properties keys and values in
47.784 + * the same format as specified in
47.785 + * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
47.786 + * with the following differences:
47.787 + * <ul>
47.788 + * <li>The stream is written using the ISO 8859-1 character encoding.
47.789 + *
47.790 + * <li>Characters not in Latin-1 in the comments are written as
47.791 + * <code>\u</code><i>xxxx</i> for their appropriate unicode
47.792 + * hexadecimal value <i>xxxx</i>.
47.793 + *
47.794 + * <li>Characters less than <code>\u0020</code> and characters greater
47.795 + * than <code>\u007E</code> in property keys or values are written
47.796 + * as <code>\u</code><i>xxxx</i> for the appropriate hexadecimal
47.797 + * value <i>xxxx</i>.
47.798 + * </ul>
47.799 + * <p>
47.800 + * After the entries have been written, the output stream is flushed.
47.801 + * The output stream remains open after this method returns.
47.802 + * <p>
47.803 + * @param out an output stream.
47.804 + * @param comments a description of the property list.
47.805 + * @exception IOException if writing this property list to the specified
47.806 + * output stream throws an <tt>IOException</tt>.
47.807 + * @exception ClassCastException if this <code>Properties</code> object
47.808 + * contains any keys or values that are not <code>Strings</code>.
47.809 + * @exception NullPointerException if <code>out</code> is null.
47.810 + * @since 1.2
47.811 + */
47.812 + public void store(OutputStream out, String comments)
47.813 + throws IOException
47.814 + {
47.815 + store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
47.816 + comments,
47.817 + true);
47.818 + }
47.819 +
47.820 + private void store0(BufferedWriter bw, String comments, boolean escUnicode)
47.821 + throws IOException
47.822 + {
47.823 + if (comments != null) {
47.824 + writeComments(bw, comments);
47.825 + }
47.826 + bw.write("#" + new Date().toString());
47.827 + bw.newLine();
47.828 + synchronized (this) {
47.829 + for (Enumeration e = keys(); e.hasMoreElements();) {
47.830 + String key = (String)e.nextElement();
47.831 + String val = (String)get(key);
47.832 + key = saveConvert(key, true, escUnicode);
47.833 + /* No need to escape embedded and trailing spaces for value, hence
47.834 + * pass false to flag.
47.835 + */
47.836 + val = saveConvert(val, false, escUnicode);
47.837 + bw.write(key + "=" + val);
47.838 + bw.newLine();
47.839 + }
47.840 + }
47.841 + bw.flush();
47.842 + }
47.843 +
47.844 + /**
47.845 + * Loads all of the properties represented by the XML document on the
47.846 + * specified input stream into this properties table.
47.847 + *
47.848 + * <p>The XML document must have the following DOCTYPE declaration:
47.849 + * <pre>
47.850 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
47.851 + * </pre>
47.852 + * Furthermore, the document must satisfy the properties DTD described
47.853 + * above.
47.854 + *
47.855 + * <p>The specified stream is closed after this method returns.
47.856 + *
47.857 + * @param in the input stream from which to read the XML document.
47.858 + * @throws IOException if reading from the specified input stream
47.859 + * results in an <tt>IOException</tt>.
47.860 + * @throws InvalidPropertiesFormatException Data on input stream does not
47.861 + * constitute a valid XML document with the mandated document type.
47.862 + * @throws NullPointerException if <code>in</code> is null.
47.863 + * @see #storeToXML(OutputStream, String, String)
47.864 + * @since 1.5
47.865 + */
47.866 + public synchronized void loadFromXML(InputStream in)
47.867 + throws IOException, InvalidPropertiesFormatException
47.868 + {
47.869 + if (in == null)
47.870 + throw new NullPointerException();
47.871 + XMLUtils.load(this, in);
47.872 + in.close();
47.873 + }
47.874 +
47.875 + /**
47.876 + * Emits an XML document representing all of the properties contained
47.877 + * in this table.
47.878 + *
47.879 + * <p> An invocation of this method of the form <tt>props.storeToXML(os,
47.880 + * comment)</tt> behaves in exactly the same way as the invocation
47.881 + * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
47.882 + *
47.883 + * @param os the output stream on which to emit the XML document.
47.884 + * @param comment a description of the property list, or <code>null</code>
47.885 + * if no comment is desired.
47.886 + * @throws IOException if writing to the specified output stream
47.887 + * results in an <tt>IOException</tt>.
47.888 + * @throws NullPointerException if <code>os</code> is null.
47.889 + * @throws ClassCastException if this <code>Properties</code> object
47.890 + * contains any keys or values that are not
47.891 + * <code>Strings</code>.
47.892 + * @see #loadFromXML(InputStream)
47.893 + * @since 1.5
47.894 + */
47.895 + public void storeToXML(OutputStream os, String comment)
47.896 + throws IOException
47.897 + {
47.898 + if (os == null)
47.899 + throw new NullPointerException();
47.900 + storeToXML(os, comment, "UTF-8");
47.901 + }
47.902 +
47.903 + /**
47.904 + * Emits an XML document representing all of the properties contained
47.905 + * in this table, using the specified encoding.
47.906 + *
47.907 + * <p>The XML document will have the following DOCTYPE declaration:
47.908 + * <pre>
47.909 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
47.910 + * </pre>
47.911 + *
47.912 + *<p>If the specified comment is <code>null</code> then no comment
47.913 + * will be stored in the document.
47.914 + *
47.915 + * <p>The specified stream remains open after this method returns.
47.916 + *
47.917 + * @param os the output stream on which to emit the XML document.
47.918 + * @param comment a description of the property list, or <code>null</code>
47.919 + * if no comment is desired.
47.920 + * @param encoding the name of a supported
47.921 + * <a href="../lang/package-summary.html#charenc">
47.922 + * character encoding</a>
47.923 + *
47.924 + * @throws IOException if writing to the specified output stream
47.925 + * results in an <tt>IOException</tt>.
47.926 + * @throws NullPointerException if <code>os</code> is <code>null</code>,
47.927 + * or if <code>encoding</code> is <code>null</code>.
47.928 + * @throws ClassCastException if this <code>Properties</code> object
47.929 + * contains any keys or values that are not
47.930 + * <code>Strings</code>.
47.931 + * @see #loadFromXML(InputStream)
47.932 + * @since 1.5
47.933 + */
47.934 + public void storeToXML(OutputStream os, String comment, String encoding)
47.935 + throws IOException
47.936 + {
47.937 + if (os == null)
47.938 + throw new NullPointerException();
47.939 + XMLUtils.save(this, os, comment, encoding);
47.940 + }
47.941 +
47.942 + /**
47.943 + * Searches for the property with the specified key in this property list.
47.944 + * If the key is not found in this property list, the default property list,
47.945 + * and its defaults, recursively, are then checked. The method returns
47.946 + * <code>null</code> if the property is not found.
47.947 + *
47.948 + * @param key the property key.
47.949 + * @return the value in this property list with the specified key value.
47.950 + * @see #setProperty
47.951 + * @see #defaults
47.952 + */
47.953 + public String getProperty(String key) {
47.954 + Object oval = super.get(key);
47.955 + String sval = (oval instanceof String) ? (String)oval : null;
47.956 + return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
47.957 + }
47.958 +
47.959 + /**
47.960 + * Searches for the property with the specified key in this property list.
47.961 + * If the key is not found in this property list, the default property list,
47.962 + * and its defaults, recursively, are then checked. The method returns the
47.963 + * default value argument if the property is not found.
47.964 + *
47.965 + * @param key the hashtable key.
47.966 + * @param defaultValue a default value.
47.967 + *
47.968 + * @return the value in this property list with the specified key value.
47.969 + * @see #setProperty
47.970 + * @see #defaults
47.971 + */
47.972 + public String getProperty(String key, String defaultValue) {
47.973 + String val = getProperty(key);
47.974 + return (val == null) ? defaultValue : val;
47.975 + }
47.976 +
47.977 + /**
47.978 + * Returns an enumeration of all the keys in this property list,
47.979 + * including distinct keys in the default property list if a key
47.980 + * of the same name has not already been found from the main
47.981 + * properties list.
47.982 + *
47.983 + * @return an enumeration of all the keys in this property list, including
47.984 + * the keys in the default property list.
47.985 + * @throws ClassCastException if any key in this property list
47.986 + * is not a string.
47.987 + * @see java.util.Enumeration
47.988 + * @see java.util.Properties#defaults
47.989 + * @see #stringPropertyNames
47.990 + */
47.991 + public Enumeration<?> propertyNames() {
47.992 + Hashtable h = new Hashtable();
47.993 + enumerate(h);
47.994 + return h.keys();
47.995 + }
47.996 +
47.997 + /**
47.998 + * Returns a set of keys in this property list where
47.999 + * the key and its corresponding value are strings,
47.1000 + * including distinct keys in the default property list if a key
47.1001 + * of the same name has not already been found from the main
47.1002 + * properties list. Properties whose key or value is not
47.1003 + * of type <tt>String</tt> are omitted.
47.1004 + * <p>
47.1005 + * The returned set is not backed by the <tt>Properties</tt> object.
47.1006 + * Changes to this <tt>Properties</tt> are not reflected in the set,
47.1007 + * or vice versa.
47.1008 + *
47.1009 + * @return a set of keys in this property list where
47.1010 + * the key and its corresponding value are strings,
47.1011 + * including the keys in the default property list.
47.1012 + * @see java.util.Properties#defaults
47.1013 + * @since 1.6
47.1014 + */
47.1015 + public Set<String> stringPropertyNames() {
47.1016 + Hashtable<String, String> h = new Hashtable<>();
47.1017 + enumerateStringProperties(h);
47.1018 + return h.keySet();
47.1019 + }
47.1020 +
47.1021 + /**
47.1022 + * Prints this property list out to the specified output stream.
47.1023 + * This method is useful for debugging.
47.1024 + *
47.1025 + * @param out an output stream.
47.1026 + * @throws ClassCastException if any key in this property list
47.1027 + * is not a string.
47.1028 + */
47.1029 + public void list(PrintStream out) {
47.1030 + out.println("-- listing properties --");
47.1031 + Hashtable h = new Hashtable();
47.1032 + enumerate(h);
47.1033 + for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
47.1034 + String key = (String)e.nextElement();
47.1035 + String val = (String)h.get(key);
47.1036 + if (val.length() > 40) {
47.1037 + val = val.substring(0, 37) + "...";
47.1038 + }
47.1039 + out.println(key + "=" + val);
47.1040 + }
47.1041 + }
47.1042 +
47.1043 + /**
47.1044 + * Prints this property list out to the specified output stream.
47.1045 + * This method is useful for debugging.
47.1046 + *
47.1047 + * @param out an output stream.
47.1048 + * @throws ClassCastException if any key in this property list
47.1049 + * is not a string.
47.1050 + * @since JDK1.1
47.1051 + */
47.1052 + /*
47.1053 + * Rather than use an anonymous inner class to share common code, this
47.1054 + * method is duplicated in order to ensure that a non-1.1 compiler can
47.1055 + * compile this file.
47.1056 + */
47.1057 + public void list(PrintWriter out) {
47.1058 + out.println("-- listing properties --");
47.1059 + Hashtable h = new Hashtable();
47.1060 + enumerate(h);
47.1061 + for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
47.1062 + String key = (String)e.nextElement();
47.1063 + String val = (String)h.get(key);
47.1064 + if (val.length() > 40) {
47.1065 + val = val.substring(0, 37) + "...";
47.1066 + }
47.1067 + out.println(key + "=" + val);
47.1068 + }
47.1069 + }
47.1070 +
47.1071 + /**
47.1072 + * Enumerates all key/value pairs in the specified hashtable.
47.1073 + * @param h the hashtable
47.1074 + * @throws ClassCastException if any of the property keys
47.1075 + * is not of String type.
47.1076 + */
47.1077 + private synchronized void enumerate(Hashtable h) {
47.1078 + if (defaults != null) {
47.1079 + defaults.enumerate(h);
47.1080 + }
47.1081 + for (Enumeration e = keys() ; e.hasMoreElements() ;) {
47.1082 + String key = (String)e.nextElement();
47.1083 + h.put(key, get(key));
47.1084 + }
47.1085 + }
47.1086 +
47.1087 + /**
47.1088 + * Enumerates all key/value pairs in the specified hashtable
47.1089 + * and omits the property if the key or value is not a string.
47.1090 + * @param h the hashtable
47.1091 + */
47.1092 + private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
47.1093 + if (defaults != null) {
47.1094 + defaults.enumerateStringProperties(h);
47.1095 + }
47.1096 + for (Enumeration e = keys() ; e.hasMoreElements() ;) {
47.1097 + Object k = e.nextElement();
47.1098 + Object v = get(k);
47.1099 + if (k instanceof String && v instanceof String) {
47.1100 + h.put((String) k, (String) v);
47.1101 + }
47.1102 + }
47.1103 + }
47.1104 +
47.1105 + /**
47.1106 + * Convert a nibble to a hex character
47.1107 + * @param nibble the nibble to convert.
47.1108 + */
47.1109 + private static char toHex(int nibble) {
47.1110 + return hexDigit[(nibble & 0xF)];
47.1111 + }
47.1112 +
47.1113 + /** A table of hex digits */
47.1114 + private static final char[] hexDigit = {
47.1115 + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
47.1116 + };
47.1117 +}
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/rt/emul/compact/src/main/java/java/util/PropertyResourceBundle.java Thu Oct 03 15:43:10 2013 +0200
48.3 @@ -0,0 +1,190 @@
48.4 +/*
48.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
48.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
48.7 + *
48.8 + * This code is free software; you can redistribute it and/or modify it
48.9 + * under the terms of the GNU General Public License version 2 only, as
48.10 + * published by the Free Software Foundation. Oracle designates this
48.11 + * particular file as subject to the "Classpath" exception as provided
48.12 + * by Oracle in the LICENSE file that accompanied this code.
48.13 + *
48.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
48.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
48.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
48.17 + * version 2 for more details (a copy is included in the LICENSE file that
48.18 + * accompanied this code).
48.19 + *
48.20 + * You should have received a copy of the GNU General Public License version
48.21 + * 2 along with this work; if not, write to the Free Software Foundation,
48.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
48.23 + *
48.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
48.25 + * or visit www.oracle.com if you need additional information or have any
48.26 + * questions.
48.27 + */
48.28 +
48.29 +/*
48.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
48.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
48.32 + *
48.33 + * The original version of this source code and documentation
48.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
48.35 + * subsidiary of IBM. These materials are provided under terms
48.36 + * of a License Agreement between Taligent and Sun. This technology
48.37 + * is protected by multiple US and International patents.
48.38 + *
48.39 + * This notice and attribution to Taligent may not be removed.
48.40 + * Taligent is a registered trademark of Taligent, Inc.
48.41 + */
48.42 +
48.43 +package java.util;
48.44 +
48.45 +import java.io.InputStream;
48.46 +import java.io.Reader;
48.47 +import java.io.IOException;
48.48 +import sun.util.ResourceBundleEnumeration;
48.49 +
48.50 +/**
48.51 + * <code>PropertyResourceBundle</code> is a concrete subclass of
48.52 + * <code>ResourceBundle</code> that manages resources for a locale
48.53 + * using a set of static strings from a property file. See
48.54 + * {@link ResourceBundle ResourceBundle} for more information about resource
48.55 + * bundles.
48.56 + *
48.57 + * <p>
48.58 + * Unlike other types of resource bundle, you don't subclass
48.59 + * <code>PropertyResourceBundle</code>. Instead, you supply properties
48.60 + * files containing the resource data. <code>ResourceBundle.getBundle</code>
48.61 + * will automatically look for the appropriate properties file and create a
48.62 + * <code>PropertyResourceBundle</code> that refers to it. See
48.63 + * {@link ResourceBundle#getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) ResourceBundle.getBundle}
48.64 + * for a complete description of the search and instantiation strategy.
48.65 + *
48.66 + * <p>
48.67 + * The following <a name="sample">example</a> shows a member of a resource
48.68 + * bundle family with the base name "MyResources".
48.69 + * The text defines the bundle "MyResources_de",
48.70 + * the German member of the bundle family.
48.71 + * This member is based on <code>PropertyResourceBundle</code>, and the text
48.72 + * therefore is the content of the file "MyResources_de.properties"
48.73 + * (a related <a href="ListResourceBundle.html#sample">example</a> shows
48.74 + * how you can add bundles to this family that are implemented as subclasses
48.75 + * of <code>ListResourceBundle</code>).
48.76 + * The keys in this example are of the form "s1" etc. The actual
48.77 + * keys are entirely up to your choice, so long as they are the same as
48.78 + * the keys you use in your program to retrieve the objects from the bundle.
48.79 + * Keys are case-sensitive.
48.80 + * <blockquote>
48.81 + * <pre>
48.82 + * # MessageFormat pattern
48.83 + * s1=Die Platte \"{1}\" enthält {0}.
48.84 + *
48.85 + * # location of {0} in pattern
48.86 + * s2=1
48.87 + *
48.88 + * # sample disk name
48.89 + * s3=Meine Platte
48.90 + *
48.91 + * # first ChoiceFormat choice
48.92 + * s4=keine Dateien
48.93 + *
48.94 + * # second ChoiceFormat choice
48.95 + * s5=eine Datei
48.96 + *
48.97 + * # third ChoiceFormat choice
48.98 + * s6={0,number} Dateien
48.99 + *
48.100 + * # sample date
48.101 + * s7=3. März 1996
48.102 + * </pre>
48.103 + * </blockquote>
48.104 + *
48.105 + * <p>
48.106 + * <strong>Note:</strong> PropertyResourceBundle can be constructed either
48.107 + * from an InputStream or a Reader, which represents a property file.
48.108 + * Constructing a PropertyResourceBundle instance from an InputStream requires
48.109 + * that the input stream be encoded in ISO-8859-1. In that case, characters
48.110 + * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
48.111 + * as defined in section 3.3 of
48.112 + * <cite>The Java™ Language Specification</cite>
48.113 + * whereas the other constructor which takes a Reader does not have that limitation.
48.114 + *
48.115 + * @see ResourceBundle
48.116 + * @see ListResourceBundle
48.117 + * @see Properties
48.118 + * @since JDK1.1
48.119 + */
48.120 +public class PropertyResourceBundle extends ResourceBundle {
48.121 + /**
48.122 + * Creates a property resource bundle from an {@link java.io.InputStream
48.123 + * InputStream}. The property file read with this constructor
48.124 + * must be encoded in ISO-8859-1.
48.125 + *
48.126 + * @param stream an InputStream that represents a property file
48.127 + * to read from.
48.128 + * @throws IOException if an I/O error occurs
48.129 + * @throws NullPointerException if <code>stream</code> is null
48.130 + */
48.131 + public PropertyResourceBundle (InputStream stream) throws IOException {
48.132 + Properties properties = new Properties();
48.133 + properties.load(stream);
48.134 + lookup = new HashMap(properties);
48.135 + }
48.136 +
48.137 + /**
48.138 + * Creates a property resource bundle from a {@link java.io.Reader
48.139 + * Reader}. Unlike the constructor
48.140 + * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
48.141 + * there is no limitation as to the encoding of the input property file.
48.142 + *
48.143 + * @param reader a Reader that represents a property file to
48.144 + * read from.
48.145 + * @throws IOException if an I/O error occurs
48.146 + * @throws NullPointerException if <code>reader</code> is null
48.147 + * @since 1.6
48.148 + */
48.149 + public PropertyResourceBundle (Reader reader) throws IOException {
48.150 + Properties properties = new Properties();
48.151 + properties.load(reader);
48.152 + lookup = new HashMap(properties);
48.153 + }
48.154 +
48.155 + // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
48.156 + public Object handleGetObject(String key) {
48.157 + if (key == null) {
48.158 + throw new NullPointerException();
48.159 + }
48.160 + return lookup.get(key);
48.161 + }
48.162 +
48.163 + /**
48.164 + * Returns an <code>Enumeration</code> of the keys contained in
48.165 + * this <code>ResourceBundle</code> and its parent bundles.
48.166 + *
48.167 + * @return an <code>Enumeration</code> of the keys contained in
48.168 + * this <code>ResourceBundle</code> and its parent bundles.
48.169 + * @see #keySet()
48.170 + */
48.171 + public Enumeration<String> getKeys() {
48.172 + ResourceBundle parent = this.parent;
48.173 + return new ResourceBundleEnumeration(lookup.keySet(),
48.174 + (parent != null) ? parent.getKeys() : null);
48.175 + }
48.176 +
48.177 + /**
48.178 + * Returns a <code>Set</code> of the keys contained
48.179 + * <em>only</em> in this <code>ResourceBundle</code>.
48.180 + *
48.181 + * @return a <code>Set</code> of the keys contained only in this
48.182 + * <code>ResourceBundle</code>
48.183 + * @since 1.6
48.184 + * @see #keySet()
48.185 + */
48.186 + protected Set<String> handleKeySet() {
48.187 + return lookup.keySet();
48.188 + }
48.189 +
48.190 + // ==================privates====================
48.191 +
48.192 + private Map<String,Object> lookup;
48.193 +}
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/rt/emul/compact/src/main/java/java/util/ResourceBundle.java Thu Oct 03 15:43:10 2013 +0200
49.3 @@ -0,0 +1,2911 @@
49.4 +/*
49.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
49.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
49.7 + *
49.8 + * This code is free software; you can redistribute it and/or modify it
49.9 + * under the terms of the GNU General Public License version 2 only, as
49.10 + * published by the Free Software Foundation. Oracle designates this
49.11 + * particular file as subject to the "Classpath" exception as provided
49.12 + * by Oracle in the LICENSE file that accompanied this code.
49.13 + *
49.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
49.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
49.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
49.17 + * version 2 for more details (a copy is included in the LICENSE file that
49.18 + * accompanied this code).
49.19 + *
49.20 + * You should have received a copy of the GNU General Public License version
49.21 + * 2 along with this work; if not, write to the Free Software Foundation,
49.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
49.23 + *
49.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
49.25 + * or visit www.oracle.com if you need additional information or have any
49.26 + * questions.
49.27 + */
49.28 +
49.29 +/*
49.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
49.31 + * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
49.32 + *
49.33 + * The original version of this source code and documentation
49.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
49.35 + * subsidiary of IBM. These materials are provided under terms
49.36 + * of a License Agreement between Taligent and Sun. This technology
49.37 + * is protected by multiple US and International patents.
49.38 + *
49.39 + * This notice and attribution to Taligent may not be removed.
49.40 + * Taligent is a registered trademark of Taligent, Inc.
49.41 + *
49.42 + */
49.43 +
49.44 +package java.util;
49.45 +
49.46 +import java.io.IOException;
49.47 +import java.io.InputStream;
49.48 +import java.lang.ref.ReferenceQueue;
49.49 +import java.lang.ref.SoftReference;
49.50 +import java.lang.ref.WeakReference;
49.51 +import java.net.JarURLConnection;
49.52 +import java.net.URL;
49.53 +import java.net.URLConnection;
49.54 +import java.security.AccessController;
49.55 +import java.security.PrivilegedAction;
49.56 +import java.security.PrivilegedActionException;
49.57 +import java.security.PrivilegedExceptionAction;
49.58 +import java.util.concurrent.ConcurrentHashMap;
49.59 +import java.util.concurrent.ConcurrentMap;
49.60 +import java.util.jar.JarEntry;
49.61 +
49.62 +import sun.util.locale.BaseLocale;
49.63 +import sun.util.locale.LocaleObjectCache;
49.64 +
49.65 +
49.66 +/**
49.67 + *
49.68 + * Resource bundles contain locale-specific objects. When your program needs a
49.69 + * locale-specific resource, a <code>String</code> for example, your program can
49.70 + * load it from the resource bundle that is appropriate for the current user's
49.71 + * locale. In this way, you can write program code that is largely independent
49.72 + * of the user's locale isolating most, if not all, of the locale-specific
49.73 + * information in resource bundles.
49.74 + *
49.75 + * <p>
49.76 + * This allows you to write programs that can:
49.77 + * <UL type=SQUARE>
49.78 + * <LI> be easily localized, or translated, into different languages
49.79 + * <LI> handle multiple locales at once
49.80 + * <LI> be easily modified later to support even more locales
49.81 + * </UL>
49.82 + *
49.83 + * <P>
49.84 + * Resource bundles belong to families whose members share a common base
49.85 + * name, but whose names also have additional components that identify
49.86 + * their locales. For example, the base name of a family of resource
49.87 + * bundles might be "MyResources". The family should have a default
49.88 + * resource bundle which simply has the same name as its family -
49.89 + * "MyResources" - and will be used as the bundle of last resort if a
49.90 + * specific locale is not supported. The family can then provide as
49.91 + * many locale-specific members as needed, for example a German one
49.92 + * named "MyResources_de".
49.93 + *
49.94 + * <P>
49.95 + * Each resource bundle in a family contains the same items, but the items have
49.96 + * been translated for the locale represented by that resource bundle.
49.97 + * For example, both "MyResources" and "MyResources_de" may have a
49.98 + * <code>String</code> that's used on a button for canceling operations.
49.99 + * In "MyResources" the <code>String</code> may contain "Cancel" and in
49.100 + * "MyResources_de" it may contain "Abbrechen".
49.101 + *
49.102 + * <P>
49.103 + * If there are different resources for different countries, you
49.104 + * can make specializations: for example, "MyResources_de_CH" contains objects for
49.105 + * the German language (de) in Switzerland (CH). If you want to only
49.106 + * modify some of the resources
49.107 + * in the specialization, you can do so.
49.108 + *
49.109 + * <P>
49.110 + * When your program needs a locale-specific object, it loads
49.111 + * the <code>ResourceBundle</code> class using the
49.112 + * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
49.113 + * method:
49.114 + * <blockquote>
49.115 + * <pre>
49.116 + * ResourceBundle myResources =
49.117 + * ResourceBundle.getBundle("MyResources", currentLocale);
49.118 + * </pre>
49.119 + * </blockquote>
49.120 + *
49.121 + * <P>
49.122 + * Resource bundles contain key/value pairs. The keys uniquely
49.123 + * identify a locale-specific object in the bundle. Here's an
49.124 + * example of a <code>ListResourceBundle</code> that contains
49.125 + * two key/value pairs:
49.126 + * <blockquote>
49.127 + * <pre>
49.128 + * public class MyResources extends ListResourceBundle {
49.129 + * protected Object[][] getContents() {
49.130 + * return new Object[][] {
49.131 + * // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
49.132 + * {"OkKey", "OK"},
49.133 + * {"CancelKey", "Cancel"},
49.134 + * // END OF MATERIAL TO LOCALIZE
49.135 + * };
49.136 + * }
49.137 + * }
49.138 + * </pre>
49.139 + * </blockquote>
49.140 + * Keys are always <code>String</code>s.
49.141 + * In this example, the keys are "OkKey" and "CancelKey".
49.142 + * In the above example, the values
49.143 + * are also <code>String</code>s--"OK" and "Cancel"--but
49.144 + * they don't have to be. The values can be any type of object.
49.145 + *
49.146 + * <P>
49.147 + * You retrieve an object from resource bundle using the appropriate
49.148 + * getter method. Because "OkKey" and "CancelKey"
49.149 + * are both strings, you would use <code>getString</code> to retrieve them:
49.150 + * <blockquote>
49.151 + * <pre>
49.152 + * button1 = new Button(myResources.getString("OkKey"));
49.153 + * button2 = new Button(myResources.getString("CancelKey"));
49.154 + * </pre>
49.155 + * </blockquote>
49.156 + * The getter methods all require the key as an argument and return
49.157 + * the object if found. If the object is not found, the getter method
49.158 + * throws a <code>MissingResourceException</code>.
49.159 + *
49.160 + * <P>
49.161 + * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
49.162 + * a method for getting string arrays, <code>getStringArray</code>,
49.163 + * as well as a generic <code>getObject</code> method for any other
49.164 + * type of object. When using <code>getObject</code>, you'll
49.165 + * have to cast the result to the appropriate type. For example:
49.166 + * <blockquote>
49.167 + * <pre>
49.168 + * int[] myIntegers = (int[]) myResources.getObject("intList");
49.169 + * </pre>
49.170 + * </blockquote>
49.171 + *
49.172 + * <P>
49.173 + * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
49.174 + * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
49.175 + * that provide a fairly simple way to create resources.
49.176 + * As you saw briefly in a previous example, <code>ListResourceBundle</code>
49.177 + * manages its resource as a list of key/value pairs.
49.178 + * <code>PropertyResourceBundle</code> uses a properties file to manage
49.179 + * its resources.
49.180 + *
49.181 + * <p>
49.182 + * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
49.183 + * do not suit your needs, you can write your own <code>ResourceBundle</code>
49.184 + * subclass. Your subclasses must override two methods: <code>handleGetObject</code>
49.185 + * and <code>getKeys()</code>.
49.186 + *
49.187 + * <h4>ResourceBundle.Control</h4>
49.188 + *
49.189 + * The {@link ResourceBundle.Control} class provides information necessary
49.190 + * to perform the bundle loading process by the <code>getBundle</code>
49.191 + * factory methods that take a <code>ResourceBundle.Control</code>
49.192 + * instance. You can implement your own subclass in order to enable
49.193 + * non-standard resource bundle formats, change the search strategy, or
49.194 + * define caching parameters. Refer to the descriptions of the class and the
49.195 + * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
49.196 + * factory method for details.
49.197 + *
49.198 + * <h4>Cache Management</h4>
49.199 + *
49.200 + * Resource bundle instances created by the <code>getBundle</code> factory
49.201 + * methods are cached by default, and the factory methods return the same
49.202 + * resource bundle instance multiple times if it has been
49.203 + * cached. <code>getBundle</code> clients may clear the cache, manage the
49.204 + * lifetime of cached resource bundle instances using time-to-live values,
49.205 + * or specify not to cache resource bundle instances. Refer to the
49.206 + * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
49.207 + * Control) <code>getBundle</code> factory method}, {@link
49.208 + * #clearCache(ClassLoader) clearCache}, {@link
49.209 + * Control#getTimeToLive(String, Locale)
49.210 + * ResourceBundle.Control.getTimeToLive}, and {@link
49.211 + * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
49.212 + * long) ResourceBundle.Control.needsReload} for details.
49.213 + *
49.214 + * <h4>Example</h4>
49.215 + *
49.216 + * The following is a very simple example of a <code>ResourceBundle</code>
49.217 + * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
49.218 + * resources you would probably use a <code>Map</code>).
49.219 + * Notice that you don't need to supply a value if
49.220 + * a "parent-level" <code>ResourceBundle</code> handles the same
49.221 + * key with the same value (as for the okKey below).
49.222 + * <blockquote>
49.223 + * <pre>
49.224 + * // default (English language, United States)
49.225 + * public class MyResources extends ResourceBundle {
49.226 + * public Object handleGetObject(String key) {
49.227 + * if (key.equals("okKey")) return "Ok";
49.228 + * if (key.equals("cancelKey")) return "Cancel";
49.229 + * return null;
49.230 + * }
49.231 + *
49.232 + * public Enumeration<String> getKeys() {
49.233 + * return Collections.enumeration(keySet());
49.234 + * }
49.235 + *
49.236 + * // Overrides handleKeySet() so that the getKeys() implementation
49.237 + * // can rely on the keySet() value.
49.238 + * protected Set<String> handleKeySet() {
49.239 + * return new HashSet<String>(Arrays.asList("okKey", "cancelKey"));
49.240 + * }
49.241 + * }
49.242 + *
49.243 + * // German language
49.244 + * public class MyResources_de extends MyResources {
49.245 + * public Object handleGetObject(String key) {
49.246 + * // don't need okKey, since parent level handles it.
49.247 + * if (key.equals("cancelKey")) return "Abbrechen";
49.248 + * return null;
49.249 + * }
49.250 + *
49.251 + * protected Set<String> handleKeySet() {
49.252 + * return new HashSet<String>(Arrays.asList("cancelKey"));
49.253 + * }
49.254 + * }
49.255 + * </pre>
49.256 + * </blockquote>
49.257 + * You do not have to restrict yourself to using a single family of
49.258 + * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
49.259 + * exception messages, <code>ExceptionResources</code>
49.260 + * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
49.261 + * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
49.262 + * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
49.263 + *
49.264 + * @see ListResourceBundle
49.265 + * @see PropertyResourceBundle
49.266 + * @see MissingResourceException
49.267 + * @since JDK1.1
49.268 + */
49.269 +public abstract class ResourceBundle {
49.270 +
49.271 + /** initial size of the bundle cache */
49.272 + private static final int INITIAL_CACHE_SIZE = 32;
49.273 +
49.274 + /** constant indicating that no resource bundle exists */
49.275 + private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
49.276 + public Enumeration<String> getKeys() { return null; }
49.277 + protected Object handleGetObject(String key) { return null; }
49.278 + public String toString() { return "NONEXISTENT_BUNDLE"; }
49.279 + };
49.280 +
49.281 +
49.282 + /**
49.283 + * The cache is a map from cache keys (with bundle base name, locale, and
49.284 + * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
49.285 + * BundleReference.
49.286 + *
49.287 + * The cache is a ConcurrentMap, allowing the cache to be searched
49.288 + * concurrently by multiple threads. This will also allow the cache keys
49.289 + * to be reclaimed along with the ClassLoaders they reference.
49.290 + *
49.291 + * This variable would be better named "cache", but we keep the old
49.292 + * name for compatibility with some workarounds for bug 4212439.
49.293 + */
49.294 + private static final ConcurrentMap<CacheKey, BundleReference> cacheList
49.295 + = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
49.296 +
49.297 + /**
49.298 + * Queue for reference objects referring to class loaders or bundles.
49.299 + */
49.300 + private static final ReferenceQueue referenceQueue = new ReferenceQueue();
49.301 +
49.302 + /**
49.303 + * The parent bundle of this bundle.
49.304 + * The parent bundle is searched by {@link #getObject getObject}
49.305 + * when this bundle does not contain a particular resource.
49.306 + */
49.307 + protected ResourceBundle parent = null;
49.308 +
49.309 + /**
49.310 + * The locale for this bundle.
49.311 + */
49.312 + private Locale locale = null;
49.313 +
49.314 + /**
49.315 + * The base bundle name for this bundle.
49.316 + */
49.317 + private String name;
49.318 +
49.319 + /**
49.320 + * The flag indicating this bundle has expired in the cache.
49.321 + */
49.322 + private volatile boolean expired;
49.323 +
49.324 + /**
49.325 + * The back link to the cache key. null if this bundle isn't in
49.326 + * the cache (yet) or has expired.
49.327 + */
49.328 + private volatile CacheKey cacheKey;
49.329 +
49.330 + /**
49.331 + * A Set of the keys contained only in this ResourceBundle.
49.332 + */
49.333 + private volatile Set<String> keySet;
49.334 +
49.335 + /**
49.336 + * Sole constructor. (For invocation by subclass constructors, typically
49.337 + * implicit.)
49.338 + */
49.339 + public ResourceBundle() {
49.340 + }
49.341 +
49.342 + /**
49.343 + * Gets a string for the given key from this resource bundle or one of its parents.
49.344 + * Calling this method is equivalent to calling
49.345 + * <blockquote>
49.346 + * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
49.347 + * </blockquote>
49.348 + *
49.349 + * @param key the key for the desired string
49.350 + * @exception NullPointerException if <code>key</code> is <code>null</code>
49.351 + * @exception MissingResourceException if no object for the given key can be found
49.352 + * @exception ClassCastException if the object found for the given key is not a string
49.353 + * @return the string for the given key
49.354 + */
49.355 + public final String getString(String key) {
49.356 + return (String) getObject(key);
49.357 + }
49.358 +
49.359 + /**
49.360 + * Gets a string array for the given key from this resource bundle or one of its parents.
49.361 + * Calling this method is equivalent to calling
49.362 + * <blockquote>
49.363 + * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
49.364 + * </blockquote>
49.365 + *
49.366 + * @param key the key for the desired string array
49.367 + * @exception NullPointerException if <code>key</code> is <code>null</code>
49.368 + * @exception MissingResourceException if no object for the given key can be found
49.369 + * @exception ClassCastException if the object found for the given key is not a string array
49.370 + * @return the string array for the given key
49.371 + */
49.372 + public final String[] getStringArray(String key) {
49.373 + return (String[]) getObject(key);
49.374 + }
49.375 +
49.376 + /**
49.377 + * Gets an object for the given key from this resource bundle or one of its parents.
49.378 + * This method first tries to obtain the object from this resource bundle using
49.379 + * {@link #handleGetObject(java.lang.String) handleGetObject}.
49.380 + * If not successful, and the parent resource bundle is not null,
49.381 + * it calls the parent's <code>getObject</code> method.
49.382 + * If still not successful, it throws a MissingResourceException.
49.383 + *
49.384 + * @param key the key for the desired object
49.385 + * @exception NullPointerException if <code>key</code> is <code>null</code>
49.386 + * @exception MissingResourceException if no object for the given key can be found
49.387 + * @return the object for the given key
49.388 + */
49.389 + public final Object getObject(String key) {
49.390 + Object obj = handleGetObject(key);
49.391 + if (obj == null) {
49.392 + if (parent != null) {
49.393 + obj = parent.getObject(key);
49.394 + }
49.395 + if (obj == null)
49.396 + throw new MissingResourceException("Can't find resource for bundle "
49.397 + +this.getClass().getName()
49.398 + +", key "+key,
49.399 + this.getClass().getName(),
49.400 + key);
49.401 + }
49.402 + return obj;
49.403 + }
49.404 +
49.405 + /**
49.406 + * Returns the locale of this resource bundle. This method can be used after a
49.407 + * call to getBundle() to determine whether the resource bundle returned really
49.408 + * corresponds to the requested locale or is a fallback.
49.409 + *
49.410 + * @return the locale of this resource bundle
49.411 + */
49.412 + public Locale getLocale() {
49.413 + return locale;
49.414 + }
49.415 +
49.416 + /*
49.417 + * Automatic determination of the ClassLoader to be used to load
49.418 + * resources on behalf of the client. N.B. The client is getLoader's
49.419 + * caller's caller.
49.420 + */
49.421 + private static ClassLoader getLoader() {
49.422 + Class[] stack = getClassContext();
49.423 + /* Magic number 2 identifies our caller's caller */
49.424 + Class c = stack[2];
49.425 + ClassLoader cl = (c == null) ? null : c.getClassLoader();
49.426 + if (cl == null) {
49.427 + // When the caller's loader is the boot class loader, cl is null
49.428 + // here. In that case, ClassLoader.getSystemClassLoader() may
49.429 + // return the same class loader that the application is
49.430 + // using. We therefore use a wrapper ClassLoader to create a
49.431 + // separate scope for bundles loaded on behalf of the Java
49.432 + // runtime so that these bundles cannot be returned from the
49.433 + // cache to the application (5048280).
49.434 + cl = RBClassLoader.INSTANCE;
49.435 + }
49.436 + return cl;
49.437 + }
49.438 +
49.439 + private static native Class[] getClassContext();
49.440 +
49.441 + /**
49.442 + * A wrapper of ClassLoader.getSystemClassLoader().
49.443 + */
49.444 + private static class RBClassLoader extends ClassLoader {
49.445 + private static final RBClassLoader INSTANCE = AccessController.doPrivileged(
49.446 + new PrivilegedAction<RBClassLoader>() {
49.447 + public RBClassLoader run() {
49.448 + return new RBClassLoader();
49.449 + }
49.450 + });
49.451 + private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
49.452 +
49.453 + private RBClassLoader() {
49.454 + }
49.455 + public Class<?> loadClass(String name) throws ClassNotFoundException {
49.456 + if (loader != null) {
49.457 + return loader.loadClass(name);
49.458 + }
49.459 + return Class.forName(name);
49.460 + }
49.461 + public URL getResource(String name) {
49.462 + if (loader != null) {
49.463 + return loader.getResource(name);
49.464 + }
49.465 + return ClassLoader.getSystemResource(name);
49.466 + }
49.467 + public InputStream getResourceAsStream(String name) {
49.468 + if (loader != null) {
49.469 + return loader.getResourceAsStream(name);
49.470 + }
49.471 + return ClassLoader.getSystemResourceAsStream(name);
49.472 + }
49.473 + }
49.474 +
49.475 + /**
49.476 + * Sets the parent bundle of this bundle.
49.477 + * The parent bundle is searched by {@link #getObject getObject}
49.478 + * when this bundle does not contain a particular resource.
49.479 + *
49.480 + * @param parent this bundle's parent bundle.
49.481 + */
49.482 + protected void setParent(ResourceBundle parent) {
49.483 + assert parent != NONEXISTENT_BUNDLE;
49.484 + this.parent = parent;
49.485 + }
49.486 +
49.487 + /**
49.488 + * Key used for cached resource bundles. The key checks the base
49.489 + * name, the locale, and the class loader to determine if the
49.490 + * resource is a match to the requested one. The loader may be
49.491 + * null, but the base name and the locale must have a non-null
49.492 + * value.
49.493 + */
49.494 + private static final class CacheKey implements Cloneable {
49.495 + // These three are the actual keys for lookup in Map.
49.496 + private String name;
49.497 + private Locale locale;
49.498 + private LoaderReference loaderRef;
49.499 +
49.500 + // bundle format which is necessary for calling
49.501 + // Control.needsReload().
49.502 + private String format;
49.503 +
49.504 + // These time values are in CacheKey so that NONEXISTENT_BUNDLE
49.505 + // doesn't need to be cloned for caching.
49.506 +
49.507 + // The time when the bundle has been loaded
49.508 + private volatile long loadTime;
49.509 +
49.510 + // The time when the bundle expires in the cache, or either
49.511 + // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
49.512 + private volatile long expirationTime;
49.513 +
49.514 + // Placeholder for an error report by a Throwable
49.515 + private Throwable cause;
49.516 +
49.517 + // Hash code value cache to avoid recalculating the hash code
49.518 + // of this instance.
49.519 + private int hashCodeCache;
49.520 +
49.521 + CacheKey(String baseName, Locale locale, ClassLoader loader) {
49.522 + this.name = baseName;
49.523 + this.locale = locale;
49.524 + if (loader == null) {
49.525 + this.loaderRef = null;
49.526 + } else {
49.527 + loaderRef = new LoaderReference(loader, referenceQueue, this);
49.528 + }
49.529 + calculateHashCode();
49.530 + }
49.531 +
49.532 + String getName() {
49.533 + return name;
49.534 + }
49.535 +
49.536 + CacheKey setName(String baseName) {
49.537 + if (!this.name.equals(baseName)) {
49.538 + this.name = baseName;
49.539 + calculateHashCode();
49.540 + }
49.541 + return this;
49.542 + }
49.543 +
49.544 + Locale getLocale() {
49.545 + return locale;
49.546 + }
49.547 +
49.548 + CacheKey setLocale(Locale locale) {
49.549 + if (!this.locale.equals(locale)) {
49.550 + this.locale = locale;
49.551 + calculateHashCode();
49.552 + }
49.553 + return this;
49.554 + }
49.555 +
49.556 + ClassLoader getLoader() {
49.557 + return (loaderRef != null) ? loaderRef.get() : null;
49.558 + }
49.559 +
49.560 + public boolean equals(Object other) {
49.561 + if (this == other) {
49.562 + return true;
49.563 + }
49.564 + try {
49.565 + final CacheKey otherEntry = (CacheKey)other;
49.566 + //quick check to see if they are not equal
49.567 + if (hashCodeCache != otherEntry.hashCodeCache) {
49.568 + return false;
49.569 + }
49.570 + //are the names the same?
49.571 + if (!name.equals(otherEntry.name)) {
49.572 + return false;
49.573 + }
49.574 + // are the locales the same?
49.575 + if (!locale.equals(otherEntry.locale)) {
49.576 + return false;
49.577 + }
49.578 + //are refs (both non-null) or (both null)?
49.579 + if (loaderRef == null) {
49.580 + return otherEntry.loaderRef == null;
49.581 + }
49.582 + ClassLoader loader = loaderRef.get();
49.583 + return (otherEntry.loaderRef != null)
49.584 + // with a null reference we can no longer find
49.585 + // out which class loader was referenced; so
49.586 + // treat it as unequal
49.587 + && (loader != null)
49.588 + && (loader == otherEntry.loaderRef.get());
49.589 + } catch (NullPointerException e) {
49.590 + } catch (ClassCastException e) {
49.591 + }
49.592 + return false;
49.593 + }
49.594 +
49.595 + public int hashCode() {
49.596 + return hashCodeCache;
49.597 + }
49.598 +
49.599 + private void calculateHashCode() {
49.600 + hashCodeCache = name.hashCode() << 3;
49.601 + hashCodeCache ^= locale.hashCode();
49.602 + ClassLoader loader = getLoader();
49.603 + if (loader != null) {
49.604 + hashCodeCache ^= loader.hashCode();
49.605 + }
49.606 + }
49.607 +
49.608 + public Object clone() {
49.609 + try {
49.610 + CacheKey clone = (CacheKey) super.clone();
49.611 + if (loaderRef != null) {
49.612 + clone.loaderRef = new LoaderReference(loaderRef.get(),
49.613 + referenceQueue, clone);
49.614 + }
49.615 + // Clear the reference to a Throwable
49.616 + clone.cause = null;
49.617 + return clone;
49.618 + } catch (CloneNotSupportedException e) {
49.619 + //this should never happen
49.620 + throw new InternalError();
49.621 + }
49.622 + }
49.623 +
49.624 + String getFormat() {
49.625 + return format;
49.626 + }
49.627 +
49.628 + void setFormat(String format) {
49.629 + this.format = format;
49.630 + }
49.631 +
49.632 + private void setCause(Throwable cause) {
49.633 + if (this.cause == null) {
49.634 + this.cause = cause;
49.635 + } else {
49.636 + // Override the cause if the previous one is
49.637 + // ClassNotFoundException.
49.638 + if (this.cause instanceof ClassNotFoundException) {
49.639 + this.cause = cause;
49.640 + }
49.641 + }
49.642 + }
49.643 +
49.644 + private Throwable getCause() {
49.645 + return cause;
49.646 + }
49.647 +
49.648 + public String toString() {
49.649 + String l = locale.toString();
49.650 + if (l.length() == 0) {
49.651 + if (locale.getVariant().length() != 0) {
49.652 + l = "__" + locale.getVariant();
49.653 + } else {
49.654 + l = "\"\"";
49.655 + }
49.656 + }
49.657 + return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader()
49.658 + + "(format=" + format + ")]";
49.659 + }
49.660 + }
49.661 +
49.662 + /**
49.663 + * The common interface to get a CacheKey in LoaderReference and
49.664 + * BundleReference.
49.665 + */
49.666 + private static interface CacheKeyReference {
49.667 + public CacheKey getCacheKey();
49.668 + }
49.669 +
49.670 + /**
49.671 + * References to class loaders are weak references, so that they can be
49.672 + * garbage collected when nobody else is using them. The ResourceBundle
49.673 + * class has no reason to keep class loaders alive.
49.674 + */
49.675 + private static final class LoaderReference extends WeakReference<ClassLoader>
49.676 + implements CacheKeyReference {
49.677 + private CacheKey cacheKey;
49.678 +
49.679 + LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) {
49.680 + super(referent, q);
49.681 + cacheKey = key;
49.682 + }
49.683 +
49.684 + public CacheKey getCacheKey() {
49.685 + return cacheKey;
49.686 + }
49.687 + }
49.688 +
49.689 + /**
49.690 + * References to bundles are soft references so that they can be garbage
49.691 + * collected when they have no hard references.
49.692 + */
49.693 + private static final class BundleReference extends SoftReference<ResourceBundle>
49.694 + implements CacheKeyReference {
49.695 + private CacheKey cacheKey;
49.696 +
49.697 + BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) {
49.698 + super(referent, q);
49.699 + cacheKey = key;
49.700 + }
49.701 +
49.702 + public CacheKey getCacheKey() {
49.703 + return cacheKey;
49.704 + }
49.705 + }
49.706 +
49.707 + /**
49.708 + * Gets a resource bundle using the specified base name, the default locale,
49.709 + * and the caller's class loader. Calling this method is equivalent to calling
49.710 + * <blockquote>
49.711 + * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
49.712 + * </blockquote>
49.713 + * except that <code>getClassLoader()</code> is run with the security
49.714 + * privileges of <code>ResourceBundle</code>.
49.715 + * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
49.716 + * for a complete description of the search and instantiation strategy.
49.717 + *
49.718 + * @param baseName the base name of the resource bundle, a fully qualified class name
49.719 + * @exception java.lang.NullPointerException
49.720 + * if <code>baseName</code> is <code>null</code>
49.721 + * @exception MissingResourceException
49.722 + * if no resource bundle for the specified base name can be found
49.723 + * @return a resource bundle for the given base name and the default locale
49.724 + */
49.725 + public static final ResourceBundle getBundle(String baseName)
49.726 + {
49.727 + return getBundleImpl(baseName, Locale.getDefault(),
49.728 + /* must determine loader here, else we break stack invariant */
49.729 + getLoader(),
49.730 + Control.INSTANCE);
49.731 + }
49.732 +
49.733 + /**
49.734 + * Returns a resource bundle using the specified base name, the
49.735 + * default locale and the specified control. Calling this method
49.736 + * is equivalent to calling
49.737 + * <pre>
49.738 + * getBundle(baseName, Locale.getDefault(),
49.739 + * this.getClass().getClassLoader(), control),
49.740 + * </pre>
49.741 + * except that <code>getClassLoader()</code> is run with the security
49.742 + * privileges of <code>ResourceBundle</code>. See {@link
49.743 + * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
49.744 + * complete description of the resource bundle loading process with a
49.745 + * <code>ResourceBundle.Control</code>.
49.746 + *
49.747 + * @param baseName
49.748 + * the base name of the resource bundle, a fully qualified class
49.749 + * name
49.750 + * @param control
49.751 + * the control which gives information for the resource bundle
49.752 + * loading process
49.753 + * @return a resource bundle for the given base name and the default
49.754 + * locale
49.755 + * @exception NullPointerException
49.756 + * if <code>baseName</code> or <code>control</code> is
49.757 + * <code>null</code>
49.758 + * @exception MissingResourceException
49.759 + * if no resource bundle for the specified base name can be found
49.760 + * @exception IllegalArgumentException
49.761 + * if the given <code>control</code> doesn't perform properly
49.762 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
49.763 + * Note that validation of <code>control</code> is performed as
49.764 + * needed.
49.765 + * @since 1.6
49.766 + */
49.767 + public static final ResourceBundle getBundle(String baseName,
49.768 + Control control) {
49.769 + return getBundleImpl(baseName, Locale.getDefault(),
49.770 + /* must determine loader here, else we break stack invariant */
49.771 + getLoader(),
49.772 + control);
49.773 + }
49.774 +
49.775 + /**
49.776 + * Gets a resource bundle using the specified base name and locale,
49.777 + * and the caller's class loader. Calling this method is equivalent to calling
49.778 + * <blockquote>
49.779 + * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
49.780 + * </blockquote>
49.781 + * except that <code>getClassLoader()</code> is run with the security
49.782 + * privileges of <code>ResourceBundle</code>.
49.783 + * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
49.784 + * for a complete description of the search and instantiation strategy.
49.785 + *
49.786 + * @param baseName
49.787 + * the base name of the resource bundle, a fully qualified class name
49.788 + * @param locale
49.789 + * the locale for which a resource bundle is desired
49.790 + * @exception NullPointerException
49.791 + * if <code>baseName</code> or <code>locale</code> is <code>null</code>
49.792 + * @exception MissingResourceException
49.793 + * if no resource bundle for the specified base name can be found
49.794 + * @return a resource bundle for the given base name and locale
49.795 + */
49.796 + public static final ResourceBundle getBundle(String baseName,
49.797 + Locale locale)
49.798 + {
49.799 + return getBundleImpl(baseName, locale,
49.800 + /* must determine loader here, else we break stack invariant */
49.801 + getLoader(),
49.802 + Control.INSTANCE);
49.803 + }
49.804 +
49.805 + /**
49.806 + * Returns a resource bundle using the specified base name, target
49.807 + * locale and control, and the caller's class loader. Calling this
49.808 + * method is equivalent to calling
49.809 + * <pre>
49.810 + * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
49.811 + * control),
49.812 + * </pre>
49.813 + * except that <code>getClassLoader()</code> is run with the security
49.814 + * privileges of <code>ResourceBundle</code>. See {@link
49.815 + * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
49.816 + * complete description of the resource bundle loading process with a
49.817 + * <code>ResourceBundle.Control</code>.
49.818 + *
49.819 + * @param baseName
49.820 + * the base name of the resource bundle, a fully qualified
49.821 + * class name
49.822 + * @param targetLocale
49.823 + * the locale for which a resource bundle is desired
49.824 + * @param control
49.825 + * the control which gives information for the resource
49.826 + * bundle loading process
49.827 + * @return a resource bundle for the given base name and a
49.828 + * <code>Locale</code> in <code>locales</code>
49.829 + * @exception NullPointerException
49.830 + * if <code>baseName</code>, <code>locales</code> or
49.831 + * <code>control</code> is <code>null</code>
49.832 + * @exception MissingResourceException
49.833 + * if no resource bundle for the specified base name in any
49.834 + * of the <code>locales</code> can be found.
49.835 + * @exception IllegalArgumentException
49.836 + * if the given <code>control</code> doesn't perform properly
49.837 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
49.838 + * Note that validation of <code>control</code> is performed as
49.839 + * needed.
49.840 + * @since 1.6
49.841 + */
49.842 + public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
49.843 + Control control) {
49.844 + return getBundleImpl(baseName, targetLocale,
49.845 + /* must determine loader here, else we break stack invariant */
49.846 + getLoader(),
49.847 + control);
49.848 + }
49.849 +
49.850 + /**
49.851 + * Gets a resource bundle using the specified base name, locale, and class
49.852 + * loader.
49.853 + *
49.854 + * <p><a name="default_behavior"/>This method behaves the same as calling
49.855 + * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
49.856 + * default instance of {@link Control}. The following describes this behavior.
49.857 + *
49.858 + * <p><code>getBundle</code> uses the base name, the specified locale, and
49.859 + * the default locale (obtained from {@link java.util.Locale#getDefault()
49.860 + * Locale.getDefault}) to generate a sequence of <a
49.861 + * name="candidates"><em>candidate bundle names</em></a>. If the specified
49.862 + * locale's language, script, country, and variant are all empty strings,
49.863 + * then the base name is the only candidate bundle name. Otherwise, a list
49.864 + * of candidate locales is generated from the attribute values of the
49.865 + * specified locale (language, script, country and variant) and appended to
49.866 + * the base name. Typically, this will look like the following:
49.867 + *
49.868 + * <pre>
49.869 + * baseName + "_" + language + "_" + script + "_" + country + "_" + variant
49.870 + * baseName + "_" + language + "_" + script + "_" + country
49.871 + * baseName + "_" + language + "_" + script
49.872 + * baseName + "_" + language + "_" + country + "_" + variant
49.873 + * baseName + "_" + language + "_" + country
49.874 + * baseName + "_" + language
49.875 + * </pre>
49.876 + *
49.877 + * <p>Candidate bundle names where the final component is an empty string
49.878 + * are omitted, along with the underscore. For example, if country is an
49.879 + * empty string, the second and the fifth candidate bundle names above
49.880 + * would be omitted. Also, if script is an empty string, the candidate names
49.881 + * including script are omitted. For example, a locale with language "de"
49.882 + * and variant "JAVA" will produce candidate names with base name
49.883 + * "MyResource" below.
49.884 + *
49.885 + * <pre>
49.886 + * MyResource_de__JAVA
49.887 + * MyResource_de
49.888 + * </pre>
49.889 + *
49.890 + * In the case that the variant contains one or more underscores ('_'), a
49.891 + * sequence of bundle names generated by truncating the last underscore and
49.892 + * the part following it is inserted after a candidate bundle name with the
49.893 + * original variant. For example, for a locale with language "en", script
49.894 + * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
49.895 + * "MyResource", the list of candidate bundle names below is generated:
49.896 + *
49.897 + * <pre>
49.898 + * MyResource_en_Latn_US_WINDOWS_VISTA
49.899 + * MyResource_en_Latn_US_WINDOWS
49.900 + * MyResource_en_Latn_US
49.901 + * MyResource_en_Latn
49.902 + * MyResource_en_US_WINDOWS_VISTA
49.903 + * MyResource_en_US_WINDOWS
49.904 + * MyResource_en_US
49.905 + * MyResource_en
49.906 + * </pre>
49.907 + *
49.908 + * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
49.909 + * candidate bundle names contains extra names, or the order of bundle names
49.910 + * is slightly modified. See the description of the default implementation
49.911 + * of {@link Control#getCandidateLocales(String, Locale)
49.912 + * getCandidateLocales} for details.</blockquote>
49.913 + *
49.914 + * <p><code>getBundle</code> then iterates over the candidate bundle names
49.915 + * to find the first one for which it can <em>instantiate</em> an actual
49.916 + * resource bundle. It uses the default controls' {@link Control#getFormats
49.917 + * getFormats} method, which generates two bundle names for each generated
49.918 + * name, the first a class name and the second a properties file name. For
49.919 + * each candidate bundle name, it attempts to create a resource bundle:
49.920 + *
49.921 + * <ul><li>First, it attempts to load a class using the generated class name.
49.922 + * If such a class can be found and loaded using the specified class
49.923 + * loader, is assignment compatible with ResourceBundle, is accessible from
49.924 + * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
49.925 + * new instance of this class and uses it as the <em>result resource
49.926 + * bundle</em>.
49.927 + *
49.928 + * <li>Otherwise, <code>getBundle</code> attempts to locate a property
49.929 + * resource file using the generated properties file name. It generates a
49.930 + * path name from the candidate bundle name by replacing all "." characters
49.931 + * with "/" and appending the string ".properties". It attempts to find a
49.932 + * "resource" with this name using {@link
49.933 + * java.lang.ClassLoader#getResource(java.lang.String)
49.934 + * ClassLoader.getResource}. (Note that a "resource" in the sense of
49.935 + * <code>getResource</code> has nothing to do with the contents of a
49.936 + * resource bundle, it is just a container of data, such as a file.) If it
49.937 + * finds a "resource", it attempts to create a new {@link
49.938 + * PropertyResourceBundle} instance from its contents. If successful, this
49.939 + * instance becomes the <em>result resource bundle</em>. </ul>
49.940 + *
49.941 + * <p>This continues until a result resource bundle is instantiated or the
49.942 + * list of candidate bundle names is exhausted. If no matching resource
49.943 + * bundle is found, the default control's {@link Control#getFallbackLocale
49.944 + * getFallbackLocale} method is called, which returns the current default
49.945 + * locale. A new sequence of candidate locale names is generated using this
49.946 + * locale and and searched again, as above.
49.947 + *
49.948 + * <p>If still no result bundle is found, the base name alone is looked up. If
49.949 + * this still fails, a <code>MissingResourceException</code> is thrown.
49.950 + *
49.951 + * <p><a name="parent_chain"/> Once a result resource bundle has been found,
49.952 + * its <em>parent chain</em> is instantiated. If the result bundle already
49.953 + * has a parent (perhaps because it was returned from a cache) the chain is
49.954 + * complete.
49.955 + *
49.956 + * <p>Otherwise, <code>getBundle</code> examines the remainder of the
49.957 + * candidate locale list that was used during the pass that generated the
49.958 + * result resource bundle. (As before, candidate bundle names where the
49.959 + * final component is an empty string are omitted.) When it comes to the
49.960 + * end of the candidate list, it tries the plain bundle name. With each of the
49.961 + * candidate bundle names it attempts to instantiate a resource bundle (first
49.962 + * looking for a class and then a properties file, as described above).
49.963 + *
49.964 + * <p>Whenever it succeeds, it calls the previously instantiated resource
49.965 + * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
49.966 + * with the new resource bundle. This continues until the list of names
49.967 + * is exhausted or the current bundle already has a non-null parent.
49.968 + *
49.969 + * <p>Once the parent chain is complete, the bundle is returned.
49.970 + *
49.971 + * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
49.972 + * bundles and might return the same resource bundle instance multiple times.
49.973 + *
49.974 + * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
49.975 + * qualified class name. However, for compatibility with earlier versions,
49.976 + * Sun's Java SE Runtime Environments do not verify this, and so it is
49.977 + * possible to access <code>PropertyResourceBundle</code>s by specifying a
49.978 + * path name (using "/") instead of a fully qualified class name (using
49.979 + * ".").
49.980 + *
49.981 + * <p><a name="default_behavior_example"/>
49.982 + * <strong>Example:</strong>
49.983 + * <p>
49.984 + * The following class and property files are provided:
49.985 + * <pre>
49.986 + * MyResources.class
49.987 + * MyResources.properties
49.988 + * MyResources_fr.properties
49.989 + * MyResources_fr_CH.class
49.990 + * MyResources_fr_CH.properties
49.991 + * MyResources_en.properties
49.992 + * MyResources_es_ES.class
49.993 + * </pre>
49.994 + *
49.995 + * The contents of all files are valid (that is, public non-abstract
49.996 + * subclasses of <code>ResourceBundle</code> for the ".class" files,
49.997 + * syntactically correct ".properties" files). The default locale is
49.998 + * <code>Locale("en", "GB")</code>.
49.999 + *
49.1000 + * <p>Calling <code>getBundle</code> with the locale arguments below will
49.1001 + * instantiate resource bundles as follows:
49.1002 + *
49.1003 + * <table>
49.1004 + * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
49.1005 + * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
49.1006 + * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
49.1007 + * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
49.1008 + * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
49.1009 + * </table>
49.1010 + *
49.1011 + * <p>The file MyResources_fr_CH.properties is never used because it is
49.1012 + * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
49.1013 + * is also hidden by MyResources.class.
49.1014 + *
49.1015 + * @param baseName the base name of the resource bundle, a fully qualified class name
49.1016 + * @param locale the locale for which a resource bundle is desired
49.1017 + * @param loader the class loader from which to load the resource bundle
49.1018 + * @return a resource bundle for the given base name and locale
49.1019 + * @exception java.lang.NullPointerException
49.1020 + * if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
49.1021 + * @exception MissingResourceException
49.1022 + * if no resource bundle for the specified base name can be found
49.1023 + * @since 1.2
49.1024 + */
49.1025 + public static ResourceBundle getBundle(String baseName, Locale locale,
49.1026 + ClassLoader loader)
49.1027 + {
49.1028 + if (loader == null) {
49.1029 + throw new NullPointerException();
49.1030 + }
49.1031 + return getBundleImpl(baseName, locale, loader, Control.INSTANCE);
49.1032 + }
49.1033 +
49.1034 + /**
49.1035 + * Returns a resource bundle using the specified base name, target
49.1036 + * locale, class loader and control. Unlike the {@linkplain
49.1037 + * #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
49.1038 + * factory methods with no <code>control</code> argument}, the given
49.1039 + * <code>control</code> specifies how to locate and instantiate resource
49.1040 + * bundles. Conceptually, the bundle loading process with the given
49.1041 + * <code>control</code> is performed in the following steps.
49.1042 + *
49.1043 + * <p>
49.1044 + * <ol>
49.1045 + * <li>This factory method looks up the resource bundle in the cache for
49.1046 + * the specified <code>baseName</code>, <code>targetLocale</code> and
49.1047 + * <code>loader</code>. If the requested resource bundle instance is
49.1048 + * found in the cache and the time-to-live periods of the instance and
49.1049 + * all of its parent instances have not expired, the instance is returned
49.1050 + * to the caller. Otherwise, this factory method proceeds with the
49.1051 + * loading process below.</li>
49.1052 + *
49.1053 + * <li>The {@link ResourceBundle.Control#getFormats(String)
49.1054 + * control.getFormats} method is called to get resource bundle formats
49.1055 + * to produce bundle or resource names. The strings
49.1056 + * <code>"java.class"</code> and <code>"java.properties"</code>
49.1057 + * designate class-based and {@linkplain PropertyResourceBundle
49.1058 + * property}-based resource bundles, respectively. Other strings
49.1059 + * starting with <code>"java."</code> are reserved for future extensions
49.1060 + * and must not be used for application-defined formats. Other strings
49.1061 + * designate application-defined formats.</li>
49.1062 + *
49.1063 + * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
49.1064 + * Locale) control.getCandidateLocales} method is called with the target
49.1065 + * locale to get a list of <em>candidate <code>Locale</code>s</em> for
49.1066 + * which resource bundles are searched.</li>
49.1067 + *
49.1068 + * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
49.1069 + * String, ClassLoader, boolean) control.newBundle} method is called to
49.1070 + * instantiate a <code>ResourceBundle</code> for the base bundle name, a
49.1071 + * candidate locale, and a format. (Refer to the note on the cache
49.1072 + * lookup below.) This step is iterated over all combinations of the
49.1073 + * candidate locales and formats until the <code>newBundle</code> method
49.1074 + * returns a <code>ResourceBundle</code> instance or the iteration has
49.1075 + * used up all the combinations. For example, if the candidate locales
49.1076 + * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
49.1077 + * <code>Locale("")</code> and the formats are <code>"java.class"</code>
49.1078 + * and <code>"java.properties"</code>, then the following is the
49.1079 + * sequence of locale-format combinations to be used to call
49.1080 + * <code>control.newBundle</code>.
49.1081 + *
49.1082 + * <table style="width: 50%; text-align: left; margin-left: 40px;"
49.1083 + * border="0" cellpadding="2" cellspacing="2">
49.1084 + * <tbody><code>
49.1085 + * <tr>
49.1086 + * <td
49.1087 + * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br>
49.1088 + * </td>
49.1089 + * <td
49.1090 + * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br>
49.1091 + * </td>
49.1092 + * </tr>
49.1093 + * <tr>
49.1094 + * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br>
49.1095 + * </td>
49.1096 + * <td style="vertical-align: top; width: 50%;">java.class<br>
49.1097 + * </td>
49.1098 + * </tr>
49.1099 + * <tr>
49.1100 + * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td>
49.1101 + * <td style="vertical-align: top; width: 50%;">java.properties<br>
49.1102 + * </td>
49.1103 + * </tr>
49.1104 + * <tr>
49.1105 + * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
49.1106 + * <td style="vertical-align: top; width: 50%;">java.class</td>
49.1107 + * </tr>
49.1108 + * <tr>
49.1109 + * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
49.1110 + * <td style="vertical-align: top; width: 50%;">java.properties</td>
49.1111 + * </tr>
49.1112 + * <tr>
49.1113 + * <td style="vertical-align: top; width: 50%;">Locale("")<br>
49.1114 + * </td>
49.1115 + * <td style="vertical-align: top; width: 50%;">java.class</td>
49.1116 + * </tr>
49.1117 + * <tr>
49.1118 + * <td style="vertical-align: top; width: 50%;">Locale("")</td>
49.1119 + * <td style="vertical-align: top; width: 50%;">java.properties</td>
49.1120 + * </tr>
49.1121 + * </code></tbody>
49.1122 + * </table>
49.1123 + * </li>
49.1124 + *
49.1125 + * <li>If the previous step has found no resource bundle, proceed to
49.1126 + * Step 6. If a bundle has been found that is a base bundle (a bundle
49.1127 + * for <code>Locale("")</code>), and the candidate locale list only contained
49.1128 + * <code>Locale("")</code>, return the bundle to the caller. If a bundle
49.1129 + * has been found that is a base bundle, but the candidate locale list
49.1130 + * contained locales other than Locale(""), put the bundle on hold and
49.1131 + * proceed to Step 6. If a bundle has been found that is not a base
49.1132 + * bundle, proceed to Step 7.</li>
49.1133 + *
49.1134 + * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
49.1135 + * Locale) control.getFallbackLocale} method is called to get a fallback
49.1136 + * locale (alternative to the current target locale) to try further
49.1137 + * finding a resource bundle. If the method returns a non-null locale,
49.1138 + * it becomes the next target locale and the loading process starts over
49.1139 + * from Step 3. Otherwise, if a base bundle was found and put on hold in
49.1140 + * a previous Step 5, it is returned to the caller now. Otherwise, a
49.1141 + * MissingResourceException is thrown.</li>
49.1142 + *
49.1143 + * <li>At this point, we have found a resource bundle that's not the
49.1144 + * base bundle. If this bundle set its parent during its instantiation,
49.1145 + * it is returned to the caller. Otherwise, its <a
49.1146 + * href="./ResourceBundle.html#parent_chain">parent chain</a> is
49.1147 + * instantiated based on the list of candidate locales from which it was
49.1148 + * found. Finally, the bundle is returned to the caller.</li>
49.1149 + * </ol>
49.1150 + *
49.1151 + * <p>During the resource bundle loading process above, this factory
49.1152 + * method looks up the cache before calling the {@link
49.1153 + * Control#newBundle(String, Locale, String, ClassLoader, boolean)
49.1154 + * control.newBundle} method. If the time-to-live period of the
49.1155 + * resource bundle found in the cache has expired, the factory method
49.1156 + * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
49.1157 + * String, ClassLoader, ResourceBundle, long) control.needsReload}
49.1158 + * method to determine whether the resource bundle needs to be reloaded.
49.1159 + * If reloading is required, the factory method calls
49.1160 + * <code>control.newBundle</code> to reload the resource bundle. If
49.1161 + * <code>control.newBundle</code> returns <code>null</code>, the factory
49.1162 + * method puts a dummy resource bundle in the cache as a mark of
49.1163 + * nonexistent resource bundles in order to avoid lookup overhead for
49.1164 + * subsequent requests. Such dummy resource bundles are under the same
49.1165 + * expiration control as specified by <code>control</code>.
49.1166 + *
49.1167 + * <p>All resource bundles loaded are cached by default. Refer to
49.1168 + * {@link Control#getTimeToLive(String,Locale)
49.1169 + * control.getTimeToLive} for details.
49.1170 + *
49.1171 + * <p>The following is an example of the bundle loading process with the
49.1172 + * default <code>ResourceBundle.Control</code> implementation.
49.1173 + *
49.1174 + * <p>Conditions:
49.1175 + * <ul>
49.1176 + * <li>Base bundle name: <code>foo.bar.Messages</code>
49.1177 + * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
49.1178 + * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
49.1179 + * <li>Available resource bundles:
49.1180 + * <code>foo/bar/Messages_fr.properties</code> and
49.1181 + * <code>foo/bar/Messages.properties</code></li>
49.1182 + * </ul>
49.1183 + *
49.1184 + * <p>First, <code>getBundle</code> tries loading a resource bundle in
49.1185 + * the following sequence.
49.1186 + *
49.1187 + * <ul>
49.1188 + * <li>class <code>foo.bar.Messages_it_IT</code>
49.1189 + * <li>file <code>foo/bar/Messages_it_IT.properties</code>
49.1190 + * <li>class <code>foo.bar.Messages_it</code></li>
49.1191 + * <li>file <code>foo/bar/Messages_it.properties</code></li>
49.1192 + * <li>class <code>foo.bar.Messages</code></li>
49.1193 + * <li>file <code>foo/bar/Messages.properties</code></li>
49.1194 + * </ul>
49.1195 + *
49.1196 + * <p>At this point, <code>getBundle</code> finds
49.1197 + * <code>foo/bar/Messages.properties</code>, which is put on hold
49.1198 + * because it's the base bundle. <code>getBundle</code> calls {@link
49.1199 + * Control#getFallbackLocale(String, Locale)
49.1200 + * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
49.1201 + * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
49.1202 + * tries loading a bundle in the following sequence.
49.1203 + *
49.1204 + * <ul>
49.1205 + * <li>class <code>foo.bar.Messages_fr</code></li>
49.1206 + * <li>file <code>foo/bar/Messages_fr.properties</code></li>
49.1207 + * <li>class <code>foo.bar.Messages</code></li>
49.1208 + * <li>file <code>foo/bar/Messages.properties</code></li>
49.1209 + * </ul>
49.1210 + *
49.1211 + * <p><code>getBundle</code> finds
49.1212 + * <code>foo/bar/Messages_fr.properties</code> and creates a
49.1213 + * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
49.1214 + * sets up its parent chain from the list of the candiate locales. Only
49.1215 + * <code>foo/bar/Messages.properties</code> is found in the list and
49.1216 + * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
49.1217 + * that becomes the parent of the instance for
49.1218 + * <code>foo/bar/Messages_fr.properties</code>.
49.1219 + *
49.1220 + * @param baseName
49.1221 + * the base name of the resource bundle, a fully qualified
49.1222 + * class name
49.1223 + * @param targetLocale
49.1224 + * the locale for which a resource bundle is desired
49.1225 + * @param loader
49.1226 + * the class loader from which to load the resource bundle
49.1227 + * @param control
49.1228 + * the control which gives information for the resource
49.1229 + * bundle loading process
49.1230 + * @return a resource bundle for the given base name and locale
49.1231 + * @exception NullPointerException
49.1232 + * if <code>baseName</code>, <code>targetLocale</code>,
49.1233 + * <code>loader</code>, or <code>control</code> is
49.1234 + * <code>null</code>
49.1235 + * @exception MissingResourceException
49.1236 + * if no resource bundle for the specified base name can be found
49.1237 + * @exception IllegalArgumentException
49.1238 + * if the given <code>control</code> doesn't perform properly
49.1239 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
49.1240 + * Note that validation of <code>control</code> is performed as
49.1241 + * needed.
49.1242 + * @since 1.6
49.1243 + */
49.1244 + public static ResourceBundle getBundle(String baseName, Locale targetLocale,
49.1245 + ClassLoader loader, Control control) {
49.1246 + if (loader == null || control == null) {
49.1247 + throw new NullPointerException();
49.1248 + }
49.1249 + return getBundleImpl(baseName, targetLocale, loader, control);
49.1250 + }
49.1251 +
49.1252 + private static ResourceBundle getBundleImpl(String baseName, Locale locale,
49.1253 + ClassLoader loader, Control control) {
49.1254 + if (locale == null || control == null) {
49.1255 + throw new NullPointerException();
49.1256 + }
49.1257 +
49.1258 + // We create a CacheKey here for use by this call. The base
49.1259 + // name and loader will never change during the bundle loading
49.1260 + // process. We have to make sure that the locale is set before
49.1261 + // using it as a cache key.
49.1262 + CacheKey cacheKey = new CacheKey(baseName, locale, loader);
49.1263 + ResourceBundle bundle = null;
49.1264 +
49.1265 + // Quick lookup of the cache.
49.1266 + BundleReference bundleRef = cacheList.get(cacheKey);
49.1267 + if (bundleRef != null) {
49.1268 + bundle = bundleRef.get();
49.1269 + bundleRef = null;
49.1270 + }
49.1271 +
49.1272 + // If this bundle and all of its parents are valid (not expired),
49.1273 + // then return this bundle. If any of the bundles is expired, we
49.1274 + // don't call control.needsReload here but instead drop into the
49.1275 + // complete loading process below.
49.1276 + if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
49.1277 + return bundle;
49.1278 + }
49.1279 +
49.1280 + // No valid bundle was found in the cache, so we need to load the
49.1281 + // resource bundle and its parents.
49.1282 +
49.1283 + boolean isKnownControl = (control == Control.INSTANCE) ||
49.1284 + (control instanceof SingleFormatControl);
49.1285 + List<String> formats = control.getFormats(baseName);
49.1286 + if (!isKnownControl && !checkList(formats)) {
49.1287 + throw new IllegalArgumentException("Invalid Control: getFormats");
49.1288 + }
49.1289 +
49.1290 + ResourceBundle baseBundle = null;
49.1291 + for (Locale targetLocale = locale;
49.1292 + targetLocale != null;
49.1293 + targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
49.1294 + List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
49.1295 + if (!isKnownControl && !checkList(candidateLocales)) {
49.1296 + throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
49.1297 + }
49.1298 +
49.1299 + bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
49.1300 +
49.1301 + // If the loaded bundle is the base bundle and exactly for the
49.1302 + // requested locale or the only candidate locale, then take the
49.1303 + // bundle as the resulting one. If the loaded bundle is the base
49.1304 + // bundle, it's put on hold until we finish processing all
49.1305 + // fallback locales.
49.1306 + if (isValidBundle(bundle)) {
49.1307 + boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
49.1308 + if (!isBaseBundle || bundle.locale.equals(locale)
49.1309 + || (candidateLocales.size() == 1
49.1310 + && bundle.locale.equals(candidateLocales.get(0)))) {
49.1311 + break;
49.1312 + }
49.1313 +
49.1314 + // If the base bundle has been loaded, keep the reference in
49.1315 + // baseBundle so that we can avoid any redundant loading in case
49.1316 + // the control specify not to cache bundles.
49.1317 + if (isBaseBundle && baseBundle == null) {
49.1318 + baseBundle = bundle;
49.1319 + }
49.1320 + }
49.1321 + }
49.1322 +
49.1323 + if (bundle == null) {
49.1324 + if (baseBundle == null) {
49.1325 + throwMissingResourceException(baseName, locale, cacheKey.getCause());
49.1326 + }
49.1327 + bundle = baseBundle;
49.1328 + }
49.1329 +
49.1330 + return bundle;
49.1331 + }
49.1332 +
49.1333 + /**
49.1334 + * Checks if the given <code>List</code> is not null, not empty,
49.1335 + * not having null in its elements.
49.1336 + */
49.1337 + private static final boolean checkList(List a) {
49.1338 + boolean valid = (a != null && a.size() != 0);
49.1339 + if (valid) {
49.1340 + int size = a.size();
49.1341 + for (int i = 0; valid && i < size; i++) {
49.1342 + valid = (a.get(i) != null);
49.1343 + }
49.1344 + }
49.1345 + return valid;
49.1346 + }
49.1347 +
49.1348 + private static final ResourceBundle findBundle(CacheKey cacheKey,
49.1349 + List<Locale> candidateLocales,
49.1350 + List<String> formats,
49.1351 + int index,
49.1352 + Control control,
49.1353 + ResourceBundle baseBundle) {
49.1354 + Locale targetLocale = candidateLocales.get(index);
49.1355 + ResourceBundle parent = null;
49.1356 + if (index != candidateLocales.size() - 1) {
49.1357 + parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
49.1358 + control, baseBundle);
49.1359 + } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
49.1360 + return baseBundle;
49.1361 + }
49.1362 +
49.1363 + // Before we do the real loading work, see whether we need to
49.1364 + // do some housekeeping: If references to class loaders or
49.1365 + // resource bundles have been nulled out, remove all related
49.1366 + // information from the cache.
49.1367 + Object ref;
49.1368 + while ((ref = referenceQueue.poll()) != null) {
49.1369 + cacheList.remove(((CacheKeyReference)ref).getCacheKey());
49.1370 + }
49.1371 +
49.1372 + // flag indicating the resource bundle has expired in the cache
49.1373 + boolean expiredBundle = false;
49.1374 +
49.1375 + // First, look up the cache to see if it's in the cache, without
49.1376 + // attempting to load bundle.
49.1377 + cacheKey.setLocale(targetLocale);
49.1378 + ResourceBundle bundle = findBundleInCache(cacheKey, control);
49.1379 + if (isValidBundle(bundle)) {
49.1380 + expiredBundle = bundle.expired;
49.1381 + if (!expiredBundle) {
49.1382 + // If its parent is the one asked for by the candidate
49.1383 + // locales (the runtime lookup path), we can take the cached
49.1384 + // one. (If it's not identical, then we'd have to check the
49.1385 + // parent's parents to be consistent with what's been
49.1386 + // requested.)
49.1387 + if (bundle.parent == parent) {
49.1388 + return bundle;
49.1389 + }
49.1390 + // Otherwise, remove the cached one since we can't keep
49.1391 + // the same bundles having different parents.
49.1392 + BundleReference bundleRef = cacheList.get(cacheKey);
49.1393 + if (bundleRef != null && bundleRef.get() == bundle) {
49.1394 + cacheList.remove(cacheKey, bundleRef);
49.1395 + }
49.1396 + }
49.1397 + }
49.1398 +
49.1399 + if (bundle != NONEXISTENT_BUNDLE) {
49.1400 + CacheKey constKey = (CacheKey) cacheKey.clone();
49.1401 +
49.1402 + try {
49.1403 + bundle = loadBundle(cacheKey, formats, control, expiredBundle);
49.1404 + if (bundle != null) {
49.1405 + if (bundle.parent == null) {
49.1406 + bundle.setParent(parent);
49.1407 + }
49.1408 + bundle.locale = targetLocale;
49.1409 + bundle = putBundleInCache(cacheKey, bundle, control);
49.1410 + return bundle;
49.1411 + }
49.1412 +
49.1413 + // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
49.1414 + // instance for the locale.
49.1415 + putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
49.1416 + } finally {
49.1417 + if (constKey.getCause() instanceof InterruptedException) {
49.1418 + Thread.currentThread().interrupt();
49.1419 + }
49.1420 + }
49.1421 + }
49.1422 + return parent;
49.1423 + }
49.1424 +
49.1425 + private static final ResourceBundle loadBundle(CacheKey cacheKey,
49.1426 + List<String> formats,
49.1427 + Control control,
49.1428 + boolean reload) {
49.1429 +
49.1430 + // Here we actually load the bundle in the order of formats
49.1431 + // specified by the getFormats() value.
49.1432 + Locale targetLocale = cacheKey.getLocale();
49.1433 +
49.1434 + ResourceBundle bundle = null;
49.1435 + int size = formats.size();
49.1436 + for (int i = 0; i < size; i++) {
49.1437 + String format = formats.get(i);
49.1438 + try {
49.1439 + bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
49.1440 + cacheKey.getLoader(), reload);
49.1441 + } catch (LinkageError error) {
49.1442 + // We need to handle the LinkageError case due to
49.1443 + // inconsistent case-sensitivity in ClassLoader.
49.1444 + // See 6572242 for details.
49.1445 + cacheKey.setCause(error);
49.1446 + } catch (Exception cause) {
49.1447 + cacheKey.setCause(cause);
49.1448 + }
49.1449 + if (bundle != null) {
49.1450 + // Set the format in the cache key so that it can be
49.1451 + // used when calling needsReload later.
49.1452 + cacheKey.setFormat(format);
49.1453 + bundle.name = cacheKey.getName();
49.1454 + bundle.locale = targetLocale;
49.1455 + // Bundle provider might reuse instances. So we should make
49.1456 + // sure to clear the expired flag here.
49.1457 + bundle.expired = false;
49.1458 + break;
49.1459 + }
49.1460 + }
49.1461 +
49.1462 + return bundle;
49.1463 + }
49.1464 +
49.1465 + private static final boolean isValidBundle(ResourceBundle bundle) {
49.1466 + return bundle != null && bundle != NONEXISTENT_BUNDLE;
49.1467 + }
49.1468 +
49.1469 + /**
49.1470 + * Determines whether any of resource bundles in the parent chain,
49.1471 + * including the leaf, have expired.
49.1472 + */
49.1473 + private static final boolean hasValidParentChain(ResourceBundle bundle) {
49.1474 + long now = System.currentTimeMillis();
49.1475 + while (bundle != null) {
49.1476 + if (bundle.expired) {
49.1477 + return false;
49.1478 + }
49.1479 + CacheKey key = bundle.cacheKey;
49.1480 + if (key != null) {
49.1481 + long expirationTime = key.expirationTime;
49.1482 + if (expirationTime >= 0 && expirationTime <= now) {
49.1483 + return false;
49.1484 + }
49.1485 + }
49.1486 + bundle = bundle.parent;
49.1487 + }
49.1488 + return true;
49.1489 + }
49.1490 +
49.1491 + /**
49.1492 + * Throw a MissingResourceException with proper message
49.1493 + */
49.1494 + private static final void throwMissingResourceException(String baseName,
49.1495 + Locale locale,
49.1496 + Throwable cause) {
49.1497 + // If the cause is a MissingResourceException, avoid creating
49.1498 + // a long chain. (6355009)
49.1499 + if (cause instanceof MissingResourceException) {
49.1500 + cause = null;
49.1501 + }
49.1502 + throw new MissingResourceException("Can't find bundle for base name "
49.1503 + + baseName + ", locale " + locale,
49.1504 + baseName + "_" + locale, // className
49.1505 + "", // key
49.1506 + cause);
49.1507 + }
49.1508 +
49.1509 + /**
49.1510 + * Finds a bundle in the cache. Any expired bundles are marked as
49.1511 + * `expired' and removed from the cache upon return.
49.1512 + *
49.1513 + * @param cacheKey the key to look up the cache
49.1514 + * @param control the Control to be used for the expiration control
49.1515 + * @return the cached bundle, or null if the bundle is not found in the
49.1516 + * cache or its parent has expired. <code>bundle.expire</code> is true
49.1517 + * upon return if the bundle in the cache has expired.
49.1518 + */
49.1519 + private static final ResourceBundle findBundleInCache(CacheKey cacheKey,
49.1520 + Control control) {
49.1521 + BundleReference bundleRef = cacheList.get(cacheKey);
49.1522 + if (bundleRef == null) {
49.1523 + return null;
49.1524 + }
49.1525 + ResourceBundle bundle = bundleRef.get();
49.1526 + if (bundle == null) {
49.1527 + return null;
49.1528 + }
49.1529 + ResourceBundle p = bundle.parent;
49.1530 + assert p != NONEXISTENT_BUNDLE;
49.1531 + // If the parent has expired, then this one must also expire. We
49.1532 + // check only the immediate parent because the actual loading is
49.1533 + // done from the root (base) to leaf (child) and the purpose of
49.1534 + // checking is to propagate expiration towards the leaf. For
49.1535 + // example, if the requested locale is ja_JP_JP and there are
49.1536 + // bundles for all of the candidates in the cache, we have a list,
49.1537 + //
49.1538 + // base <- ja <- ja_JP <- ja_JP_JP
49.1539 + //
49.1540 + // If ja has expired, then it will reload ja and the list becomes a
49.1541 + // tree.
49.1542 + //
49.1543 + // base <- ja (new)
49.1544 + // " <- ja (expired) <- ja_JP <- ja_JP_JP
49.1545 + //
49.1546 + // When looking up ja_JP in the cache, it finds ja_JP in the cache
49.1547 + // which references to the expired ja. Then, ja_JP is marked as
49.1548 + // expired and removed from the cache. This will be propagated to
49.1549 + // ja_JP_JP.
49.1550 + //
49.1551 + // Now, it's possible, for example, that while loading new ja_JP,
49.1552 + // someone else has started loading the same bundle and finds the
49.1553 + // base bundle has expired. Then, what we get from the first
49.1554 + // getBundle call includes the expired base bundle. However, if
49.1555 + // someone else didn't start its loading, we wouldn't know if the
49.1556 + // base bundle has expired at the end of the loading process. The
49.1557 + // expiration control doesn't guarantee that the returned bundle and
49.1558 + // its parents haven't expired.
49.1559 + //
49.1560 + // We could check the entire parent chain to see if there's any in
49.1561 + // the chain that has expired. But this process may never end. An
49.1562 + // extreme case would be that getTimeToLive returns 0 and
49.1563 + // needsReload always returns true.
49.1564 + if (p != null && p.expired) {
49.1565 + assert bundle != NONEXISTENT_BUNDLE;
49.1566 + bundle.expired = true;
49.1567 + bundle.cacheKey = null;
49.1568 + cacheList.remove(cacheKey, bundleRef);
49.1569 + bundle = null;
49.1570 + } else {
49.1571 + CacheKey key = bundleRef.getCacheKey();
49.1572 + long expirationTime = key.expirationTime;
49.1573 + if (!bundle.expired && expirationTime >= 0 &&
49.1574 + expirationTime <= System.currentTimeMillis()) {
49.1575 + // its TTL period has expired.
49.1576 + if (bundle != NONEXISTENT_BUNDLE) {
49.1577 + // Synchronize here to call needsReload to avoid
49.1578 + // redundant concurrent calls for the same bundle.
49.1579 + synchronized (bundle) {
49.1580 + expirationTime = key.expirationTime;
49.1581 + if (!bundle.expired && expirationTime >= 0 &&
49.1582 + expirationTime <= System.currentTimeMillis()) {
49.1583 + try {
49.1584 + bundle.expired = control.needsReload(key.getName(),
49.1585 + key.getLocale(),
49.1586 + key.getFormat(),
49.1587 + key.getLoader(),
49.1588 + bundle,
49.1589 + key.loadTime);
49.1590 + } catch (Exception e) {
49.1591 + cacheKey.setCause(e);
49.1592 + }
49.1593 + if (bundle.expired) {
49.1594 + // If the bundle needs to be reloaded, then
49.1595 + // remove the bundle from the cache, but
49.1596 + // return the bundle with the expired flag
49.1597 + // on.
49.1598 + bundle.cacheKey = null;
49.1599 + cacheList.remove(cacheKey, bundleRef);
49.1600 + } else {
49.1601 + // Update the expiration control info. and reuse
49.1602 + // the same bundle instance
49.1603 + setExpirationTime(key, control);
49.1604 + }
49.1605 + }
49.1606 + }
49.1607 + } else {
49.1608 + // We just remove NONEXISTENT_BUNDLE from the cache.
49.1609 + cacheList.remove(cacheKey, bundleRef);
49.1610 + bundle = null;
49.1611 + }
49.1612 + }
49.1613 + }
49.1614 + return bundle;
49.1615 + }
49.1616 +
49.1617 + /**
49.1618 + * Put a new bundle in the cache.
49.1619 + *
49.1620 + * @param cacheKey the key for the resource bundle
49.1621 + * @param bundle the resource bundle to be put in the cache
49.1622 + * @return the ResourceBundle for the cacheKey; if someone has put
49.1623 + * the bundle before this call, the one found in the cache is
49.1624 + * returned.
49.1625 + */
49.1626 + private static final ResourceBundle putBundleInCache(CacheKey cacheKey,
49.1627 + ResourceBundle bundle,
49.1628 + Control control) {
49.1629 + setExpirationTime(cacheKey, control);
49.1630 + if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
49.1631 + CacheKey key = (CacheKey) cacheKey.clone();
49.1632 + BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
49.1633 + bundle.cacheKey = key;
49.1634 +
49.1635 + // Put the bundle in the cache if it's not been in the cache.
49.1636 + BundleReference result = cacheList.putIfAbsent(key, bundleRef);
49.1637 +
49.1638 + // If someone else has put the same bundle in the cache before
49.1639 + // us and it has not expired, we should use the one in the cache.
49.1640 + if (result != null) {
49.1641 + ResourceBundle rb = result.get();
49.1642 + if (rb != null && !rb.expired) {
49.1643 + // Clear the back link to the cache key
49.1644 + bundle.cacheKey = null;
49.1645 + bundle = rb;
49.1646 + // Clear the reference in the BundleReference so that
49.1647 + // it won't be enqueued.
49.1648 + bundleRef.clear();
49.1649 + } else {
49.1650 + // Replace the invalid (garbage collected or expired)
49.1651 + // instance with the valid one.
49.1652 + cacheList.put(key, bundleRef);
49.1653 + }
49.1654 + }
49.1655 + }
49.1656 + return bundle;
49.1657 + }
49.1658 +
49.1659 + private static final void setExpirationTime(CacheKey cacheKey, Control control) {
49.1660 + long ttl = control.getTimeToLive(cacheKey.getName(),
49.1661 + cacheKey.getLocale());
49.1662 + if (ttl >= 0) {
49.1663 + // If any expiration time is specified, set the time to be
49.1664 + // expired in the cache.
49.1665 + long now = System.currentTimeMillis();
49.1666 + cacheKey.loadTime = now;
49.1667 + cacheKey.expirationTime = now + ttl;
49.1668 + } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
49.1669 + cacheKey.expirationTime = ttl;
49.1670 + } else {
49.1671 + throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
49.1672 + }
49.1673 + }
49.1674 +
49.1675 + /**
49.1676 + * Removes all resource bundles from the cache that have been loaded
49.1677 + * using the caller's class loader.
49.1678 + *
49.1679 + * @since 1.6
49.1680 + * @see ResourceBundle.Control#getTimeToLive(String,Locale)
49.1681 + */
49.1682 + public static final void clearCache() {
49.1683 + clearCache(getLoader());
49.1684 + }
49.1685 +
49.1686 + /**
49.1687 + * Removes all resource bundles from the cache that have been loaded
49.1688 + * using the given class loader.
49.1689 + *
49.1690 + * @param loader the class loader
49.1691 + * @exception NullPointerException if <code>loader</code> is null
49.1692 + * @since 1.6
49.1693 + * @see ResourceBundle.Control#getTimeToLive(String,Locale)
49.1694 + */
49.1695 + public static final void clearCache(ClassLoader loader) {
49.1696 + if (loader == null) {
49.1697 + throw new NullPointerException();
49.1698 + }
49.1699 + Set<CacheKey> set = cacheList.keySet();
49.1700 + for (CacheKey key : set) {
49.1701 + if (key.getLoader() == loader) {
49.1702 + set.remove(key);
49.1703 + }
49.1704 + }
49.1705 + }
49.1706 +
49.1707 + /**
49.1708 + * Gets an object for the given key from this resource bundle.
49.1709 + * Returns null if this resource bundle does not contain an
49.1710 + * object for the given key.
49.1711 + *
49.1712 + * @param key the key for the desired object
49.1713 + * @exception NullPointerException if <code>key</code> is <code>null</code>
49.1714 + * @return the object for the given key, or null
49.1715 + */
49.1716 + protected abstract Object handleGetObject(String key);
49.1717 +
49.1718 + /**
49.1719 + * Returns an enumeration of the keys.
49.1720 + *
49.1721 + * @return an <code>Enumeration</code> of the keys contained in
49.1722 + * this <code>ResourceBundle</code> and its parent bundles.
49.1723 + */
49.1724 + public abstract Enumeration<String> getKeys();
49.1725 +
49.1726 + /**
49.1727 + * Determines whether the given <code>key</code> is contained in
49.1728 + * this <code>ResourceBundle</code> or its parent bundles.
49.1729 + *
49.1730 + * @param key
49.1731 + * the resource <code>key</code>
49.1732 + * @return <code>true</code> if the given <code>key</code> is
49.1733 + * contained in this <code>ResourceBundle</code> or its
49.1734 + * parent bundles; <code>false</code> otherwise.
49.1735 + * @exception NullPointerException
49.1736 + * if <code>key</code> is <code>null</code>
49.1737 + * @since 1.6
49.1738 + */
49.1739 + public boolean containsKey(String key) {
49.1740 + if (key == null) {
49.1741 + throw new NullPointerException();
49.1742 + }
49.1743 + for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
49.1744 + if (rb.handleKeySet().contains(key)) {
49.1745 + return true;
49.1746 + }
49.1747 + }
49.1748 + return false;
49.1749 + }
49.1750 +
49.1751 + /**
49.1752 + * Returns a <code>Set</code> of all keys contained in this
49.1753 + * <code>ResourceBundle</code> and its parent bundles.
49.1754 + *
49.1755 + * @return a <code>Set</code> of all keys contained in this
49.1756 + * <code>ResourceBundle</code> and its parent bundles.
49.1757 + * @since 1.6
49.1758 + */
49.1759 + public Set<String> keySet() {
49.1760 + Set<String> keys = new HashSet<>();
49.1761 + for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
49.1762 + keys.addAll(rb.handleKeySet());
49.1763 + }
49.1764 + return keys;
49.1765 + }
49.1766 +
49.1767 + /**
49.1768 + * Returns a <code>Set</code> of the keys contained <em>only</em>
49.1769 + * in this <code>ResourceBundle</code>.
49.1770 + *
49.1771 + * <p>The default implementation returns a <code>Set</code> of the
49.1772 + * keys returned by the {@link #getKeys() getKeys} method except
49.1773 + * for the ones for which the {@link #handleGetObject(String)
49.1774 + * handleGetObject} method returns <code>null</code>. Once the
49.1775 + * <code>Set</code> has been created, the value is kept in this
49.1776 + * <code>ResourceBundle</code> in order to avoid producing the
49.1777 + * same <code>Set</code> in subsequent calls. Subclasses can
49.1778 + * override this method for faster handling.
49.1779 + *
49.1780 + * @return a <code>Set</code> of the keys contained only in this
49.1781 + * <code>ResourceBundle</code>
49.1782 + * @since 1.6
49.1783 + */
49.1784 + protected Set<String> handleKeySet() {
49.1785 + if (keySet == null) {
49.1786 + synchronized (this) {
49.1787 + if (keySet == null) {
49.1788 + Set<String> keys = new HashSet<>();
49.1789 + Enumeration<String> enumKeys = getKeys();
49.1790 + while (enumKeys.hasMoreElements()) {
49.1791 + String key = enumKeys.nextElement();
49.1792 + if (handleGetObject(key) != null) {
49.1793 + keys.add(key);
49.1794 + }
49.1795 + }
49.1796 + keySet = keys;
49.1797 + }
49.1798 + }
49.1799 + }
49.1800 + return keySet;
49.1801 + }
49.1802 +
49.1803 +
49.1804 +
49.1805 + /**
49.1806 + * <code>ResourceBundle.Control</code> defines a set of callback methods
49.1807 + * that are invoked by the {@link ResourceBundle#getBundle(String,
49.1808 + * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
49.1809 + * methods during the bundle loading process. In other words, a
49.1810 + * <code>ResourceBundle.Control</code> collaborates with the factory
49.1811 + * methods for loading resource bundles. The default implementation of
49.1812 + * the callback methods provides the information necessary for the
49.1813 + * factory methods to perform the <a
49.1814 + * href="./ResourceBundle.html#default_behavior">default behavior</a>.
49.1815 + *
49.1816 + * <p>In addition to the callback methods, the {@link
49.1817 + * #toBundleName(String, Locale) toBundleName} and {@link
49.1818 + * #toResourceName(String, String) toResourceName} methods are defined
49.1819 + * primarily for convenience in implementing the callback
49.1820 + * methods. However, the <code>toBundleName</code> method could be
49.1821 + * overridden to provide different conventions in the organization and
49.1822 + * packaging of localized resources. The <code>toResourceName</code>
49.1823 + * method is <code>final</code> to avoid use of wrong resource and class
49.1824 + * name separators.
49.1825 + *
49.1826 + * <p>Two factory methods, {@link #getControl(List)} and {@link
49.1827 + * #getNoFallbackControl(List)}, provide
49.1828 + * <code>ResourceBundle.Control</code> instances that implement common
49.1829 + * variations of the default bundle loading process.
49.1830 + *
49.1831 + * <p>The formats returned by the {@link Control#getFormats(String)
49.1832 + * getFormats} method and candidate locales returned by the {@link
49.1833 + * ResourceBundle.Control#getCandidateLocales(String, Locale)
49.1834 + * getCandidateLocales} method must be consistent in all
49.1835 + * <code>ResourceBundle.getBundle</code> invocations for the same base
49.1836 + * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
49.1837 + * may return unintended bundles. For example, if only
49.1838 + * <code>"java.class"</code> is returned by the <code>getFormats</code>
49.1839 + * method for the first call to <code>ResourceBundle.getBundle</code>
49.1840 + * and only <code>"java.properties"</code> for the second call, then the
49.1841 + * second call will return the class-based one that has been cached
49.1842 + * during the first call.
49.1843 + *
49.1844 + * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
49.1845 + * if it's simultaneously used by multiple threads.
49.1846 + * <code>ResourceBundle.getBundle</code> does not synchronize to call
49.1847 + * the <code>ResourceBundle.Control</code> methods. The default
49.1848 + * implementations of the methods are thread-safe.
49.1849 + *
49.1850 + * <p>Applications can specify <code>ResourceBundle.Control</code>
49.1851 + * instances returned by the <code>getControl</code> factory methods or
49.1852 + * created from a subclass of <code>ResourceBundle.Control</code> to
49.1853 + * customize the bundle loading process. The following are examples of
49.1854 + * changing the default bundle loading process.
49.1855 + *
49.1856 + * <p><b>Example 1</b>
49.1857 + *
49.1858 + * <p>The following code lets <code>ResourceBundle.getBundle</code> look
49.1859 + * up only properties-based resources.
49.1860 + *
49.1861 + * <pre>
49.1862 + * import java.util.*;
49.1863 + * import static java.util.ResourceBundle.Control.*;
49.1864 + * ...
49.1865 + * ResourceBundle bundle =
49.1866 + * ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
49.1867 + * ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
49.1868 + * </pre>
49.1869 + *
49.1870 + * Given the resource bundles in the <a
49.1871 + * href="./ResourceBundle.html#default_behavior_example">example</a> in
49.1872 + * the <code>ResourceBundle.getBundle</code> description, this
49.1873 + * <code>ResourceBundle.getBundle</code> call loads
49.1874 + * <code>MyResources_fr_CH.properties</code> whose parent is
49.1875 + * <code>MyResources_fr.properties</code> whose parent is
49.1876 + * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
49.1877 + * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
49.1878 + *
49.1879 + * <p><b>Example 2</b>
49.1880 + *
49.1881 + * <p>The following is an example of loading XML-based bundles
49.1882 + * using {@link Properties#loadFromXML(java.io.InputStream)
49.1883 + * Properties.loadFromXML}.
49.1884 + *
49.1885 + * <pre>
49.1886 + * ResourceBundle rb = ResourceBundle.getBundle("Messages",
49.1887 + * new ResourceBundle.Control() {
49.1888 + * public List<String> getFormats(String baseName) {
49.1889 + * if (baseName == null)
49.1890 + * throw new NullPointerException();
49.1891 + * return Arrays.asList("xml");
49.1892 + * }
49.1893 + * public ResourceBundle newBundle(String baseName,
49.1894 + * Locale locale,
49.1895 + * String format,
49.1896 + * ClassLoader loader,
49.1897 + * boolean reload)
49.1898 + * throws IllegalAccessException,
49.1899 + * InstantiationException,
49.1900 + * IOException {
49.1901 + * if (baseName == null || locale == null
49.1902 + * || format == null || loader == null)
49.1903 + * throw new NullPointerException();
49.1904 + * ResourceBundle bundle = null;
49.1905 + * if (format.equals("xml")) {
49.1906 + * String bundleName = toBundleName(baseName, locale);
49.1907 + * String resourceName = toResourceName(bundleName, format);
49.1908 + * InputStream stream = null;
49.1909 + * if (reload) {
49.1910 + * URL url = loader.getResource(resourceName);
49.1911 + * if (url != null) {
49.1912 + * URLConnection connection = url.openConnection();
49.1913 + * if (connection != null) {
49.1914 + * // Disable caches to get fresh data for
49.1915 + * // reloading.
49.1916 + * connection.setUseCaches(false);
49.1917 + * stream = connection.getInputStream();
49.1918 + * }
49.1919 + * }
49.1920 + * } else {
49.1921 + * stream = loader.getResourceAsStream(resourceName);
49.1922 + * }
49.1923 + * if (stream != null) {
49.1924 + * BufferedInputStream bis = new BufferedInputStream(stream);
49.1925 + * bundle = new XMLResourceBundle(bis);
49.1926 + * bis.close();
49.1927 + * }
49.1928 + * }
49.1929 + * return bundle;
49.1930 + * }
49.1931 + * });
49.1932 + *
49.1933 + * ...
49.1934 + *
49.1935 + * private static class XMLResourceBundle extends ResourceBundle {
49.1936 + * private Properties props;
49.1937 + * XMLResourceBundle(InputStream stream) throws IOException {
49.1938 + * props = new Properties();
49.1939 + * props.loadFromXML(stream);
49.1940 + * }
49.1941 + * protected Object handleGetObject(String key) {
49.1942 + * return props.getProperty(key);
49.1943 + * }
49.1944 + * public Enumeration<String> getKeys() {
49.1945 + * ...
49.1946 + * }
49.1947 + * }
49.1948 + * </pre>
49.1949 + *
49.1950 + * @since 1.6
49.1951 + */
49.1952 + public static class Control {
49.1953 + /**
49.1954 + * The default format <code>List</code>, which contains the strings
49.1955 + * <code>"java.class"</code> and <code>"java.properties"</code>, in
49.1956 + * this order. This <code>List</code> is {@linkplain
49.1957 + * Collections#unmodifiableList(List) unmodifiable}.
49.1958 + *
49.1959 + * @see #getFormats(String)
49.1960 + */
49.1961 + public static final List<String> FORMAT_DEFAULT
49.1962 + = Collections.unmodifiableList(Arrays.asList("java.class",
49.1963 + "java.properties"));
49.1964 +
49.1965 + /**
49.1966 + * The class-only format <code>List</code> containing
49.1967 + * <code>"java.class"</code>. This <code>List</code> is {@linkplain
49.1968 + * Collections#unmodifiableList(List) unmodifiable}.
49.1969 + *
49.1970 + * @see #getFormats(String)
49.1971 + */
49.1972 + public static final List<String> FORMAT_CLASS
49.1973 + = Collections.unmodifiableList(Arrays.asList("java.class"));
49.1974 +
49.1975 + /**
49.1976 + * The properties-only format <code>List</code> containing
49.1977 + * <code>"java.properties"</code>. This <code>List</code> is
49.1978 + * {@linkplain Collections#unmodifiableList(List) unmodifiable}.
49.1979 + *
49.1980 + * @see #getFormats(String)
49.1981 + */
49.1982 + public static final List<String> FORMAT_PROPERTIES
49.1983 + = Collections.unmodifiableList(Arrays.asList("java.properties"));
49.1984 +
49.1985 + /**
49.1986 + * The time-to-live constant for not caching loaded resource bundle
49.1987 + * instances.
49.1988 + *
49.1989 + * @see #getTimeToLive(String, Locale)
49.1990 + */
49.1991 + public static final long TTL_DONT_CACHE = -1;
49.1992 +
49.1993 + /**
49.1994 + * The time-to-live constant for disabling the expiration control
49.1995 + * for loaded resource bundle instances in the cache.
49.1996 + *
49.1997 + * @see #getTimeToLive(String, Locale)
49.1998 + */
49.1999 + public static final long TTL_NO_EXPIRATION_CONTROL = -2;
49.2000 +
49.2001 + private static final Control INSTANCE = new Control();
49.2002 +
49.2003 + /**
49.2004 + * Sole constructor. (For invocation by subclass constructors,
49.2005 + * typically implicit.)
49.2006 + */
49.2007 + protected Control() {
49.2008 + }
49.2009 +
49.2010 + /**
49.2011 + * Returns a <code>ResourceBundle.Control</code> in which the {@link
49.2012 + * #getFormats(String) getFormats} method returns the specified
49.2013 + * <code>formats</code>. The <code>formats</code> must be equal to
49.2014 + * one of {@link Control#FORMAT_PROPERTIES}, {@link
49.2015 + * Control#FORMAT_CLASS} or {@link
49.2016 + * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
49.2017 + * instances returned by this method are singletons and thread-safe.
49.2018 + *
49.2019 + * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
49.2020 + * instantiating the <code>ResourceBundle.Control</code> class,
49.2021 + * except that this method returns a singleton.
49.2022 + *
49.2023 + * @param formats
49.2024 + * the formats to be returned by the
49.2025 + * <code>ResourceBundle.Control.getFormats</code> method
49.2026 + * @return a <code>ResourceBundle.Control</code> supporting the
49.2027 + * specified <code>formats</code>
49.2028 + * @exception NullPointerException
49.2029 + * if <code>formats</code> is <code>null</code>
49.2030 + * @exception IllegalArgumentException
49.2031 + * if <code>formats</code> is unknown
49.2032 + */
49.2033 + public static final Control getControl(List<String> formats) {
49.2034 + if (formats.equals(Control.FORMAT_PROPERTIES)) {
49.2035 + return SingleFormatControl.PROPERTIES_ONLY;
49.2036 + }
49.2037 + if (formats.equals(Control.FORMAT_CLASS)) {
49.2038 + return SingleFormatControl.CLASS_ONLY;
49.2039 + }
49.2040 + if (formats.equals(Control.FORMAT_DEFAULT)) {
49.2041 + return Control.INSTANCE;
49.2042 + }
49.2043 + throw new IllegalArgumentException();
49.2044 + }
49.2045 +
49.2046 + /**
49.2047 + * Returns a <code>ResourceBundle.Control</code> in which the {@link
49.2048 + * #getFormats(String) getFormats} method returns the specified
49.2049 + * <code>formats</code> and the {@link
49.2050 + * Control#getFallbackLocale(String, Locale) getFallbackLocale}
49.2051 + * method returns <code>null</code>. The <code>formats</code> must
49.2052 + * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
49.2053 + * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
49.2054 + * <code>ResourceBundle.Control</code> instances returned by this
49.2055 + * method are singletons and thread-safe.
49.2056 + *
49.2057 + * @param formats
49.2058 + * the formats to be returned by the
49.2059 + * <code>ResourceBundle.Control.getFormats</code> method
49.2060 + * @return a <code>ResourceBundle.Control</code> supporting the
49.2061 + * specified <code>formats</code> with no fallback
49.2062 + * <code>Locale</code> support
49.2063 + * @exception NullPointerException
49.2064 + * if <code>formats</code> is <code>null</code>
49.2065 + * @exception IllegalArgumentException
49.2066 + * if <code>formats</code> is unknown
49.2067 + */
49.2068 + public static final Control getNoFallbackControl(List<String> formats) {
49.2069 + if (formats.equals(Control.FORMAT_DEFAULT)) {
49.2070 + return NoFallbackControl.NO_FALLBACK;
49.2071 + }
49.2072 + if (formats.equals(Control.FORMAT_PROPERTIES)) {
49.2073 + return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
49.2074 + }
49.2075 + if (formats.equals(Control.FORMAT_CLASS)) {
49.2076 + return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
49.2077 + }
49.2078 + throw new IllegalArgumentException();
49.2079 + }
49.2080 +
49.2081 + /**
49.2082 + * Returns a <code>List</code> of <code>String</code>s containing
49.2083 + * formats to be used to load resource bundles for the given
49.2084 + * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
49.2085 + * factory method tries to load resource bundles with formats in the
49.2086 + * order specified by the list. The list returned by this method
49.2087 + * must have at least one <code>String</code>. The predefined
49.2088 + * formats are <code>"java.class"</code> for class-based resource
49.2089 + * bundles and <code>"java.properties"</code> for {@linkplain
49.2090 + * PropertyResourceBundle properties-based} ones. Strings starting
49.2091 + * with <code>"java."</code> are reserved for future extensions and
49.2092 + * must not be used by application-defined formats.
49.2093 + *
49.2094 + * <p>It is not a requirement to return an immutable (unmodifiable)
49.2095 + * <code>List</code>. However, the returned <code>List</code> must
49.2096 + * not be mutated after it has been returned by
49.2097 + * <code>getFormats</code>.
49.2098 + *
49.2099 + * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
49.2100 + * that the <code>ResourceBundle.getBundle</code> factory method
49.2101 + * looks up first class-based resource bundles, then
49.2102 + * properties-based ones.
49.2103 + *
49.2104 + * @param baseName
49.2105 + * the base name of the resource bundle, a fully qualified class
49.2106 + * name
49.2107 + * @return a <code>List</code> of <code>String</code>s containing
49.2108 + * formats for loading resource bundles.
49.2109 + * @exception NullPointerException
49.2110 + * if <code>baseName</code> is null
49.2111 + * @see #FORMAT_DEFAULT
49.2112 + * @see #FORMAT_CLASS
49.2113 + * @see #FORMAT_PROPERTIES
49.2114 + */
49.2115 + public List<String> getFormats(String baseName) {
49.2116 + if (baseName == null) {
49.2117 + throw new NullPointerException();
49.2118 + }
49.2119 + return FORMAT_DEFAULT;
49.2120 + }
49.2121 +
49.2122 + /**
49.2123 + * Returns a <code>List</code> of <code>Locale</code>s as candidate
49.2124 + * locales for <code>baseName</code> and <code>locale</code>. This
49.2125 + * method is called by the <code>ResourceBundle.getBundle</code>
49.2126 + * factory method each time the factory method tries finding a
49.2127 + * resource bundle for a target <code>Locale</code>.
49.2128 + *
49.2129 + * <p>The sequence of the candidate locales also corresponds to the
49.2130 + * runtime resource lookup path (also known as the <I>parent
49.2131 + * chain</I>), if the corresponding resource bundles for the
49.2132 + * candidate locales exist and their parents are not defined by
49.2133 + * loaded resource bundles themselves. The last element of the list
49.2134 + * must be a {@linkplain Locale#ROOT root locale} if it is desired to
49.2135 + * have the base bundle as the terminal of the parent chain.
49.2136 + *
49.2137 + * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
49.2138 + * root locale), a <code>List</code> containing only the root
49.2139 + * <code>Locale</code> must be returned. In this case, the
49.2140 + * <code>ResourceBundle.getBundle</code> factory method loads only
49.2141 + * the base bundle as the resulting resource bundle.
49.2142 + *
49.2143 + * <p>It is not a requirement to return an immutable (unmodifiable)
49.2144 + * <code>List</code>. However, the returned <code>List</code> must not
49.2145 + * be mutated after it has been returned by
49.2146 + * <code>getCandidateLocales</code>.
49.2147 + *
49.2148 + * <p>The default implementation returns a <code>List</code> containing
49.2149 + * <code>Locale</code>s using the rules described below. In the
49.2150 + * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
49.2151 + * respectively represent non-empty language, script, country, and
49.2152 + * variant. For example, [<em>L</em>, <em>C</em>] represents a
49.2153 + * <code>Locale</code> that has non-empty values only for language and
49.2154 + * country. The form <em>L</em>("xx") represents the (non-empty)
49.2155 + * language value is "xx". For all cases, <code>Locale</code>s whose
49.2156 + * final component values are empty strings are omitted.
49.2157 + *
49.2158 + * <ol><li>For an input <code>Locale</code> with an empty script value,
49.2159 + * append candidate <code>Locale</code>s by omitting the final component
49.2160 + * one by one as below:
49.2161 + *
49.2162 + * <ul>
49.2163 + * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
49.2164 + * <li> [<em>L</em>, <em>C</em>]
49.2165 + * <li> [<em>L</em>]
49.2166 + * <li> <code>Locale.ROOT</code>
49.2167 + * </ul>
49.2168 + *
49.2169 + * <li>For an input <code>Locale</code> with a non-empty script value,
49.2170 + * append candidate <code>Locale</code>s by omitting the final component
49.2171 + * up to language, then append candidates generated from the
49.2172 + * <code>Locale</code> with country and variant restored:
49.2173 + *
49.2174 + * <ul>
49.2175 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
49.2176 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
49.2177 + * <li> [<em>L</em>, <em>S</em>]
49.2178 + * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
49.2179 + * <li> [<em>L</em>, <em>C</em>]
49.2180 + * <li> [<em>L</em>]
49.2181 + * <li> <code>Locale.ROOT</code>
49.2182 + * </ul>
49.2183 + *
49.2184 + * <li>For an input <code>Locale</code> with a variant value consisting
49.2185 + * of multiple subtags separated by underscore, generate candidate
49.2186 + * <code>Locale</code>s by omitting the variant subtags one by one, then
49.2187 + * insert them after every occurence of <code> Locale</code>s with the
49.2188 + * full variant value in the original list. For example, if the
49.2189 + * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
49.2190 + *
49.2191 + * <ul>
49.2192 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
49.2193 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
49.2194 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
49.2195 + * <li> [<em>L</em>, <em>S</em>]
49.2196 + * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
49.2197 + * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
49.2198 + * <li> [<em>L</em>, <em>C</em>]
49.2199 + * <li> [<em>L</em>]
49.2200 + * <li> <code>Locale.ROOT</code>
49.2201 + * </ul>
49.2202 + *
49.2203 + * <li>Special cases for Chinese. When an input <code>Locale</code> has the
49.2204 + * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
49.2205 + * "Hant" (Traditional) might be supplied, depending on the country.
49.2206 + * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
49.2207 + * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
49.2208 + * or "TW" (Taiwan), "Hant" is supplied. For all other countries or when the country
49.2209 + * is empty, no script is supplied. For example, for <code>Locale("zh", "CN")
49.2210 + * </code>, the candidate list will be:
49.2211 + * <ul>
49.2212 + * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
49.2213 + * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
49.2214 + * <li> [<em>L</em>("zh"), <em>C</em>("CN")]
49.2215 + * <li> [<em>L</em>("zh")]
49.2216 + * <li> <code>Locale.ROOT</code>
49.2217 + * </ul>
49.2218 + *
49.2219 + * For <code>Locale("zh", "TW")</code>, the candidate list will be:
49.2220 + * <ul>
49.2221 + * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
49.2222 + * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
49.2223 + * <li> [<em>L</em>("zh"), <em>C</em>("TW")]
49.2224 + * <li> [<em>L</em>("zh")]
49.2225 + * <li> <code>Locale.ROOT</code>
49.2226 + * </ul>
49.2227 + *
49.2228 + * <li>Special cases for Norwegian. Both <code>Locale("no", "NO",
49.2229 + * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
49.2230 + * Nynorsk. When a locale's language is "nn", the standard candidate
49.2231 + * list is generated up to [<em>L</em>("nn")], and then the following
49.2232 + * candidates are added:
49.2233 + *
49.2234 + * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
49.2235 + * <li> [<em>L</em>("no"), <em>C</em>("NO")]
49.2236 + * <li> [<em>L</em>("no")]
49.2237 + * <li> <code>Locale.ROOT</code>
49.2238 + * </ul>
49.2239 + *
49.2240 + * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
49.2241 + * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
49.2242 + * followed.
49.2243 + *
49.2244 + * <p>Also, Java treats the language "no" as a synonym of Norwegian
49.2245 + * Bokmål "nb". Except for the single case <code>Locale("no",
49.2246 + * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
49.2247 + * has language "no" or "nb", candidate <code>Locale</code>s with
49.2248 + * language code "no" and "nb" are interleaved, first using the
49.2249 + * requested language, then using its synonym. For example,
49.2250 + * <code>Locale("nb", "NO", "POSIX")</code> generates the following
49.2251 + * candidate list:
49.2252 + *
49.2253 + * <ul>
49.2254 + * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
49.2255 + * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
49.2256 + * <li> [<em>L</em>("nb"), <em>C</em>("NO")]
49.2257 + * <li> [<em>L</em>("no"), <em>C</em>("NO")]
49.2258 + * <li> [<em>L</em>("nb")]
49.2259 + * <li> [<em>L</em>("no")]
49.2260 + * <li> <code>Locale.ROOT</code>
49.2261 + * </ul>
49.2262 + *
49.2263 + * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
49.2264 + * except that locales with "no" would appear before the corresponding
49.2265 + * locales with "nb".</li>
49.2266 + *
49.2267 + * </li>
49.2268 + * </ol>
49.2269 + *
49.2270 + * <p>The default implementation uses an {@link ArrayList} that
49.2271 + * overriding implementations may modify before returning it to the
49.2272 + * caller. However, a subclass must not modify it after it has
49.2273 + * been returned by <code>getCandidateLocales</code>.
49.2274 + *
49.2275 + * <p>For example, if the given <code>baseName</code> is "Messages"
49.2276 + * and the given <code>locale</code> is
49.2277 + * <code>Locale("ja", "", "XX")</code>, then a
49.2278 + * <code>List</code> of <code>Locale</code>s:
49.2279 + * <pre>
49.2280 + * Locale("ja", "", "XX")
49.2281 + * Locale("ja")
49.2282 + * Locale.ROOT
49.2283 + * </pre>
49.2284 + * is returned. And if the resource bundles for the "ja" and
49.2285 + * "" <code>Locale</code>s are found, then the runtime resource
49.2286 + * lookup path (parent chain) is:
49.2287 + * <pre>
49.2288 + * Messages_ja -> Messages
49.2289 + * </pre>
49.2290 + *
49.2291 + * @param baseName
49.2292 + * the base name of the resource bundle, a fully
49.2293 + * qualified class name
49.2294 + * @param locale
49.2295 + * the locale for which a resource bundle is desired
49.2296 + * @return a <code>List</code> of candidate
49.2297 + * <code>Locale</code>s for the given <code>locale</code>
49.2298 + * @exception NullPointerException
49.2299 + * if <code>baseName</code> or <code>locale</code> is
49.2300 + * <code>null</code>
49.2301 + */
49.2302 + public List<Locale> getCandidateLocales(String baseName, Locale locale) {
49.2303 + if (baseName == null) {
49.2304 + throw new NullPointerException();
49.2305 + }
49.2306 + return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
49.2307 + }
49.2308 +
49.2309 + private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
49.2310 +
49.2311 + private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
49.2312 + protected List<Locale> createObject(BaseLocale base) {
49.2313 + String language = base.getLanguage();
49.2314 + String script = base.getScript();
49.2315 + String region = base.getRegion();
49.2316 + String variant = base.getVariant();
49.2317 +
49.2318 + // Special handling for Norwegian
49.2319 + boolean isNorwegianBokmal = false;
49.2320 + boolean isNorwegianNynorsk = false;
49.2321 + if (language.equals("no")) {
49.2322 + if (region.equals("NO") && variant.equals("NY")) {
49.2323 + variant = "";
49.2324 + isNorwegianNynorsk = true;
49.2325 + } else {
49.2326 + isNorwegianBokmal = true;
49.2327 + }
49.2328 + }
49.2329 + if (language.equals("nb") || isNorwegianBokmal) {
49.2330 + List<Locale> tmpList = getDefaultList("nb", script, region, variant);
49.2331 + // Insert a locale replacing "nb" with "no" for every list entry
49.2332 + List<Locale> bokmalList = new LinkedList<>();
49.2333 + for (Locale l : tmpList) {
49.2334 + bokmalList.add(l);
49.2335 + if (l.getLanguage().length() == 0) {
49.2336 + break;
49.2337 + }
49.2338 + bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
49.2339 + l.getVariant(), null));
49.2340 + }
49.2341 + return bokmalList;
49.2342 + } else if (language.equals("nn") || isNorwegianNynorsk) {
49.2343 + // Insert no_NO_NY, no_NO, no after nn
49.2344 + List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
49.2345 + int idx = nynorskList.size() - 1;
49.2346 + nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
49.2347 + nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
49.2348 + nynorskList.add(idx++, Locale.getInstance("no", "", ""));
49.2349 + return nynorskList;
49.2350 + }
49.2351 + // Special handling for Chinese
49.2352 + else if (language.equals("zh")) {
49.2353 + if (script.length() == 0 && region.length() > 0) {
49.2354 + // Supply script for users who want to use zh_Hans/zh_Hant
49.2355 + // as bundle names (recommended for Java7+)
49.2356 + if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
49.2357 + script = "Hant";
49.2358 + } else if (region.equals("CN") || region.equals("SG")) {
49.2359 + script = "Hans";
49.2360 + }
49.2361 + } else if (script.length() > 0 && region.length() == 0) {
49.2362 + // Supply region(country) for users who still package Chinese
49.2363 + // bundles using old convension.
49.2364 + if (script.equals("Hans")) {
49.2365 + region = "CN";
49.2366 + } else if (script.equals("Hant")) {
49.2367 + region = "TW";
49.2368 + }
49.2369 + }
49.2370 + }
49.2371 +
49.2372 + return getDefaultList(language, script, region, variant);
49.2373 + }
49.2374 +
49.2375 + private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
49.2376 + List<String> variants = null;
49.2377 +
49.2378 + if (variant.length() > 0) {
49.2379 + variants = new LinkedList<>();
49.2380 + int idx = variant.length();
49.2381 + while (idx != -1) {
49.2382 + variants.add(variant.substring(0, idx));
49.2383 + idx = variant.lastIndexOf('_', --idx);
49.2384 + }
49.2385 + }
49.2386 +
49.2387 + List<Locale> list = new LinkedList<>();
49.2388 +
49.2389 + if (variants != null) {
49.2390 + for (String v : variants) {
49.2391 + list.add(Locale.getInstance(language, script, region, v, null));
49.2392 + }
49.2393 + }
49.2394 + if (region.length() > 0) {
49.2395 + list.add(Locale.getInstance(language, script, region, "", null));
49.2396 + }
49.2397 + if (script.length() > 0) {
49.2398 + list.add(Locale.getInstance(language, script, "", "", null));
49.2399 +
49.2400 + // With script, after truncating variant, region and script,
49.2401 + // start over without script.
49.2402 + if (variants != null) {
49.2403 + for (String v : variants) {
49.2404 + list.add(Locale.getInstance(language, "", region, v, null));
49.2405 + }
49.2406 + }
49.2407 + if (region.length() > 0) {
49.2408 + list.add(Locale.getInstance(language, "", region, "", null));
49.2409 + }
49.2410 + }
49.2411 + if (language.length() > 0) {
49.2412 + list.add(Locale.getInstance(language, "", "", "", null));
49.2413 + }
49.2414 + // Add root locale at the end
49.2415 + list.add(Locale.ROOT);
49.2416 +
49.2417 + return list;
49.2418 + }
49.2419 + }
49.2420 +
49.2421 + /**
49.2422 + * Returns a <code>Locale</code> to be used as a fallback locale for
49.2423 + * further resource bundle searches by the
49.2424 + * <code>ResourceBundle.getBundle</code> factory method. This method
49.2425 + * is called from the factory method every time when no resulting
49.2426 + * resource bundle has been found for <code>baseName</code> and
49.2427 + * <code>locale</code>, where locale is either the parameter for
49.2428 + * <code>ResourceBundle.getBundle</code> or the previous fallback
49.2429 + * locale returned by this method.
49.2430 + *
49.2431 + * <p>The method returns <code>null</code> if no further fallback
49.2432 + * search is desired.
49.2433 + *
49.2434 + * <p>The default implementation returns the {@linkplain
49.2435 + * Locale#getDefault() default <code>Locale</code>} if the given
49.2436 + * <code>locale</code> isn't the default one. Otherwise,
49.2437 + * <code>null</code> is returned.
49.2438 + *
49.2439 + * @param baseName
49.2440 + * the base name of the resource bundle, a fully
49.2441 + * qualified class name for which
49.2442 + * <code>ResourceBundle.getBundle</code> has been
49.2443 + * unable to find any resource bundles (except for the
49.2444 + * base bundle)
49.2445 + * @param locale
49.2446 + * the <code>Locale</code> for which
49.2447 + * <code>ResourceBundle.getBundle</code> has been
49.2448 + * unable to find any resource bundles (except for the
49.2449 + * base bundle)
49.2450 + * @return a <code>Locale</code> for the fallback search,
49.2451 + * or <code>null</code> if no further fallback search
49.2452 + * is desired.
49.2453 + * @exception NullPointerException
49.2454 + * if <code>baseName</code> or <code>locale</code>
49.2455 + * is <code>null</code>
49.2456 + */
49.2457 + public Locale getFallbackLocale(String baseName, Locale locale) {
49.2458 + if (baseName == null) {
49.2459 + throw new NullPointerException();
49.2460 + }
49.2461 + Locale defaultLocale = Locale.getDefault();
49.2462 + return locale.equals(defaultLocale) ? null : defaultLocale;
49.2463 + }
49.2464 +
49.2465 + /**
49.2466 + * Instantiates a resource bundle for the given bundle name of the
49.2467 + * given format and locale, using the given class loader if
49.2468 + * necessary. This method returns <code>null</code> if there is no
49.2469 + * resource bundle available for the given parameters. If a resource
49.2470 + * bundle can't be instantiated due to an unexpected error, the
49.2471 + * error must be reported by throwing an <code>Error</code> or
49.2472 + * <code>Exception</code> rather than simply returning
49.2473 + * <code>null</code>.
49.2474 + *
49.2475 + * <p>If the <code>reload</code> flag is <code>true</code>, it
49.2476 + * indicates that this method is being called because the previously
49.2477 + * loaded resource bundle has expired.
49.2478 + *
49.2479 + * <p>The default implementation instantiates a
49.2480 + * <code>ResourceBundle</code> as follows.
49.2481 + *
49.2482 + * <ul>
49.2483 + *
49.2484 + * <li>The bundle name is obtained by calling {@link
49.2485 + * #toBundleName(String, Locale) toBundleName(baseName,
49.2486 + * locale)}.</li>
49.2487 + *
49.2488 + * <li>If <code>format</code> is <code>"java.class"</code>, the
49.2489 + * {@link Class} specified by the bundle name is loaded by calling
49.2490 + * {@link ClassLoader#loadClass(String)}. Then, a
49.2491 + * <code>ResourceBundle</code> is instantiated by calling {@link
49.2492 + * Class#newInstance()}. Note that the <code>reload</code> flag is
49.2493 + * ignored for loading class-based resource bundles in this default
49.2494 + * implementation.</li>
49.2495 + *
49.2496 + * <li>If <code>format</code> is <code>"java.properties"</code>,
49.2497 + * {@link #toResourceName(String, String) toResourceName(bundlename,
49.2498 + * "properties")} is called to get the resource name.
49.2499 + * If <code>reload</code> is <code>true</code>, {@link
49.2500 + * ClassLoader#getResource(String) load.getResource} is called
49.2501 + * to get a {@link URL} for creating a {@link
49.2502 + * URLConnection}. This <code>URLConnection</code> is used to
49.2503 + * {@linkplain URLConnection#setUseCaches(boolean) disable the
49.2504 + * caches} of the underlying resource loading layers,
49.2505 + * and to {@linkplain URLConnection#getInputStream() get an
49.2506 + * <code>InputStream</code>}.
49.2507 + * Otherwise, {@link ClassLoader#getResourceAsStream(String)
49.2508 + * loader.getResourceAsStream} is called to get an {@link
49.2509 + * InputStream}. Then, a {@link
49.2510 + * PropertyResourceBundle} is constructed with the
49.2511 + * <code>InputStream</code>.</li>
49.2512 + *
49.2513 + * <li>If <code>format</code> is neither <code>"java.class"</code>
49.2514 + * nor <code>"java.properties"</code>, an
49.2515 + * <code>IllegalArgumentException</code> is thrown.</li>
49.2516 + *
49.2517 + * </ul>
49.2518 + *
49.2519 + * @param baseName
49.2520 + * the base bundle name of the resource bundle, a fully
49.2521 + * qualified class name
49.2522 + * @param locale
49.2523 + * the locale for which the resource bundle should be
49.2524 + * instantiated
49.2525 + * @param format
49.2526 + * the resource bundle format to be loaded
49.2527 + * @param loader
49.2528 + * the <code>ClassLoader</code> to use to load the bundle
49.2529 + * @param reload
49.2530 + * the flag to indicate bundle reloading; <code>true</code>
49.2531 + * if reloading an expired resource bundle,
49.2532 + * <code>false</code> otherwise
49.2533 + * @return the resource bundle instance,
49.2534 + * or <code>null</code> if none could be found.
49.2535 + * @exception NullPointerException
49.2536 + * if <code>bundleName</code>, <code>locale</code>,
49.2537 + * <code>format</code>, or <code>loader</code> is
49.2538 + * <code>null</code>, or if <code>null</code> is returned by
49.2539 + * {@link #toBundleName(String, Locale) toBundleName}
49.2540 + * @exception IllegalArgumentException
49.2541 + * if <code>format</code> is unknown, or if the resource
49.2542 + * found for the given parameters contains malformed data.
49.2543 + * @exception ClassCastException
49.2544 + * if the loaded class cannot be cast to <code>ResourceBundle</code>
49.2545 + * @exception IllegalAccessException
49.2546 + * if the class or its nullary constructor is not
49.2547 + * accessible.
49.2548 + * @exception InstantiationException
49.2549 + * if the instantiation of a class fails for some other
49.2550 + * reason.
49.2551 + * @exception ExceptionInInitializerError
49.2552 + * if the initialization provoked by this method fails.
49.2553 + * @exception SecurityException
49.2554 + * If a security manager is present and creation of new
49.2555 + * instances is denied. See {@link Class#newInstance()}
49.2556 + * for details.
49.2557 + * @exception IOException
49.2558 + * if an error occurred when reading resources using
49.2559 + * any I/O operations
49.2560 + */
49.2561 + public ResourceBundle newBundle(String baseName, Locale locale, String format,
49.2562 + ClassLoader loader, boolean reload)
49.2563 + throws IllegalAccessException, InstantiationException, IOException {
49.2564 + String bundleName = toBundleName(baseName, locale);
49.2565 + ResourceBundle bundle = null;
49.2566 + if (format.equals("java.class")) {
49.2567 + try {
49.2568 + Class<? extends ResourceBundle> bundleClass
49.2569 + = (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
49.2570 +
49.2571 + // If the class isn't a ResourceBundle subclass, throw a
49.2572 + // ClassCastException.
49.2573 + if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
49.2574 + bundle = bundleClass.newInstance();
49.2575 + } else {
49.2576 + throw new ClassCastException(bundleClass.getName()
49.2577 + + " cannot be cast to ResourceBundle");
49.2578 + }
49.2579 + } catch (ClassNotFoundException e) {
49.2580 + }
49.2581 + } else if (format.equals("java.properties")) {
49.2582 + final String resourceName = toResourceName(bundleName, "properties");
49.2583 + final ClassLoader classLoader = loader;
49.2584 + final boolean reloadFlag = reload;
49.2585 + InputStream stream = null;
49.2586 + try {
49.2587 + stream = AccessController.doPrivileged(
49.2588 + new PrivilegedExceptionAction<InputStream>() {
49.2589 + public InputStream run() throws IOException {
49.2590 + InputStream is = null;
49.2591 + if (reloadFlag) {
49.2592 + URL url = classLoader.getResource(resourceName);
49.2593 + if (url != null) {
49.2594 + URLConnection connection = url.openConnection();
49.2595 + if (connection != null) {
49.2596 + // Disable caches to get fresh data for
49.2597 + // reloading.
49.2598 + connection.setUseCaches(false);
49.2599 + is = connection.getInputStream();
49.2600 + }
49.2601 + }
49.2602 + } else {
49.2603 + is = classLoader.getResourceAsStream(resourceName);
49.2604 + }
49.2605 + return is;
49.2606 + }
49.2607 + });
49.2608 + } catch (PrivilegedActionException e) {
49.2609 + throw (IOException) e.getException();
49.2610 + }
49.2611 + if (stream != null) {
49.2612 + try {
49.2613 + bundle = new PropertyResourceBundle(stream);
49.2614 + } finally {
49.2615 + stream.close();
49.2616 + }
49.2617 + }
49.2618 + } else {
49.2619 + throw new IllegalArgumentException("unknown format: " + format);
49.2620 + }
49.2621 + return bundle;
49.2622 + }
49.2623 +
49.2624 + /**
49.2625 + * Returns the time-to-live (TTL) value for resource bundles that
49.2626 + * are loaded under this
49.2627 + * <code>ResourceBundle.Control</code>. Positive time-to-live values
49.2628 + * specify the number of milliseconds a bundle can remain in the
49.2629 + * cache without being validated against the source data from which
49.2630 + * it was constructed. The value 0 indicates that a bundle must be
49.2631 + * validated each time it is retrieved from the cache. {@link
49.2632 + * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
49.2633 + * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
49.2634 + * that loaded resource bundles are put in the cache with no
49.2635 + * expiration control.
49.2636 + *
49.2637 + * <p>The expiration affects only the bundle loading process by the
49.2638 + * <code>ResourceBundle.getBundle</code> factory method. That is,
49.2639 + * if the factory method finds a resource bundle in the cache that
49.2640 + * has expired, the factory method calls the {@link
49.2641 + * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
49.2642 + * long) needsReload} method to determine whether the resource
49.2643 + * bundle needs to be reloaded. If <code>needsReload</code> returns
49.2644 + * <code>true</code>, the cached resource bundle instance is removed
49.2645 + * from the cache. Otherwise, the instance stays in the cache,
49.2646 + * updated with the new TTL value returned by this method.
49.2647 + *
49.2648 + * <p>All cached resource bundles are subject to removal from the
49.2649 + * cache due to memory constraints of the runtime environment.
49.2650 + * Returning a large positive value doesn't mean to lock loaded
49.2651 + * resource bundles in the cache.
49.2652 + *
49.2653 + * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
49.2654 + *
49.2655 + * @param baseName
49.2656 + * the base name of the resource bundle for which the
49.2657 + * expiration value is specified.
49.2658 + * @param locale
49.2659 + * the locale of the resource bundle for which the
49.2660 + * expiration value is specified.
49.2661 + * @return the time (0 or a positive millisecond offset from the
49.2662 + * cached time) to get loaded bundles expired in the cache,
49.2663 + * {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
49.2664 + * expiration control, or {@link #TTL_DONT_CACHE} to disable
49.2665 + * caching.
49.2666 + * @exception NullPointerException
49.2667 + * if <code>baseName</code> or <code>locale</code> is
49.2668 + * <code>null</code>
49.2669 + */
49.2670 + public long getTimeToLive(String baseName, Locale locale) {
49.2671 + if (baseName == null || locale == null) {
49.2672 + throw new NullPointerException();
49.2673 + }
49.2674 + return TTL_NO_EXPIRATION_CONTROL;
49.2675 + }
49.2676 +
49.2677 + /**
49.2678 + * Determines if the expired <code>bundle</code> in the cache needs
49.2679 + * to be reloaded based on the loading time given by
49.2680 + * <code>loadTime</code> or some other criteria. The method returns
49.2681 + * <code>true</code> if reloading is required; <code>false</code>
49.2682 + * otherwise. <code>loadTime</code> is a millisecond offset since
49.2683 + * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
49.2684 + * Epoch</a>.
49.2685 + *
49.2686 + * The calling <code>ResourceBundle.getBundle</code> factory method
49.2687 + * calls this method on the <code>ResourceBundle.Control</code>
49.2688 + * instance used for its current invocation, not on the instance
49.2689 + * used in the invocation that originally loaded the resource
49.2690 + * bundle.
49.2691 + *
49.2692 + * <p>The default implementation compares <code>loadTime</code> and
49.2693 + * the last modified time of the source data of the resource
49.2694 + * bundle. If it's determined that the source data has been modified
49.2695 + * since <code>loadTime</code>, <code>true</code> is
49.2696 + * returned. Otherwise, <code>false</code> is returned. This
49.2697 + * implementation assumes that the given <code>format</code> is the
49.2698 + * same string as its file suffix if it's not one of the default
49.2699 + * formats, <code>"java.class"</code> or
49.2700 + * <code>"java.properties"</code>.
49.2701 + *
49.2702 + * @param baseName
49.2703 + * the base bundle name of the resource bundle, a
49.2704 + * fully qualified class name
49.2705 + * @param locale
49.2706 + * the locale for which the resource bundle
49.2707 + * should be instantiated
49.2708 + * @param format
49.2709 + * the resource bundle format to be loaded
49.2710 + * @param loader
49.2711 + * the <code>ClassLoader</code> to use to load the bundle
49.2712 + * @param bundle
49.2713 + * the resource bundle instance that has been expired
49.2714 + * in the cache
49.2715 + * @param loadTime
49.2716 + * the time when <code>bundle</code> was loaded and put
49.2717 + * in the cache
49.2718 + * @return <code>true</code> if the expired bundle needs to be
49.2719 + * reloaded; <code>false</code> otherwise.
49.2720 + * @exception NullPointerException
49.2721 + * if <code>baseName</code>, <code>locale</code>,
49.2722 + * <code>format</code>, <code>loader</code>, or
49.2723 + * <code>bundle</code> is <code>null</code>
49.2724 + */
49.2725 + public boolean needsReload(String baseName, Locale locale,
49.2726 + String format, ClassLoader loader,
49.2727 + ResourceBundle bundle, long loadTime) {
49.2728 + if (bundle == null) {
49.2729 + throw new NullPointerException();
49.2730 + }
49.2731 + if (format.equals("java.class") || format.equals("java.properties")) {
49.2732 + format = format.substring(5);
49.2733 + }
49.2734 + boolean result = false;
49.2735 + try {
49.2736 + String resourceName = toResourceName(toBundleName(baseName, locale), format);
49.2737 + URL url = loader.getResource(resourceName);
49.2738 + if (url != null) {
49.2739 + long lastModified = 0;
49.2740 + URLConnection connection = url.openConnection();
49.2741 + if (connection != null) {
49.2742 + // disable caches to get the correct data
49.2743 + connection.setUseCaches(false);
49.2744 + if (connection instanceof JarURLConnection) {
49.2745 + JarEntry ent = ((JarURLConnection)connection).getJarEntry();
49.2746 + if (ent != null) {
49.2747 + lastModified = ent.getTime();
49.2748 + if (lastModified == -1) {
49.2749 + lastModified = 0;
49.2750 + }
49.2751 + }
49.2752 + } else {
49.2753 + lastModified = connection.getLastModified();
49.2754 + }
49.2755 + }
49.2756 + result = lastModified >= loadTime;
49.2757 + }
49.2758 + } catch (NullPointerException npe) {
49.2759 + throw npe;
49.2760 + } catch (Exception e) {
49.2761 + // ignore other exceptions
49.2762 + }
49.2763 + return result;
49.2764 + }
49.2765 +
49.2766 + /**
49.2767 + * Converts the given <code>baseName</code> and <code>locale</code>
49.2768 + * to the bundle name. This method is called from the default
49.2769 + * implementation of the {@link #newBundle(String, Locale, String,
49.2770 + * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
49.2771 + * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
49.2772 + * methods.
49.2773 + *
49.2774 + * <p>This implementation returns the following value:
49.2775 + * <pre>
49.2776 + * baseName + "_" + language + "_" + script + "_" + country + "_" + variant
49.2777 + * </pre>
49.2778 + * where <code>language</code>, <code>script</code>, <code>country</code>,
49.2779 + * and <code>variant</code> are the language, script, country, and variant
49.2780 + * values of <code>locale</code>, respectively. Final component values that
49.2781 + * are empty Strings are omitted along with the preceding '_'. When the
49.2782 + * script is empty, the script value is ommitted along with the preceding '_'.
49.2783 + * If all of the values are empty strings, then <code>baseName</code>
49.2784 + * is returned.
49.2785 + *
49.2786 + * <p>For example, if <code>baseName</code> is
49.2787 + * <code>"baseName"</code> and <code>locale</code> is
49.2788 + * <code>Locale("ja", "", "XX")</code>, then
49.2789 + * <code>"baseName_ja_ _XX"</code> is returned. If the given
49.2790 + * locale is <code>Locale("en")</code>, then
49.2791 + * <code>"baseName_en"</code> is returned.
49.2792 + *
49.2793 + * <p>Overriding this method allows applications to use different
49.2794 + * conventions in the organization and packaging of localized
49.2795 + * resources.
49.2796 + *
49.2797 + * @param baseName
49.2798 + * the base name of the resource bundle, a fully
49.2799 + * qualified class name
49.2800 + * @param locale
49.2801 + * the locale for which a resource bundle should be
49.2802 + * loaded
49.2803 + * @return the bundle name for the resource bundle
49.2804 + * @exception NullPointerException
49.2805 + * if <code>baseName</code> or <code>locale</code>
49.2806 + * is <code>null</code>
49.2807 + */
49.2808 + public String toBundleName(String baseName, Locale locale) {
49.2809 + if (locale == Locale.ROOT) {
49.2810 + return baseName;
49.2811 + }
49.2812 +
49.2813 + String language = locale.getLanguage();
49.2814 + String script = locale.getScript();
49.2815 + String country = locale.getCountry();
49.2816 + String variant = locale.getVariant();
49.2817 +
49.2818 + if (language == "" && country == "" && variant == "") {
49.2819 + return baseName;
49.2820 + }
49.2821 +
49.2822 + StringBuilder sb = new StringBuilder(baseName);
49.2823 + sb.append('_');
49.2824 + if (script != "") {
49.2825 + if (variant != "") {
49.2826 + sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
49.2827 + } else if (country != "") {
49.2828 + sb.append(language).append('_').append(script).append('_').append(country);
49.2829 + } else {
49.2830 + sb.append(language).append('_').append(script);
49.2831 + }
49.2832 + } else {
49.2833 + if (variant != "") {
49.2834 + sb.append(language).append('_').append(country).append('_').append(variant);
49.2835 + } else if (country != "") {
49.2836 + sb.append(language).append('_').append(country);
49.2837 + } else {
49.2838 + sb.append(language);
49.2839 + }
49.2840 + }
49.2841 + return sb.toString();
49.2842 +
49.2843 + }
49.2844 +
49.2845 + /**
49.2846 + * Converts the given <code>bundleName</code> to the form required
49.2847 + * by the {@link ClassLoader#getResource ClassLoader.getResource}
49.2848 + * method by replacing all occurrences of <code>'.'</code> in
49.2849 + * <code>bundleName</code> with <code>'/'</code> and appending a
49.2850 + * <code>'.'</code> and the given file <code>suffix</code>. For
49.2851 + * example, if <code>bundleName</code> is
49.2852 + * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code>
49.2853 + * is <code>"properties"</code>, then
49.2854 + * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned.
49.2855 + *
49.2856 + * @param bundleName
49.2857 + * the bundle name
49.2858 + * @param suffix
49.2859 + * the file type suffix
49.2860 + * @return the converted resource name
49.2861 + * @exception NullPointerException
49.2862 + * if <code>bundleName</code> or <code>suffix</code>
49.2863 + * is <code>null</code>
49.2864 + */
49.2865 + public final String toResourceName(String bundleName, String suffix) {
49.2866 + StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
49.2867 + sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
49.2868 + return sb.toString();
49.2869 + }
49.2870 + }
49.2871 +
49.2872 + private static class SingleFormatControl extends Control {
49.2873 + private static final Control PROPERTIES_ONLY
49.2874 + = new SingleFormatControl(FORMAT_PROPERTIES);
49.2875 +
49.2876 + private static final Control CLASS_ONLY
49.2877 + = new SingleFormatControl(FORMAT_CLASS);
49.2878 +
49.2879 + private final List<String> formats;
49.2880 +
49.2881 + protected SingleFormatControl(List<String> formats) {
49.2882 + this.formats = formats;
49.2883 + }
49.2884 +
49.2885 + public List<String> getFormats(String baseName) {
49.2886 + if (baseName == null) {
49.2887 + throw new NullPointerException();
49.2888 + }
49.2889 + return formats;
49.2890 + }
49.2891 + }
49.2892 +
49.2893 + private static final class NoFallbackControl extends SingleFormatControl {
49.2894 + private static final Control NO_FALLBACK
49.2895 + = new NoFallbackControl(FORMAT_DEFAULT);
49.2896 +
49.2897 + private static final Control PROPERTIES_ONLY_NO_FALLBACK
49.2898 + = new NoFallbackControl(FORMAT_PROPERTIES);
49.2899 +
49.2900 + private static final Control CLASS_ONLY_NO_FALLBACK
49.2901 + = new NoFallbackControl(FORMAT_CLASS);
49.2902 +
49.2903 + protected NoFallbackControl(List<String> formats) {
49.2904 + super(formats);
49.2905 + }
49.2906 +
49.2907 + public Locale getFallbackLocale(String baseName, Locale locale) {
49.2908 + if (baseName == null || locale == null) {
49.2909 + throw new NullPointerException();
49.2910 + }
49.2911 + return null;
49.2912 + }
49.2913 + }
49.2914 +}
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/rt/emul/compact/src/main/java/java/util/SimpleTimeZone.java Thu Oct 03 15:43:10 2013 +0200
50.3 @@ -0,0 +1,1706 @@
50.4 +/*
50.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
50.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
50.7 + *
50.8 + * This code is free software; you can redistribute it and/or modify it
50.9 + * under the terms of the GNU General Public License version 2 only, as
50.10 + * published by the Free Software Foundation. Oracle designates this
50.11 + * particular file as subject to the "Classpath" exception as provided
50.12 + * by Oracle in the LICENSE file that accompanied this code.
50.13 + *
50.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
50.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
50.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
50.17 + * version 2 for more details (a copy is included in the LICENSE file that
50.18 + * accompanied this code).
50.19 + *
50.20 + * You should have received a copy of the GNU General Public License version
50.21 + * 2 along with this work; if not, write to the Free Software Foundation,
50.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
50.23 + *
50.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
50.25 + * or visit www.oracle.com if you need additional information or have any
50.26 + * questions.
50.27 + */
50.28 +
50.29 +/*
50.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
50.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
50.32 + *
50.33 + * The original version of this source code and documentation is copyrighted
50.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
50.35 + * materials are provided under terms of a License Agreement between Taligent
50.36 + * and Sun. This technology is protected by multiple US and International
50.37 + * patents. This notice and attribution to Taligent may not be removed.
50.38 + * Taligent is a registered trademark of Taligent, Inc.
50.39 + *
50.40 + */
50.41 +
50.42 +package java.util;
50.43 +
50.44 +import java.io.ObjectInputStream;
50.45 +import java.io.ObjectOutputStream;
50.46 +import java.io.IOException;
50.47 +import sun.util.calendar.CalendarSystem;
50.48 +import sun.util.calendar.CalendarUtils;
50.49 +import sun.util.calendar.BaseCalendar;
50.50 +import sun.util.calendar.Gregorian;
50.51 +
50.52 +/**
50.53 + * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
50.54 + * that represents a time zone for use with a Gregorian calendar.
50.55 + * The class holds an offset from GMT, called <em>raw offset</em>, and start
50.56 + * and end rules for a daylight saving time schedule. Since it only holds
50.57 + * single values for each, it cannot handle historical changes in the offset
50.58 + * from GMT and the daylight saving schedule, except that the {@link
50.59 + * #setStartYear setStartYear} method can specify the year when the daylight
50.60 + * saving time schedule starts in effect.
50.61 + * <p>
50.62 + * To construct a <code>SimpleTimeZone</code> with a daylight saving time
50.63 + * schedule, the schedule can be described with a set of rules,
50.64 + * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
50.65 + * starts or ends is specified by a combination of <em>month</em>,
50.66 + * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
50.67 + * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
50.68 + * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
50.69 + * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
50.70 + * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
50.71 + * are as follows.
50.72 + *
50.73 + * <ul>
50.74 + * <li><b>Exact day of month</b><br>
50.75 + * To specify an exact day of month, set the <em>month</em> and
50.76 + * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
50.77 + * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
50.78 + * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
50.79 + *
50.80 + * <li><b>Day of week on or after day of month</b><br>
50.81 + * To specify a day of week on or after an exact day of month, set the
50.82 + * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
50.83 + * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
50.84 + * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
50.85 + * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
50.86 + * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
50.87 + * Calendar#SUNDAY SUNDAY}.</li>
50.88 + *
50.89 + * <li><b>Day of week on or before day of month</b><br>
50.90 + * To specify a day of the week on or before an exact day of the month, set
50.91 + * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
50.92 + * example, to specify the last Wednesday on or before the 21st of March, set
50.93 + * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
50.94 + * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
50.95 + *
50.96 + * <li><b>Last day-of-week of month</b><br>
50.97 + * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
50.98 + * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
50.99 + * -1. For example, to specify the last Sunday of October, set <em>month</em>
50.100 + * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
50.101 + * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1. </li>
50.102 + *
50.103 + * </ul>
50.104 + * The time of the day at which daylight saving time starts or ends is
50.105 + * specified by a millisecond value within the day. There are three kinds of
50.106 + * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
50.107 + * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
50.108 + * saving time ends
50.109 + * at 2:00 am in the wall clock time, it can be specified by 7200000
50.110 + * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
50.111 + * for an <em>end-rule</em> means the same thing as the daylight time.
50.112 + * <p>
50.113 + * The following are examples of parameters for constructing time zone objects.
50.114 + * <pre><code>
50.115 + * // Base GMT offset: -8:00
50.116 + * // DST starts: at 2:00am in standard time
50.117 + * // on the first Sunday in April
50.118 + * // DST ends: at 2:00am in daylight time
50.119 + * // on the last Sunday in October
50.120 + * // Save: 1 hour
50.121 + * SimpleTimeZone(-28800000,
50.122 + * "America/Los_Angeles",
50.123 + * Calendar.APRIL, 1, -Calendar.SUNDAY,
50.124 + * 7200000,
50.125 + * Calendar.OCTOBER, -1, Calendar.SUNDAY,
50.126 + * 7200000,
50.127 + * 3600000)
50.128 + *
50.129 + * // Base GMT offset: +1:00
50.130 + * // DST starts: at 1:00am in UTC time
50.131 + * // on the last Sunday in March
50.132 + * // DST ends: at 1:00am in UTC time
50.133 + * // on the last Sunday in October
50.134 + * // Save: 1 hour
50.135 + * SimpleTimeZone(3600000,
50.136 + * "Europe/Paris",
50.137 + * Calendar.MARCH, -1, Calendar.SUNDAY,
50.138 + * 3600000, SimpleTimeZone.UTC_TIME,
50.139 + * Calendar.OCTOBER, -1, Calendar.SUNDAY,
50.140 + * 3600000, SimpleTimeZone.UTC_TIME,
50.141 + * 3600000)
50.142 + * </code></pre>
50.143 + * These parameter rules are also applicable to the set rule methods, such as
50.144 + * <code>setStartRule</code>.
50.145 + *
50.146 + * @since 1.1
50.147 + * @see Calendar
50.148 + * @see GregorianCalendar
50.149 + * @see TimeZone
50.150 + * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
50.151 + */
50.152 +
50.153 +public class SimpleTimeZone extends TimeZone {
50.154 + /**
50.155 + * Constructs a SimpleTimeZone with the given base time zone offset from GMT
50.156 + * and time zone ID with no daylight saving time schedule.
50.157 + *
50.158 + * @param rawOffset The base time zone offset in milliseconds to GMT.
50.159 + * @param ID The time zone name that is given to this instance.
50.160 + */
50.161 + public SimpleTimeZone(int rawOffset, String ID)
50.162 + {
50.163 + this.rawOffset = rawOffset;
50.164 + setID (ID);
50.165 + dstSavings = millisPerHour; // In case user sets rules later
50.166 + }
50.167 +
50.168 + /**
50.169 + * Constructs a SimpleTimeZone with the given base time zone offset from
50.170 + * GMT, time zone ID, and rules for starting and ending the daylight
50.171 + * time.
50.172 + * Both <code>startTime</code> and <code>endTime</code> are specified to be
50.173 + * represented in the wall clock time. The amount of daylight saving is
50.174 + * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
50.175 + * equivalent to:
50.176 + * <pre><code>
50.177 + * SimpleTimeZone(rawOffset,
50.178 + * ID,
50.179 + * startMonth,
50.180 + * startDay,
50.181 + * startDayOfWeek,
50.182 + * startTime,
50.183 + * SimpleTimeZone.{@link #WALL_TIME},
50.184 + * endMonth,
50.185 + * endDay,
50.186 + * endDayOfWeek,
50.187 + * endTime,
50.188 + * SimpleTimeZone.{@link #WALL_TIME},
50.189 + * 3600000)
50.190 + * </code></pre>
50.191 + *
50.192 + * @param rawOffset The given base time zone offset from GMT.
50.193 + * @param ID The time zone ID which is given to this object.
50.194 + * @param startMonth The daylight saving time starting month. Month is
50.195 + * a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
50.196 + * for January).
50.197 + * @param startDay The day of the month on which the daylight saving time starts.
50.198 + * See the class description for the special cases of this parameter.
50.199 + * @param startDayOfWeek The daylight saving time starting day-of-week.
50.200 + * See the class description for the special cases of this parameter.
50.201 + * @param startTime The daylight saving time starting time in local wall clock
50.202 + * time (in milliseconds within the day), which is local
50.203 + * standard time in this case.
50.204 + * @param endMonth The daylight saving time ending month. Month is
50.205 + * a {@link Calendar#MONTH MONTH} field
50.206 + * value (0-based. e.g., 9 for October).
50.207 + * @param endDay The day of the month on which the daylight saving time ends.
50.208 + * See the class description for the special cases of this parameter.
50.209 + * @param endDayOfWeek The daylight saving time ending day-of-week.
50.210 + * See the class description for the special cases of this parameter.
50.211 + * @param endTime The daylight saving ending time in local wall clock time,
50.212 + * (in milliseconds within the day) which is local daylight
50.213 + * time in this case.
50.214 + * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
50.215 + * parameters are out of range for the start or end rule
50.216 + */
50.217 + public SimpleTimeZone(int rawOffset, String ID,
50.218 + int startMonth, int startDay, int startDayOfWeek, int startTime,
50.219 + int endMonth, int endDay, int endDayOfWeek, int endTime)
50.220 + {
50.221 + this(rawOffset, ID,
50.222 + startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
50.223 + endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
50.224 + millisPerHour);
50.225 + }
50.226 +
50.227 + /**
50.228 + * Constructs a SimpleTimeZone with the given base time zone offset from
50.229 + * GMT, time zone ID, and rules for starting and ending the daylight
50.230 + * time.
50.231 + * Both <code>startTime</code> and <code>endTime</code> are assumed to be
50.232 + * represented in the wall clock time. This constructor is equivalent to:
50.233 + * <pre><code>
50.234 + * SimpleTimeZone(rawOffset,
50.235 + * ID,
50.236 + * startMonth,
50.237 + * startDay,
50.238 + * startDayOfWeek,
50.239 + * startTime,
50.240 + * SimpleTimeZone.{@link #WALL_TIME},
50.241 + * endMonth,
50.242 + * endDay,
50.243 + * endDayOfWeek,
50.244 + * endTime,
50.245 + * SimpleTimeZone.{@link #WALL_TIME},
50.246 + * dstSavings)
50.247 + * </code></pre>
50.248 + *
50.249 + * @param rawOffset The given base time zone offset from GMT.
50.250 + * @param ID The time zone ID which is given to this object.
50.251 + * @param startMonth The daylight saving time starting month. Month is
50.252 + * a {@link Calendar#MONTH MONTH} field
50.253 + * value (0-based. e.g., 0 for January).
50.254 + * @param startDay The day of the month on which the daylight saving time starts.
50.255 + * See the class description for the special cases of this parameter.
50.256 + * @param startDayOfWeek The daylight saving time starting day-of-week.
50.257 + * See the class description for the special cases of this parameter.
50.258 + * @param startTime The daylight saving time starting time in local wall clock
50.259 + * time, which is local standard time in this case.
50.260 + * @param endMonth The daylight saving time ending month. Month is
50.261 + * a {@link Calendar#MONTH MONTH} field
50.262 + * value (0-based. e.g., 9 for October).
50.263 + * @param endDay The day of the month on which the daylight saving time ends.
50.264 + * See the class description for the special cases of this parameter.
50.265 + * @param endDayOfWeek The daylight saving time ending day-of-week.
50.266 + * See the class description for the special cases of this parameter.
50.267 + * @param endTime The daylight saving ending time in local wall clock time,
50.268 + * which is local daylight time in this case.
50.269 + * @param dstSavings The amount of time in milliseconds saved during
50.270 + * daylight saving time.
50.271 + * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
50.272 + * parameters are out of range for the start or end rule
50.273 + * @since 1.2
50.274 + */
50.275 + public SimpleTimeZone(int rawOffset, String ID,
50.276 + int startMonth, int startDay, int startDayOfWeek, int startTime,
50.277 + int endMonth, int endDay, int endDayOfWeek, int endTime,
50.278 + int dstSavings)
50.279 + {
50.280 + this(rawOffset, ID,
50.281 + startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
50.282 + endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
50.283 + dstSavings);
50.284 + }
50.285 +
50.286 + /**
50.287 + * Constructs a SimpleTimeZone with the given base time zone offset from
50.288 + * GMT, time zone ID, and rules for starting and ending the daylight
50.289 + * time.
50.290 + * This constructor takes the full set of the start and end rules
50.291 + * parameters, including modes of <code>startTime</code> and
50.292 + * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
50.293 + * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
50.294 + * time}.
50.295 + *
50.296 + * @param rawOffset The given base time zone offset from GMT.
50.297 + * @param ID The time zone ID which is given to this object.
50.298 + * @param startMonth The daylight saving time starting month. Month is
50.299 + * a {@link Calendar#MONTH MONTH} field
50.300 + * value (0-based. e.g., 0 for January).
50.301 + * @param startDay The day of the month on which the daylight saving time starts.
50.302 + * See the class description for the special cases of this parameter.
50.303 + * @param startDayOfWeek The daylight saving time starting day-of-week.
50.304 + * See the class description for the special cases of this parameter.
50.305 + * @param startTime The daylight saving time starting time in the time mode
50.306 + * specified by <code>startTimeMode</code>.
50.307 + * @param startTimeMode The mode of the start time specified by startTime.
50.308 + * @param endMonth The daylight saving time ending month. Month is
50.309 + * a {@link Calendar#MONTH MONTH} field
50.310 + * value (0-based. e.g., 9 for October).
50.311 + * @param endDay The day of the month on which the daylight saving time ends.
50.312 + * See the class description for the special cases of this parameter.
50.313 + * @param endDayOfWeek The daylight saving time ending day-of-week.
50.314 + * See the class description for the special cases of this parameter.
50.315 + * @param endTime The daylight saving ending time in time time mode
50.316 + * specified by <code>endTimeMode</code>.
50.317 + * @param endTimeMode The mode of the end time specified by endTime
50.318 + * @param dstSavings The amount of time in milliseconds saved during
50.319 + * daylight saving time.
50.320 + *
50.321 + * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
50.322 + * time parameters are out of range for the start or end rule, or if a time mode
50.323 + * value is invalid.
50.324 + *
50.325 + * @see #WALL_TIME
50.326 + * @see #STANDARD_TIME
50.327 + * @see #UTC_TIME
50.328 + *
50.329 + * @since 1.4
50.330 + */
50.331 + public SimpleTimeZone(int rawOffset, String ID,
50.332 + int startMonth, int startDay, int startDayOfWeek,
50.333 + int startTime, int startTimeMode,
50.334 + int endMonth, int endDay, int endDayOfWeek,
50.335 + int endTime, int endTimeMode,
50.336 + int dstSavings) {
50.337 +
50.338 + setID(ID);
50.339 + this.rawOffset = rawOffset;
50.340 + this.startMonth = startMonth;
50.341 + this.startDay = startDay;
50.342 + this.startDayOfWeek = startDayOfWeek;
50.343 + this.startTime = startTime;
50.344 + this.startTimeMode = startTimeMode;
50.345 + this.endMonth = endMonth;
50.346 + this.endDay = endDay;
50.347 + this.endDayOfWeek = endDayOfWeek;
50.348 + this.endTime = endTime;
50.349 + this.endTimeMode = endTimeMode;
50.350 + this.dstSavings = dstSavings;
50.351 +
50.352 + // this.useDaylight is set by decodeRules
50.353 + decodeRules();
50.354 + if (dstSavings <= 0) {
50.355 + throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
50.356 + }
50.357 + }
50.358 +
50.359 + /**
50.360 + * Sets the daylight saving time starting year.
50.361 + *
50.362 + * @param year The daylight saving starting year.
50.363 + */
50.364 + public void setStartYear(int year)
50.365 + {
50.366 + startYear = year;
50.367 + invalidateCache();
50.368 + }
50.369 +
50.370 + /**
50.371 + * Sets the daylight saving time start rule. For example, if daylight saving
50.372 + * time starts on the first Sunday in April at 2 am in local wall clock
50.373 + * time, you can set the start rule by calling:
50.374 + * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
50.375 + *
50.376 + * @param startMonth The daylight saving time starting month. Month is
50.377 + * a {@link Calendar#MONTH MONTH} field
50.378 + * value (0-based. e.g., 0 for January).
50.379 + * @param startDay The day of the month on which the daylight saving time starts.
50.380 + * See the class description for the special cases of this parameter.
50.381 + * @param startDayOfWeek The daylight saving time starting day-of-week.
50.382 + * See the class description for the special cases of this parameter.
50.383 + * @param startTime The daylight saving time starting time in local wall clock
50.384 + * time, which is local standard time in this case.
50.385 + * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
50.386 + * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
50.387 + */
50.388 + public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
50.389 + {
50.390 + this.startMonth = startMonth;
50.391 + this.startDay = startDay;
50.392 + this.startDayOfWeek = startDayOfWeek;
50.393 + this.startTime = startTime;
50.394 + startTimeMode = WALL_TIME;
50.395 + decodeStartRule();
50.396 + invalidateCache();
50.397 + }
50.398 +
50.399 + /**
50.400 + * Sets the daylight saving time start rule to a fixed date within a month.
50.401 + * This method is equivalent to:
50.402 + * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
50.403 + *
50.404 + * @param startMonth The daylight saving time starting month. Month is
50.405 + * a {@link Calendar#MONTH MONTH} field
50.406 + * value (0-based. e.g., 0 for January).
50.407 + * @param startDay The day of the month on which the daylight saving time starts.
50.408 + * @param startTime The daylight saving time starting time in local wall clock
50.409 + * time, which is local standard time in this case.
50.410 + * See the class description for the special cases of this parameter.
50.411 + * @exception IllegalArgumentException if the <code>startMonth</code>,
50.412 + * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
50.413 + * @since 1.2
50.414 + */
50.415 + public void setStartRule(int startMonth, int startDay, int startTime) {
50.416 + setStartRule(startMonth, startDay, 0, startTime);
50.417 + }
50.418 +
50.419 + /**
50.420 + * Sets the daylight saving time start rule to a weekday before or after the given date within
50.421 + * a month, e.g., the first Monday on or after the 8th.
50.422 + *
50.423 + * @param startMonth The daylight saving time starting month. Month is
50.424 + * a {@link Calendar#MONTH MONTH} field
50.425 + * value (0-based. e.g., 0 for January).
50.426 + * @param startDay The day of the month on which the daylight saving time starts.
50.427 + * @param startDayOfWeek The daylight saving time starting day-of-week.
50.428 + * @param startTime The daylight saving time starting time in local wall clock
50.429 + * time, which is local standard time in this case.
50.430 + * @param after If true, this rule selects the first <code>dayOfWeek</code> on or
50.431 + * <em>after</em> <code>dayOfMonth</code>. If false, this rule
50.432 + * selects the last <code>dayOfWeek</code> on or <em>before</em>
50.433 + * <code>dayOfMonth</code>.
50.434 + * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
50.435 + * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
50.436 + * @since 1.2
50.437 + */
50.438 + public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
50.439 + int startTime, boolean after)
50.440 + {
50.441 + // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
50.442 + if (after) {
50.443 + setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
50.444 + } else {
50.445 + setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
50.446 + }
50.447 + }
50.448 +
50.449 + /**
50.450 + * Sets the daylight saving time end rule. For example, if daylight saving time
50.451 + * ends on the last Sunday in October at 2 am in wall clock time,
50.452 + * you can set the end rule by calling:
50.453 + * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
50.454 + *
50.455 + * @param endMonth The daylight saving time ending month. Month is
50.456 + * a {@link Calendar#MONTH MONTH} field
50.457 + * value (0-based. e.g., 9 for October).
50.458 + * @param endDay The day of the month on which the daylight saving time ends.
50.459 + * See the class description for the special cases of this parameter.
50.460 + * @param endDayOfWeek The daylight saving time ending day-of-week.
50.461 + * See the class description for the special cases of this parameter.
50.462 + * @param endTime The daylight saving ending time in local wall clock time,
50.463 + * (in milliseconds within the day) which is local daylight
50.464 + * time in this case.
50.465 + * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
50.466 + * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
50.467 + */
50.468 + public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
50.469 + int endTime)
50.470 + {
50.471 + this.endMonth = endMonth;
50.472 + this.endDay = endDay;
50.473 + this.endDayOfWeek = endDayOfWeek;
50.474 + this.endTime = endTime;
50.475 + this.endTimeMode = WALL_TIME;
50.476 + decodeEndRule();
50.477 + invalidateCache();
50.478 + }
50.479 +
50.480 + /**
50.481 + * Sets the daylight saving time end rule to a fixed date within a month.
50.482 + * This method is equivalent to:
50.483 + * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
50.484 + *
50.485 + * @param endMonth The daylight saving time ending month. Month is
50.486 + * a {@link Calendar#MONTH MONTH} field
50.487 + * value (0-based. e.g., 9 for October).
50.488 + * @param endDay The day of the month on which the daylight saving time ends.
50.489 + * @param endTime The daylight saving ending time in local wall clock time,
50.490 + * (in milliseconds within the day) which is local daylight
50.491 + * time in this case.
50.492 + * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
50.493 + * or <code>endTime</code> parameters are out of range
50.494 + * @since 1.2
50.495 + */
50.496 + public void setEndRule(int endMonth, int endDay, int endTime)
50.497 + {
50.498 + setEndRule(endMonth, endDay, 0, endTime);
50.499 + }
50.500 +
50.501 + /**
50.502 + * Sets the daylight saving time end rule to a weekday before or after the given date within
50.503 + * a month, e.g., the first Monday on or after the 8th.
50.504 + *
50.505 + * @param endMonth The daylight saving time ending month. Month is
50.506 + * a {@link Calendar#MONTH MONTH} field
50.507 + * value (0-based. e.g., 9 for October).
50.508 + * @param endDay The day of the month on which the daylight saving time ends.
50.509 + * @param endDayOfWeek The daylight saving time ending day-of-week.
50.510 + * @param endTime The daylight saving ending time in local wall clock time,
50.511 + * (in milliseconds within the day) which is local daylight
50.512 + * time in this case.
50.513 + * @param after If true, this rule selects the first <code>endDayOfWeek</code> on
50.514 + * or <em>after</em> <code>endDay</code>. If false, this rule
50.515 + * selects the last <code>endDayOfWeek</code> on or before
50.516 + * <code>endDay</code> of the month.
50.517 + * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
50.518 + * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
50.519 + * @since 1.2
50.520 + */
50.521 + public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
50.522 + {
50.523 + if (after) {
50.524 + setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
50.525 + } else {
50.526 + setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
50.527 + }
50.528 + }
50.529 +
50.530 + /**
50.531 + * Returns the offset of this time zone from UTC at the given
50.532 + * time. If daylight saving time is in effect at the given time,
50.533 + * the offset value is adjusted with the amount of daylight
50.534 + * saving.
50.535 + *
50.536 + * @param date the time at which the time zone offset is found
50.537 + * @return the amount of time in milliseconds to add to UTC to get
50.538 + * local time.
50.539 + * @since 1.4
50.540 + */
50.541 + public int getOffset(long date) {
50.542 + return getOffsets(date, null);
50.543 + }
50.544 +
50.545 + /**
50.546 + * @see TimeZone#getOffsets
50.547 + */
50.548 + int getOffsets(long date, int[] offsets) {
50.549 + int offset = rawOffset;
50.550 +
50.551 + computeOffset:
50.552 + if (useDaylight) {
50.553 + synchronized (this) {
50.554 + if (cacheStart != 0) {
50.555 + if (date >= cacheStart && date < cacheEnd) {
50.556 + offset += dstSavings;
50.557 + break computeOffset;
50.558 + }
50.559 + }
50.560 + }
50.561 + BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
50.562 + gcal : (BaseCalendar) CalendarSystem.forName("julian");
50.563 + BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
50.564 + // Get the year in local time
50.565 + cal.getCalendarDate(date + rawOffset, cdate);
50.566 + int year = cdate.getNormalizedYear();
50.567 + if (year >= startYear) {
50.568 + // Clear time elements for the transition calculations
50.569 + cdate.setTimeOfDay(0, 0, 0, 0);
50.570 + offset = getOffset(cal, cdate, year, date);
50.571 + }
50.572 + }
50.573 +
50.574 + if (offsets != null) {
50.575 + offsets[0] = rawOffset;
50.576 + offsets[1] = offset - rawOffset;
50.577 + }
50.578 + return offset;
50.579 + }
50.580 +
50.581 + /**
50.582 + * Returns the difference in milliseconds between local time and
50.583 + * UTC, taking into account both the raw offset and the effect of
50.584 + * daylight saving, for the specified date and time. This method
50.585 + * assumes that the start and end month are distinct. It also
50.586 + * uses a default {@link GregorianCalendar} object as its
50.587 + * underlying calendar, such as for determining leap years. Do
50.588 + * not use the result of this method with a calendar other than a
50.589 + * default <code>GregorianCalendar</code>.
50.590 + *
50.591 + * <p><em>Note: In general, clients should use
50.592 + * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
50.593 + * instead of calling this method.</em>
50.594 + *
50.595 + * @param era The era of the given date.
50.596 + * @param year The year in the given date.
50.597 + * @param month The month in the given date. Month is 0-based. e.g.,
50.598 + * 0 for January.
50.599 + * @param day The day-in-month of the given date.
50.600 + * @param dayOfWeek The day-of-week of the given date.
50.601 + * @param millis The milliseconds in day in <em>standard</em> local time.
50.602 + * @return The milliseconds to add to UTC to get local time.
50.603 + * @exception IllegalArgumentException the <code>era</code>,
50.604 + * <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
50.605 + * or <code>millis</code> parameters are out of range
50.606 + */
50.607 + public int getOffset(int era, int year, int month, int day, int dayOfWeek,
50.608 + int millis)
50.609 + {
50.610 + if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
50.611 + throw new IllegalArgumentException("Illegal era " + era);
50.612 + }
50.613 +
50.614 + int y = year;
50.615 + if (era == GregorianCalendar.BC) {
50.616 + // adjust y with the GregorianCalendar-style year numbering.
50.617 + y = 1 - y;
50.618 + }
50.619 +
50.620 + // If the year isn't representable with the 64-bit long
50.621 + // integer in milliseconds, convert the year to an
50.622 + // equivalent year. This is required to pass some JCK test cases
50.623 + // which are actually useless though because the specified years
50.624 + // can't be supported by the Java time system.
50.625 + if (y >= 292278994) {
50.626 + y = 2800 + y % 2800;
50.627 + } else if (y <= -292269054) {
50.628 + // y %= 28 also produces an equivalent year, but positive
50.629 + // year numbers would be convenient to use the UNIX cal
50.630 + // command.
50.631 + y = (int) CalendarUtils.mod((long) y, 28);
50.632 + }
50.633 +
50.634 + // convert year to its 1-based month value
50.635 + int m = month + 1;
50.636 +
50.637 + // First, calculate time as a Gregorian date.
50.638 + BaseCalendar cal = gcal;
50.639 + BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
50.640 + cdate.setDate(y, m, day);
50.641 + long time = cal.getTime(cdate); // normalize cdate
50.642 + time += millis - rawOffset; // UTC time
50.643 +
50.644 + // If the time value represents a time before the default
50.645 + // Gregorian cutover, recalculate time using the Julian
50.646 + // calendar system. For the Julian calendar system, the
50.647 + // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
50.648 + // 1, 2 ... which is different from the GregorianCalendar
50.649 + // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
50.650 + if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
50.651 + cal = (BaseCalendar) CalendarSystem.forName("julian");
50.652 + cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
50.653 + cdate.setNormalizedDate(y, m, day);
50.654 + time = cal.getTime(cdate) + millis - rawOffset;
50.655 + }
50.656 +
50.657 + if ((cdate.getNormalizedYear() != y)
50.658 + || (cdate.getMonth() != m)
50.659 + || (cdate.getDayOfMonth() != day)
50.660 + // The validation should be cdate.getDayOfWeek() ==
50.661 + // dayOfWeek. However, we don't check dayOfWeek for
50.662 + // compatibility.
50.663 + || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
50.664 + || (millis < 0 || millis >= (24*60*60*1000))) {
50.665 + throw new IllegalArgumentException();
50.666 + }
50.667 +
50.668 + if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
50.669 + return rawOffset;
50.670 + }
50.671 +
50.672 + return getOffset(cal, cdate, y, time);
50.673 + }
50.674 +
50.675 + private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
50.676 + synchronized (this) {
50.677 + if (cacheStart != 0) {
50.678 + if (time >= cacheStart && time < cacheEnd) {
50.679 + return rawOffset + dstSavings;
50.680 + }
50.681 + if (year == cacheYear) {
50.682 + return rawOffset;
50.683 + }
50.684 + }
50.685 + }
50.686 +
50.687 + long start = getStart(cal, cdate, year);
50.688 + long end = getEnd(cal, cdate, year);
50.689 + int offset = rawOffset;
50.690 + if (start <= end) {
50.691 + if (time >= start && time < end) {
50.692 + offset += dstSavings;
50.693 + }
50.694 + synchronized (this) {
50.695 + cacheYear = year;
50.696 + cacheStart = start;
50.697 + cacheEnd = end;
50.698 + }
50.699 + } else {
50.700 + if (time < end) {
50.701 + // TODO: support Gregorian cutover. The previous year
50.702 + // may be in the other calendar system.
50.703 + start = getStart(cal, cdate, year - 1);
50.704 + if (time >= start) {
50.705 + offset += dstSavings;
50.706 + }
50.707 + } else if (time >= start) {
50.708 + // TODO: support Gregorian cutover. The next year
50.709 + // may be in the other calendar system.
50.710 + end = getEnd(cal, cdate, year + 1);
50.711 + if (time < end) {
50.712 + offset += dstSavings;
50.713 + }
50.714 + }
50.715 + if (start <= end) {
50.716 + synchronized (this) {
50.717 + // The start and end transitions are in multiple years.
50.718 + cacheYear = (long) startYear - 1;
50.719 + cacheStart = start;
50.720 + cacheEnd = end;
50.721 + }
50.722 + }
50.723 + }
50.724 + return offset;
50.725 + }
50.726 +
50.727 + private long getStart(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
50.728 + int time = startTime;
50.729 + if (startTimeMode != UTC_TIME) {
50.730 + time -= rawOffset;
50.731 + }
50.732 + return getTransition(cal, cdate, startMode, year, startMonth, startDay,
50.733 + startDayOfWeek, time);
50.734 + }
50.735 +
50.736 + private long getEnd(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
50.737 + int time = endTime;
50.738 + if (endTimeMode != UTC_TIME) {
50.739 + time -= rawOffset;
50.740 + }
50.741 + if (endTimeMode == WALL_TIME) {
50.742 + time -= dstSavings;
50.743 + }
50.744 + return getTransition(cal, cdate, endMode, year, endMonth, endDay,
50.745 + endDayOfWeek, time);
50.746 + }
50.747 +
50.748 + private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate,
50.749 + int mode, int year, int month, int dayOfMonth,
50.750 + int dayOfWeek, int timeOfDay) {
50.751 + cdate.setNormalizedYear(year);
50.752 + cdate.setMonth(month + 1);
50.753 + switch (mode) {
50.754 + case DOM_MODE:
50.755 + cdate.setDayOfMonth(dayOfMonth);
50.756 + break;
50.757 +
50.758 + case DOW_IN_MONTH_MODE:
50.759 + cdate.setDayOfMonth(1);
50.760 + if (dayOfMonth < 0) {
50.761 + cdate.setDayOfMonth(cal.getMonthLength(cdate));
50.762 + }
50.763 + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
50.764 + break;
50.765 +
50.766 + case DOW_GE_DOM_MODE:
50.767 + cdate.setDayOfMonth(dayOfMonth);
50.768 + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
50.769 + break;
50.770 +
50.771 + case DOW_LE_DOM_MODE:
50.772 + cdate.setDayOfMonth(dayOfMonth);
50.773 + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
50.774 + break;
50.775 + }
50.776 + return cal.getTime(cdate) + timeOfDay;
50.777 + }
50.778 +
50.779 + /**
50.780 + * Gets the GMT offset for this time zone.
50.781 + * @return the GMT offset value in milliseconds
50.782 + * @see #setRawOffset
50.783 + */
50.784 + public int getRawOffset()
50.785 + {
50.786 + // The given date will be taken into account while
50.787 + // we have the historical time zone data in place.
50.788 + return rawOffset;
50.789 + }
50.790 +
50.791 + /**
50.792 + * Sets the base time zone offset to GMT.
50.793 + * This is the offset to add to UTC to get local time.
50.794 + * @see #getRawOffset
50.795 + */
50.796 + public void setRawOffset(int offsetMillis)
50.797 + {
50.798 + this.rawOffset = offsetMillis;
50.799 + }
50.800 +
50.801 + /**
50.802 + * Sets the amount of time in milliseconds that the clock is advanced
50.803 + * during daylight saving time.
50.804 + * @param millisSavedDuringDST the number of milliseconds the time is
50.805 + * advanced with respect to standard time when the daylight saving time rules
50.806 + * are in effect. A positive number, typically one hour (3600000).
50.807 + * @see #getDSTSavings
50.808 + * @since 1.2
50.809 + */
50.810 + public void setDSTSavings(int millisSavedDuringDST) {
50.811 + if (millisSavedDuringDST <= 0) {
50.812 + throw new IllegalArgumentException("Illegal daylight saving value: "
50.813 + + millisSavedDuringDST);
50.814 + }
50.815 + dstSavings = millisSavedDuringDST;
50.816 + }
50.817 +
50.818 + /**
50.819 + * Returns the amount of time in milliseconds that the clock is
50.820 + * advanced during daylight saving time.
50.821 + *
50.822 + * @return the number of milliseconds the time is advanced with
50.823 + * respect to standard time when the daylight saving rules are in
50.824 + * effect, or 0 (zero) if this time zone doesn't observe daylight
50.825 + * saving time.
50.826 + *
50.827 + * @see #setDSTSavings
50.828 + * @since 1.2
50.829 + */
50.830 + public int getDSTSavings() {
50.831 + return useDaylight ? dstSavings : 0;
50.832 + }
50.833 +
50.834 + /**
50.835 + * Queries if this time zone uses daylight saving time.
50.836 + * @return true if this time zone uses daylight saving time;
50.837 + * false otherwise.
50.838 + */
50.839 + public boolean useDaylightTime()
50.840 + {
50.841 + return useDaylight;
50.842 + }
50.843 +
50.844 + /**
50.845 + * Returns {@code true} if this {@code SimpleTimeZone} observes
50.846 + * Daylight Saving Time. This method is equivalent to {@link
50.847 + * #useDaylightTime()}.
50.848 + *
50.849 + * @return {@code true} if this {@code SimpleTimeZone} observes
50.850 + * Daylight Saving Time; {@code false} otherwise.
50.851 + * @since 1.7
50.852 + */
50.853 + @Override
50.854 + public boolean observesDaylightTime() {
50.855 + return useDaylightTime();
50.856 + }
50.857 +
50.858 + /**
50.859 + * Queries if the given date is in daylight saving time.
50.860 + * @return true if daylight saving time is in effective at the
50.861 + * given date; false otherwise.
50.862 + */
50.863 + public boolean inDaylightTime(Date date)
50.864 + {
50.865 + return (getOffset(date.getTime()) != rawOffset);
50.866 + }
50.867 +
50.868 + /**
50.869 + * Returns a clone of this <code>SimpleTimeZone</code> instance.
50.870 + * @return a clone of this instance.
50.871 + */
50.872 + public Object clone()
50.873 + {
50.874 + return super.clone();
50.875 + }
50.876 +
50.877 + /**
50.878 + * Generates the hash code for the SimpleDateFormat object.
50.879 + * @return the hash code for this object
50.880 + */
50.881 + public synchronized int hashCode()
50.882 + {
50.883 + return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
50.884 + endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
50.885 + }
50.886 +
50.887 + /**
50.888 + * Compares the equality of two <code>SimpleTimeZone</code> objects.
50.889 + *
50.890 + * @param obj The <code>SimpleTimeZone</code> object to be compared with.
50.891 + * @return True if the given <code>obj</code> is the same as this
50.892 + * <code>SimpleTimeZone</code> object; false otherwise.
50.893 + */
50.894 + public boolean equals(Object obj)
50.895 + {
50.896 + if (this == obj) {
50.897 + return true;
50.898 + }
50.899 + if (!(obj instanceof SimpleTimeZone)) {
50.900 + return false;
50.901 + }
50.902 +
50.903 + SimpleTimeZone that = (SimpleTimeZone) obj;
50.904 +
50.905 + return getID().equals(that.getID()) &&
50.906 + hasSameRules(that);
50.907 + }
50.908 +
50.909 + /**
50.910 + * Returns <code>true</code> if this zone has the same rules and offset as another zone.
50.911 + * @param other the TimeZone object to be compared with
50.912 + * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
50.913 + * same rules and offset as this one
50.914 + * @since 1.2
50.915 + */
50.916 + public boolean hasSameRules(TimeZone other) {
50.917 + if (this == other) {
50.918 + return true;
50.919 + }
50.920 + if (!(other instanceof SimpleTimeZone)) {
50.921 + return false;
50.922 + }
50.923 + SimpleTimeZone that = (SimpleTimeZone) other;
50.924 + return rawOffset == that.rawOffset &&
50.925 + useDaylight == that.useDaylight &&
50.926 + (!useDaylight
50.927 + // Only check rules if using DST
50.928 + || (dstSavings == that.dstSavings &&
50.929 + startMode == that.startMode &&
50.930 + startMonth == that.startMonth &&
50.931 + startDay == that.startDay &&
50.932 + startDayOfWeek == that.startDayOfWeek &&
50.933 + startTime == that.startTime &&
50.934 + startTimeMode == that.startTimeMode &&
50.935 + endMode == that.endMode &&
50.936 + endMonth == that.endMonth &&
50.937 + endDay == that.endDay &&
50.938 + endDayOfWeek == that.endDayOfWeek &&
50.939 + endTime == that.endTime &&
50.940 + endTimeMode == that.endTimeMode &&
50.941 + startYear == that.startYear));
50.942 + }
50.943 +
50.944 + /**
50.945 + * Returns a string representation of this time zone.
50.946 + * @return a string representation of this time zone.
50.947 + */
50.948 + public String toString() {
50.949 + return getClass().getName() +
50.950 + "[id=" + getID() +
50.951 + ",offset=" + rawOffset +
50.952 + ",dstSavings=" + dstSavings +
50.953 + ",useDaylight=" + useDaylight +
50.954 + ",startYear=" + startYear +
50.955 + ",startMode=" + startMode +
50.956 + ",startMonth=" + startMonth +
50.957 + ",startDay=" + startDay +
50.958 + ",startDayOfWeek=" + startDayOfWeek +
50.959 + ",startTime=" + startTime +
50.960 + ",startTimeMode=" + startTimeMode +
50.961 + ",endMode=" + endMode +
50.962 + ",endMonth=" + endMonth +
50.963 + ",endDay=" + endDay +
50.964 + ",endDayOfWeek=" + endDayOfWeek +
50.965 + ",endTime=" + endTime +
50.966 + ",endTimeMode=" + endTimeMode + ']';
50.967 + }
50.968 +
50.969 + // =======================privates===============================
50.970 +
50.971 + /**
50.972 + * The month in which daylight saving time starts. This value must be
50.973 + * between <code>Calendar.JANUARY</code> and
50.974 + * <code>Calendar.DECEMBER</code> inclusive. This value must not equal
50.975 + * <code>endMonth</code>.
50.976 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.977 + * @serial
50.978 + */
50.979 + private int startMonth;
50.980 +
50.981 + /**
50.982 + * This field has two possible interpretations:
50.983 + * <dl>
50.984 + * <dt><code>startMode == DOW_IN_MONTH</code></dt>
50.985 + * <dd>
50.986 + * <code>startDay</code> indicates the day of the month of
50.987 + * <code>startMonth</code> on which daylight
50.988 + * saving time starts, from 1 to 28, 30, or 31, depending on the
50.989 + * <code>startMonth</code>.
50.990 + * </dd>
50.991 + * <dt><code>startMode != DOW_IN_MONTH</code></dt>
50.992 + * <dd>
50.993 + * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
50.994 + * month <code>startMonth</code> daylight
50.995 + * saving time starts on. For example, a value of +1 and a
50.996 + * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
50.997 + * first Sunday of <code>startMonth</code>. Likewise, +2 would indicate the
50.998 + * second Sunday, and -1 the last Sunday. A value of 0 is illegal.
50.999 + * </dd>
50.1000 + * </dl>
50.1001 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1002 + * @serial
50.1003 + */
50.1004 + private int startDay;
50.1005 +
50.1006 + /**
50.1007 + * The day of the week on which daylight saving time starts. This value
50.1008 + * must be between <code>Calendar.SUNDAY</code> and
50.1009 + * <code>Calendar.SATURDAY</code> inclusive.
50.1010 + * <p>If <code>useDaylight</code> is false or
50.1011 + * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
50.1012 + * @serial
50.1013 + */
50.1014 + private int startDayOfWeek;
50.1015 +
50.1016 + /**
50.1017 + * The time in milliseconds after midnight at which daylight saving
50.1018 + * time starts. This value is expressed as wall time, standard time,
50.1019 + * or UTC time, depending on the setting of <code>startTimeMode</code>.
50.1020 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1021 + * @serial
50.1022 + */
50.1023 + private int startTime;
50.1024 +
50.1025 + /**
50.1026 + * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
50.1027 + * @serial
50.1028 + * @since 1.3
50.1029 + */
50.1030 + private int startTimeMode;
50.1031 +
50.1032 + /**
50.1033 + * The month in which daylight saving time ends. This value must be
50.1034 + * between <code>Calendar.JANUARY</code> and
50.1035 + * <code>Calendar.UNDECIMBER</code>. This value must not equal
50.1036 + * <code>startMonth</code>.
50.1037 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1038 + * @serial
50.1039 + */
50.1040 + private int endMonth;
50.1041 +
50.1042 + /**
50.1043 + * This field has two possible interpretations:
50.1044 + * <dl>
50.1045 + * <dt><code>endMode == DOW_IN_MONTH</code></dt>
50.1046 + * <dd>
50.1047 + * <code>endDay</code> indicates the day of the month of
50.1048 + * <code>endMonth</code> on which daylight
50.1049 + * saving time ends, from 1 to 28, 30, or 31, depending on the
50.1050 + * <code>endMonth</code>.
50.1051 + * </dd>
50.1052 + * <dt><code>endMode != DOW_IN_MONTH</code></dt>
50.1053 + * <dd>
50.1054 + * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
50.1055 + * month <code>endMonth</code> daylight
50.1056 + * saving time ends on. For example, a value of +1 and a
50.1057 + * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
50.1058 + * first Sunday of <code>endMonth</code>. Likewise, +2 would indicate the
50.1059 + * second Sunday, and -1 the last Sunday. A value of 0 is illegal.
50.1060 + * </dd>
50.1061 + * </dl>
50.1062 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1063 + * @serial
50.1064 + */
50.1065 + private int endDay;
50.1066 +
50.1067 + /**
50.1068 + * The day of the week on which daylight saving time ends. This value
50.1069 + * must be between <code>Calendar.SUNDAY</code> and
50.1070 + * <code>Calendar.SATURDAY</code> inclusive.
50.1071 + * <p>If <code>useDaylight</code> is false or
50.1072 + * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
50.1073 + * @serial
50.1074 + */
50.1075 + private int endDayOfWeek;
50.1076 +
50.1077 + /**
50.1078 + * The time in milliseconds after midnight at which daylight saving
50.1079 + * time ends. This value is expressed as wall time, standard time,
50.1080 + * or UTC time, depending on the setting of <code>endTimeMode</code>.
50.1081 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1082 + * @serial
50.1083 + */
50.1084 + private int endTime;
50.1085 +
50.1086 + /**
50.1087 + * The format of endTime, either <code>WALL_TIME</code>,
50.1088 + * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
50.1089 + * @serial
50.1090 + * @since 1.3
50.1091 + */
50.1092 + private int endTimeMode;
50.1093 +
50.1094 + /**
50.1095 + * The year in which daylight saving time is first observed. This is an {@link GregorianCalendar#AD AD}
50.1096 + * value. If this value is less than 1 then daylight saving time is observed
50.1097 + * for all <code>AD</code> years.
50.1098 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1099 + * @serial
50.1100 + */
50.1101 + private int startYear;
50.1102 +
50.1103 + /**
50.1104 + * The offset in milliseconds between this zone and GMT. Negative offsets
50.1105 + * are to the west of Greenwich. To obtain local <em>standard</em> time,
50.1106 + * add the offset to GMT time. To obtain local wall time it may also be
50.1107 + * necessary to add <code>dstSavings</code>.
50.1108 + * @serial
50.1109 + */
50.1110 + private int rawOffset;
50.1111 +
50.1112 + /**
50.1113 + * A boolean value which is true if and only if this zone uses daylight
50.1114 + * saving time. If this value is false, several other fields are ignored.
50.1115 + * @serial
50.1116 + */
50.1117 + private boolean useDaylight=false; // indicate if this time zone uses DST
50.1118 +
50.1119 + private static final int millisPerHour = 60*60*1000;
50.1120 + private static final int millisPerDay = 24*millisPerHour;
50.1121 +
50.1122 + /**
50.1123 + * This field was serialized in JDK 1.1, so we have to keep it that way
50.1124 + * to maintain serialization compatibility. However, there's no need to
50.1125 + * recreate the array each time we create a new time zone.
50.1126 + * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
50.1127 + * 31, 31, 30, 31, 30, 31}. This is ignored as of the Java 2 platform v1.2, however, it must
50.1128 + * be streamed out for compatibility with JDK 1.1.
50.1129 + */
50.1130 + private final byte monthLength[] = staticMonthLength;
50.1131 + private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
50.1132 + private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
50.1133 +
50.1134 + /**
50.1135 + * Variables specifying the mode of the start rule. Takes the following
50.1136 + * values:
50.1137 + * <dl>
50.1138 + * <dt><code>DOM_MODE</code></dt>
50.1139 + * <dd>
50.1140 + * Exact day of week; e.g., March 1.
50.1141 + * </dd>
50.1142 + * <dt><code>DOW_IN_MONTH_MODE</code></dt>
50.1143 + * <dd>
50.1144 + * Day of week in month; e.g., last Sunday in March.
50.1145 + * </dd>
50.1146 + * <dt><code>DOW_GE_DOM_MODE</code></dt>
50.1147 + * <dd>
50.1148 + * Day of week after day of month; e.g., Sunday on or after March 15.
50.1149 + * </dd>
50.1150 + * <dt><code>DOW_LE_DOM_MODE</code></dt>
50.1151 + * <dd>
50.1152 + * Day of week before day of month; e.g., Sunday on or before March 15.
50.1153 + * </dd>
50.1154 + * </dl>
50.1155 + * The setting of this field affects the interpretation of the
50.1156 + * <code>startDay</code> field.
50.1157 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1158 + * @serial
50.1159 + * @since 1.1.4
50.1160 + */
50.1161 + private int startMode;
50.1162 +
50.1163 + /**
50.1164 + * Variables specifying the mode of the end rule. Takes the following
50.1165 + * values:
50.1166 + * <dl>
50.1167 + * <dt><code>DOM_MODE</code></dt>
50.1168 + * <dd>
50.1169 + * Exact day of week; e.g., March 1.
50.1170 + * </dd>
50.1171 + * <dt><code>DOW_IN_MONTH_MODE</code></dt>
50.1172 + * <dd>
50.1173 + * Day of week in month; e.g., last Sunday in March.
50.1174 + * </dd>
50.1175 + * <dt><code>DOW_GE_DOM_MODE</code></dt>
50.1176 + * <dd>
50.1177 + * Day of week after day of month; e.g., Sunday on or after March 15.
50.1178 + * </dd>
50.1179 + * <dt><code>DOW_LE_DOM_MODE</code></dt>
50.1180 + * <dd>
50.1181 + * Day of week before day of month; e.g., Sunday on or before March 15.
50.1182 + * </dd>
50.1183 + * </dl>
50.1184 + * The setting of this field affects the interpretation of the
50.1185 + * <code>endDay</code> field.
50.1186 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1187 + * @serial
50.1188 + * @since 1.1.4
50.1189 + */
50.1190 + private int endMode;
50.1191 +
50.1192 + /**
50.1193 + * A positive value indicating the amount of time saved during DST in
50.1194 + * milliseconds.
50.1195 + * Typically one hour (3600000); sometimes 30 minutes (1800000).
50.1196 + * <p>If <code>useDaylight</code> is false, this value is ignored.
50.1197 + * @serial
50.1198 + * @since 1.1.4
50.1199 + */
50.1200 + private int dstSavings;
50.1201 +
50.1202 + private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
50.1203 +
50.1204 + /**
50.1205 + * Cache values representing a single period of daylight saving
50.1206 + * time. When the cache values are valid, cacheStart is the start
50.1207 + * time (inclusive) of daylight saving time and cacheEnd is the
50.1208 + * end time (exclusive).
50.1209 + *
50.1210 + * cacheYear has a year value if both cacheStart and cacheEnd are
50.1211 + * in the same year. cacheYear is set to startYear - 1 if
50.1212 + * cacheStart and cacheEnd are in different years. cacheStart is 0
50.1213 + * if the cache values are void. cacheYear is a long to support
50.1214 + * Integer.MIN_VALUE - 1 (JCK requirement).
50.1215 + */
50.1216 + private transient long cacheYear;
50.1217 + private transient long cacheStart;
50.1218 + private transient long cacheEnd;
50.1219 +
50.1220 + /**
50.1221 + * Constants specifying values of startMode and endMode.
50.1222 + */
50.1223 + private static final int DOM_MODE = 1; // Exact day of month, "Mar 1"
50.1224 + private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
50.1225 + private static final int DOW_GE_DOM_MODE = 3; // Day of week after day of month, "Sun>=15"
50.1226 + private static final int DOW_LE_DOM_MODE = 4; // Day of week before day of month, "Sun<=21"
50.1227 +
50.1228 + /**
50.1229 + * Constant for a mode of start or end time specified as wall clock
50.1230 + * time. Wall clock time is standard time for the onset rule, and
50.1231 + * daylight time for the end rule.
50.1232 + * @since 1.4
50.1233 + */
50.1234 + public static final int WALL_TIME = 0; // Zero for backward compatibility
50.1235 +
50.1236 + /**
50.1237 + * Constant for a mode of start or end time specified as standard time.
50.1238 + * @since 1.4
50.1239 + */
50.1240 + public static final int STANDARD_TIME = 1;
50.1241 +
50.1242 + /**
50.1243 + * Constant for a mode of start or end time specified as UTC. European
50.1244 + * Union rules are specified as UTC time, for example.
50.1245 + * @since 1.4
50.1246 + */
50.1247 + public static final int UTC_TIME = 2;
50.1248 +
50.1249 + // Proclaim compatibility with 1.1
50.1250 + static final long serialVersionUID = -403250971215465050L;
50.1251 +
50.1252 + // the internal serial version which says which version was written
50.1253 + // - 0 (default) for version up to JDK 1.1.3
50.1254 + // - 1 for version from JDK 1.1.4, which includes 3 new fields
50.1255 + // - 2 for JDK 1.3, which includes 2 new fields
50.1256 + static final int currentSerialVersion = 2;
50.1257 +
50.1258 + /**
50.1259 + * The version of the serialized data on the stream. Possible values:
50.1260 + * <dl>
50.1261 + * <dt><b>0</b> or not present on stream</dt>
50.1262 + * <dd>
50.1263 + * JDK 1.1.3 or earlier.
50.1264 + * </dd>
50.1265 + * <dt><b>1</b></dt>
50.1266 + * <dd>
50.1267 + * JDK 1.1.4 or later. Includes three new fields: <code>startMode</code>,
50.1268 + * <code>endMode</code>, and <code>dstSavings</code>.
50.1269 + * </dd>
50.1270 + * <dt><b>2</b></dt>
50.1271 + * <dd>
50.1272 + * JDK 1.3 or later. Includes two new fields: <code>startTimeMode</code>
50.1273 + * and <code>endTimeMode</code>.
50.1274 + * </dd>
50.1275 + * </dl>
50.1276 + * When streaming out this class, the most recent format
50.1277 + * and the highest allowable <code>serialVersionOnStream</code>
50.1278 + * is written.
50.1279 + * @serial
50.1280 + * @since 1.1.4
50.1281 + */
50.1282 + private int serialVersionOnStream = currentSerialVersion;
50.1283 +
50.1284 + synchronized private void invalidateCache() {
50.1285 + cacheYear = startYear - 1;
50.1286 + cacheStart = cacheEnd = 0;
50.1287 + }
50.1288 +
50.1289 + //----------------------------------------------------------------------
50.1290 + // Rule representation
50.1291 + //
50.1292 + // We represent the following flavors of rules:
50.1293 + // 5 the fifth of the month
50.1294 + // lastSun the last Sunday in the month
50.1295 + // lastMon the last Monday in the month
50.1296 + // Sun>=8 first Sunday on or after the eighth
50.1297 + // Sun<=25 last Sunday on or before the 25th
50.1298 + // This is further complicated by the fact that we need to remain
50.1299 + // backward compatible with the 1.1 FCS. Finally, we need to minimize
50.1300 + // API changes. In order to satisfy these requirements, we support
50.1301 + // three representation systems, and we translate between them.
50.1302 + //
50.1303 + // INTERNAL REPRESENTATION
50.1304 + // This is the format SimpleTimeZone objects take after construction or
50.1305 + // streaming in is complete. Rules are represented directly, using an
50.1306 + // unencoded format. We will discuss the start rule only below; the end
50.1307 + // rule is analogous.
50.1308 + // startMode Takes on enumerated values DAY_OF_MONTH,
50.1309 + // DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
50.1310 + // startDay The day of the month, or for DOW_IN_MONTH mode, a
50.1311 + // value indicating which DOW, such as +1 for first,
50.1312 + // +2 for second, -1 for last, etc.
50.1313 + // startDayOfWeek The day of the week. Ignored for DAY_OF_MONTH.
50.1314 + //
50.1315 + // ENCODED REPRESENTATION
50.1316 + // This is the format accepted by the constructor and by setStartRule()
50.1317 + // and setEndRule(). It uses various combinations of positive, negative,
50.1318 + // and zero values to encode the different rules. This representation
50.1319 + // allows us to specify all the different rule flavors without altering
50.1320 + // the API.
50.1321 + // MODE startMonth startDay startDayOfWeek
50.1322 + // DOW_IN_MONTH_MODE >=0 !=0 >0
50.1323 + // DOM_MODE >=0 >0 ==0
50.1324 + // DOW_GE_DOM_MODE >=0 >0 <0
50.1325 + // DOW_LE_DOM_MODE >=0 <0 <0
50.1326 + // (no DST) don't care ==0 don't care
50.1327 + //
50.1328 + // STREAMED REPRESENTATION
50.1329 + // We must retain binary compatibility with the 1.1 FCS. The 1.1 code only
50.1330 + // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
50.1331 + // flag useDaylight. When we stream an object out, we translate into an
50.1332 + // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
50.1333 + // and used by 1.1 code. Following that, we write out the full
50.1334 + // representation separately so that contemporary code can recognize and
50.1335 + // parse it. The full representation is written in a "packed" format,
50.1336 + // consisting of a version number, a length, and an array of bytes. Future
50.1337 + // versions of this class may specify different versions. If they wish to
50.1338 + // include additional data, they should do so by storing them after the
50.1339 + // packed representation below.
50.1340 + //----------------------------------------------------------------------
50.1341 +
50.1342 + /**
50.1343 + * Given a set of encoded rules in startDay and startDayOfMonth, decode
50.1344 + * them and set the startMode appropriately. Do the same for endDay and
50.1345 + * endDayOfMonth. Upon entry, the day of week variables may be zero or
50.1346 + * negative, in order to indicate special modes. The day of month
50.1347 + * variables may also be negative. Upon exit, the mode variables will be
50.1348 + * set, and the day of week and day of month variables will be positive.
50.1349 + * This method also recognizes a startDay or endDay of zero as indicating
50.1350 + * no DST.
50.1351 + */
50.1352 + private void decodeRules()
50.1353 + {
50.1354 + decodeStartRule();
50.1355 + decodeEndRule();
50.1356 + }
50.1357 +
50.1358 + /**
50.1359 + * Decode the start rule and validate the parameters. The parameters are
50.1360 + * expected to be in encoded form, which represents the various rule modes
50.1361 + * by negating or zeroing certain values. Representation formats are:
50.1362 + * <p>
50.1363 + * <pre>
50.1364 + * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST
50.1365 + * ------------ ----- -------- -------- ----------
50.1366 + * month 0..11 same same same don't care
50.1367 + * day -5..5 1..31 1..31 -1..-31 0
50.1368 + * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care
50.1369 + * time 0..ONEDAY same same same don't care
50.1370 + * </pre>
50.1371 + * The range for month does not include UNDECIMBER since this class is
50.1372 + * really specific to GregorianCalendar, which does not use that month.
50.1373 + * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
50.1374 + * end rule is an exclusive limit point. That is, the range of times that
50.1375 + * are in DST include those >= the start and < the end. For this reason,
50.1376 + * it should be possible to specify an end of ONEDAY in order to include the
50.1377 + * entire day. Although this is equivalent to time 0 of the following day,
50.1378 + * it's not always possible to specify that, for example, on December 31.
50.1379 + * While arguably the start range should still be 0..ONEDAY-1, we keep
50.1380 + * the start and end ranges the same for consistency.
50.1381 + */
50.1382 + private void decodeStartRule() {
50.1383 + useDaylight = (startDay != 0) && (endDay != 0);
50.1384 + if (startDay != 0) {
50.1385 + if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
50.1386 + throw new IllegalArgumentException(
50.1387 + "Illegal start month " + startMonth);
50.1388 + }
50.1389 + if (startTime < 0 || startTime > millisPerDay) {
50.1390 + throw new IllegalArgumentException(
50.1391 + "Illegal start time " + startTime);
50.1392 + }
50.1393 + if (startDayOfWeek == 0) {
50.1394 + startMode = DOM_MODE;
50.1395 + } else {
50.1396 + if (startDayOfWeek > 0) {
50.1397 + startMode = DOW_IN_MONTH_MODE;
50.1398 + } else {
50.1399 + startDayOfWeek = -startDayOfWeek;
50.1400 + if (startDay > 0) {
50.1401 + startMode = DOW_GE_DOM_MODE;
50.1402 + } else {
50.1403 + startDay = -startDay;
50.1404 + startMode = DOW_LE_DOM_MODE;
50.1405 + }
50.1406 + }
50.1407 + if (startDayOfWeek > Calendar.SATURDAY) {
50.1408 + throw new IllegalArgumentException(
50.1409 + "Illegal start day of week " + startDayOfWeek);
50.1410 + }
50.1411 + }
50.1412 + if (startMode == DOW_IN_MONTH_MODE) {
50.1413 + if (startDay < -5 || startDay > 5) {
50.1414 + throw new IllegalArgumentException(
50.1415 + "Illegal start day of week in month " + startDay);
50.1416 + }
50.1417 + } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
50.1418 + throw new IllegalArgumentException(
50.1419 + "Illegal start day " + startDay);
50.1420 + }
50.1421 + }
50.1422 + }
50.1423 +
50.1424 + /**
50.1425 + * Decode the end rule and validate the parameters. This method is exactly
50.1426 + * analogous to decodeStartRule().
50.1427 + * @see decodeStartRule
50.1428 + */
50.1429 + private void decodeEndRule() {
50.1430 + useDaylight = (startDay != 0) && (endDay != 0);
50.1431 + if (endDay != 0) {
50.1432 + if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
50.1433 + throw new IllegalArgumentException(
50.1434 + "Illegal end month " + endMonth);
50.1435 + }
50.1436 + if (endTime < 0 || endTime > millisPerDay) {
50.1437 + throw new IllegalArgumentException(
50.1438 + "Illegal end time " + endTime);
50.1439 + }
50.1440 + if (endDayOfWeek == 0) {
50.1441 + endMode = DOM_MODE;
50.1442 + } else {
50.1443 + if (endDayOfWeek > 0) {
50.1444 + endMode = DOW_IN_MONTH_MODE;
50.1445 + } else {
50.1446 + endDayOfWeek = -endDayOfWeek;
50.1447 + if (endDay > 0) {
50.1448 + endMode = DOW_GE_DOM_MODE;
50.1449 + } else {
50.1450 + endDay = -endDay;
50.1451 + endMode = DOW_LE_DOM_MODE;
50.1452 + }
50.1453 + }
50.1454 + if (endDayOfWeek > Calendar.SATURDAY) {
50.1455 + throw new IllegalArgumentException(
50.1456 + "Illegal end day of week " + endDayOfWeek);
50.1457 + }
50.1458 + }
50.1459 + if (endMode == DOW_IN_MONTH_MODE) {
50.1460 + if (endDay < -5 || endDay > 5) {
50.1461 + throw new IllegalArgumentException(
50.1462 + "Illegal end day of week in month " + endDay);
50.1463 + }
50.1464 + } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
50.1465 + throw new IllegalArgumentException(
50.1466 + "Illegal end day " + endDay);
50.1467 + }
50.1468 + }
50.1469 + }
50.1470 +
50.1471 + /**
50.1472 + * Make rules compatible to 1.1 FCS code. Since 1.1 FCS code only understands
50.1473 + * day-of-week-in-month rules, we must modify other modes of rules to their
50.1474 + * approximate equivalent in 1.1 FCS terms. This method is used when streaming
50.1475 + * out objects of this class. After it is called, the rules will be modified,
50.1476 + * with a possible loss of information. startMode and endMode will NOT be
50.1477 + * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
50.1478 + * since the rule modification is only intended to be temporary.
50.1479 + */
50.1480 + private void makeRulesCompatible()
50.1481 + {
50.1482 + switch (startMode) {
50.1483 + case DOM_MODE:
50.1484 + startDay = 1 + (startDay / 7);
50.1485 + startDayOfWeek = Calendar.SUNDAY;
50.1486 + break;
50.1487 +
50.1488 + case DOW_GE_DOM_MODE:
50.1489 + // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
50.1490 + // that is, Sun>=1 == firstSun.
50.1491 + if (startDay != 1) {
50.1492 + startDay = 1 + (startDay / 7);
50.1493 + }
50.1494 + break;
50.1495 +
50.1496 + case DOW_LE_DOM_MODE:
50.1497 + if (startDay >= 30) {
50.1498 + startDay = -1;
50.1499 + } else {
50.1500 + startDay = 1 + (startDay / 7);
50.1501 + }
50.1502 + break;
50.1503 + }
50.1504 +
50.1505 + switch (endMode) {
50.1506 + case DOM_MODE:
50.1507 + endDay = 1 + (endDay / 7);
50.1508 + endDayOfWeek = Calendar.SUNDAY;
50.1509 + break;
50.1510 +
50.1511 + case DOW_GE_DOM_MODE:
50.1512 + // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
50.1513 + // that is, Sun>=1 == firstSun.
50.1514 + if (endDay != 1) {
50.1515 + endDay = 1 + (endDay / 7);
50.1516 + }
50.1517 + break;
50.1518 +
50.1519 + case DOW_LE_DOM_MODE:
50.1520 + if (endDay >= 30) {
50.1521 + endDay = -1;
50.1522 + } else {
50.1523 + endDay = 1 + (endDay / 7);
50.1524 + }
50.1525 + break;
50.1526 + }
50.1527 +
50.1528 + /*
50.1529 + * Adjust the start and end times to wall time. This works perfectly
50.1530 + * well unless it pushes into the next or previous day. If that
50.1531 + * happens, we attempt to adjust the day rule somewhat crudely. The day
50.1532 + * rules have been forced into DOW_IN_MONTH mode already, so we change
50.1533 + * the day of week to move forward or back by a day. It's possible to
50.1534 + * make a more refined adjustment of the original rules first, but in
50.1535 + * most cases this extra effort will go to waste once we adjust the day
50.1536 + * rules anyway.
50.1537 + */
50.1538 + switch (startTimeMode) {
50.1539 + case UTC_TIME:
50.1540 + startTime += rawOffset;
50.1541 + break;
50.1542 + }
50.1543 + while (startTime < 0) {
50.1544 + startTime += millisPerDay;
50.1545 + startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
50.1546 + }
50.1547 + while (startTime >= millisPerDay) {
50.1548 + startTime -= millisPerDay;
50.1549 + startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
50.1550 + }
50.1551 +
50.1552 + switch (endTimeMode) {
50.1553 + case UTC_TIME:
50.1554 + endTime += rawOffset + dstSavings;
50.1555 + break;
50.1556 + case STANDARD_TIME:
50.1557 + endTime += dstSavings;
50.1558 + }
50.1559 + while (endTime < 0) {
50.1560 + endTime += millisPerDay;
50.1561 + endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
50.1562 + }
50.1563 + while (endTime >= millisPerDay) {
50.1564 + endTime -= millisPerDay;
50.1565 + endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
50.1566 + }
50.1567 + }
50.1568 +
50.1569 + /**
50.1570 + * Pack the start and end rules into an array of bytes. Only pack
50.1571 + * data which is not preserved by makeRulesCompatible.
50.1572 + */
50.1573 + private byte[] packRules()
50.1574 + {
50.1575 + byte[] rules = new byte[6];
50.1576 + rules[0] = (byte)startDay;
50.1577 + rules[1] = (byte)startDayOfWeek;
50.1578 + rules[2] = (byte)endDay;
50.1579 + rules[3] = (byte)endDayOfWeek;
50.1580 +
50.1581 + // As of serial version 2, include time modes
50.1582 + rules[4] = (byte)startTimeMode;
50.1583 + rules[5] = (byte)endTimeMode;
50.1584 +
50.1585 + return rules;
50.1586 + }
50.1587 +
50.1588 + /**
50.1589 + * Given an array of bytes produced by packRules, interpret them
50.1590 + * as the start and end rules.
50.1591 + */
50.1592 + private void unpackRules(byte[] rules)
50.1593 + {
50.1594 + startDay = rules[0];
50.1595 + startDayOfWeek = rules[1];
50.1596 + endDay = rules[2];
50.1597 + endDayOfWeek = rules[3];
50.1598 +
50.1599 + // As of serial version 2, include time modes
50.1600 + if (rules.length >= 6) {
50.1601 + startTimeMode = rules[4];
50.1602 + endTimeMode = rules[5];
50.1603 + }
50.1604 + }
50.1605 +
50.1606 + /**
50.1607 + * Pack the start and end times into an array of bytes. This is required
50.1608 + * as of serial version 2.
50.1609 + */
50.1610 + private int[] packTimes() {
50.1611 + int[] times = new int[2];
50.1612 + times[0] = startTime;
50.1613 + times[1] = endTime;
50.1614 + return times;
50.1615 + }
50.1616 +
50.1617 + /**
50.1618 + * Unpack the start and end times from an array of bytes. This is required
50.1619 + * as of serial version 2.
50.1620 + */
50.1621 + private void unpackTimes(int[] times) {
50.1622 + startTime = times[0];
50.1623 + endTime = times[1];
50.1624 + }
50.1625 +
50.1626 + /**
50.1627 + * Save the state of this object to a stream (i.e., serialize it).
50.1628 + *
50.1629 + * @serialData We write out two formats, a JDK 1.1 compatible format, using
50.1630 + * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
50.1631 + * by the full rules, in packed format, in the optional section. The
50.1632 + * optional section will be ignored by JDK 1.1 code upon stream in.
50.1633 + * <p> Contents of the optional section: The length of a byte array is
50.1634 + * emitted (int); this is 4 as of this release. The byte array of the given
50.1635 + * length is emitted. The contents of the byte array are the true values of
50.1636 + * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
50.1637 + * <code>endDay</code>, and <code>endDayOfWeek</code>. The values of these
50.1638 + * fields in the required section are approximate values suited to the rule
50.1639 + * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
50.1640 + * JDK 1.1.
50.1641 + */
50.1642 + private void writeObject(ObjectOutputStream stream)
50.1643 + throws IOException
50.1644 + {
50.1645 + // Construct a binary rule
50.1646 + byte[] rules = packRules();
50.1647 + int[] times = packTimes();
50.1648 +
50.1649 + // Convert to 1.1 FCS rules. This step may cause us to lose information.
50.1650 + makeRulesCompatible();
50.1651 +
50.1652 + // Write out the 1.1 FCS rules
50.1653 + stream.defaultWriteObject();
50.1654 +
50.1655 + // Write out the binary rules in the optional data area of the stream.
50.1656 + stream.writeInt(rules.length);
50.1657 + stream.write(rules);
50.1658 + stream.writeObject(times);
50.1659 +
50.1660 + // Recover the original rules. This recovers the information lost
50.1661 + // by makeRulesCompatible.
50.1662 + unpackRules(rules);
50.1663 + unpackTimes(times);
50.1664 + }
50.1665 +
50.1666 + /**
50.1667 + * Reconstitute this object from a stream (i.e., deserialize it).
50.1668 + *
50.1669 + * We handle both JDK 1.1
50.1670 + * binary formats and full formats with a packed byte array.
50.1671 + */
50.1672 + private void readObject(ObjectInputStream stream)
50.1673 + throws IOException, ClassNotFoundException
50.1674 + {
50.1675 + stream.defaultReadObject();
50.1676 +
50.1677 + if (serialVersionOnStream < 1) {
50.1678 + // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
50.1679 + // startDayOfWeek and endDayOfWeek were usually uninitialized. We can't do
50.1680 + // too much, so we assume SUNDAY, which actually works most of the time.
50.1681 + if (startDayOfWeek == 0) {
50.1682 + startDayOfWeek = Calendar.SUNDAY;
50.1683 + }
50.1684 + if (endDayOfWeek == 0) {
50.1685 + endDayOfWeek = Calendar.SUNDAY;
50.1686 + }
50.1687 +
50.1688 + // The variables dstSavings, startMode, and endMode are post-1.1, so they
50.1689 + // won't be present if we're reading from a 1.1 stream. Fix them up.
50.1690 + startMode = endMode = DOW_IN_MONTH_MODE;
50.1691 + dstSavings = millisPerHour;
50.1692 + } else {
50.1693 + // For 1.1.4, in addition to the 3 new instance variables, we also
50.1694 + // store the actual rules (which have not be made compatible with 1.1)
50.1695 + // in the optional area. Read them in here and parse them.
50.1696 + int length = stream.readInt();
50.1697 + byte[] rules = new byte[length];
50.1698 + stream.readFully(rules);
50.1699 + unpackRules(rules);
50.1700 + }
50.1701 +
50.1702 + if (serialVersionOnStream >= 2) {
50.1703 + int[] times = (int[]) stream.readObject();
50.1704 + unpackTimes(times);
50.1705 + }
50.1706 +
50.1707 + serialVersionOnStream = currentSerialVersion;
50.1708 + }
50.1709 +}
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
51.2 +++ b/rt/emul/compact/src/main/java/java/util/TimeZone.java Thu Oct 03 15:43:10 2013 +0200
51.3 @@ -0,0 +1,864 @@
51.4 +/*
51.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
51.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
51.7 + *
51.8 + * This code is free software; you can redistribute it and/or modify it
51.9 + * under the terms of the GNU General Public License version 2 only, as
51.10 + * published by the Free Software Foundation. Oracle designates this
51.11 + * particular file as subject to the "Classpath" exception as provided
51.12 + * by Oracle in the LICENSE file that accompanied this code.
51.13 + *
51.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
51.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
51.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
51.17 + * version 2 for more details (a copy is included in the LICENSE file that
51.18 + * accompanied this code).
51.19 + *
51.20 + * You should have received a copy of the GNU General Public License version
51.21 + * 2 along with this work; if not, write to the Free Software Foundation,
51.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
51.23 + *
51.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
51.25 + * or visit www.oracle.com if you need additional information or have any
51.26 + * questions.
51.27 + */
51.28 +
51.29 +/*
51.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
51.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
51.32 + *
51.33 + * The original version of this source code and documentation is copyrighted
51.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
51.35 + * materials are provided under terms of a License Agreement between Taligent
51.36 + * and Sun. This technology is protected by multiple US and International
51.37 + * patents. This notice and attribution to Taligent may not be removed.
51.38 + * Taligent is a registered trademark of Taligent, Inc.
51.39 + *
51.40 + */
51.41 +
51.42 +package java.util;
51.43 +
51.44 +import java.io.Serializable;
51.45 +import java.lang.ref.SoftReference;
51.46 +import java.security.AccessController;
51.47 +import java.security.PrivilegedAction;
51.48 +import java.util.concurrent.ConcurrentHashMap;
51.49 +import sun.security.action.GetPropertyAction;
51.50 +import sun.util.TimeZoneNameUtility;
51.51 +import sun.util.calendar.ZoneInfo;
51.52 +import sun.util.calendar.ZoneInfoFile;
51.53 +
51.54 +/**
51.55 + * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
51.56 + * savings.
51.57 + *
51.58 + * <p>
51.59 + * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
51.60 + * which creates a <code>TimeZone</code> based on the time zone where the program
51.61 + * is running. For example, for a program running in Japan, <code>getDefault</code>
51.62 + * creates a <code>TimeZone</code> object based on Japanese Standard Time.
51.63 + *
51.64 + * <p>
51.65 + * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
51.66 + * along with a time zone ID. For instance, the time zone ID for the
51.67 + * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
51.68 + * U.S. Pacific Time <code>TimeZone</code> object with:
51.69 + * <blockquote><pre>
51.70 + * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
51.71 + * </pre></blockquote>
51.72 + * You can use the <code>getAvailableIDs</code> method to iterate through
51.73 + * all the supported time zone IDs. You can then choose a
51.74 + * supported ID to get a <code>TimeZone</code>.
51.75 + * If the time zone you want is not represented by one of the
51.76 + * supported IDs, then a custom time zone ID can be specified to
51.77 + * produce a TimeZone. The syntax of a custom time zone ID is:
51.78 + *
51.79 + * <blockquote><pre>
51.80 + * <a name="CustomID"><i>CustomID:</i></a>
51.81 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
51.82 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
51.83 + * <code>GMT</code> <i>Sign</i> <i>Hours</i>
51.84 + * <i>Sign:</i> one of
51.85 + * <code>+ -</code>
51.86 + * <i>Hours:</i>
51.87 + * <i>Digit</i>
51.88 + * <i>Digit</i> <i>Digit</i>
51.89 + * <i>Minutes:</i>
51.90 + * <i>Digit</i> <i>Digit</i>
51.91 + * <i>Digit:</i> one of
51.92 + * <code>0 1 2 3 4 5 6 7 8 9</code>
51.93 + * </pre></blockquote>
51.94 + *
51.95 + * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
51.96 + * between 00 to 59. For example, "GMT+10" and "GMT+0010" mean ten
51.97 + * hours and ten minutes ahead of GMT, respectively.
51.98 + * <p>
51.99 + * The format is locale independent and digits must be taken from the
51.100 + * Basic Latin block of the Unicode standard. No daylight saving time
51.101 + * transition schedule can be specified with a custom time zone ID. If
51.102 + * the specified string doesn't match the syntax, <code>"GMT"</code>
51.103 + * is used.
51.104 + * <p>
51.105 + * When creating a <code>TimeZone</code>, the specified custom time
51.106 + * zone ID is normalized in the following syntax:
51.107 + * <blockquote><pre>
51.108 + * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
51.109 + * <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
51.110 + * <i>Sign:</i> one of
51.111 + * <code>+ -</code>
51.112 + * <i>TwoDigitHours:</i>
51.113 + * <i>Digit</i> <i>Digit</i>
51.114 + * <i>Minutes:</i>
51.115 + * <i>Digit</i> <i>Digit</i>
51.116 + * <i>Digit:</i> one of
51.117 + * <code>0 1 2 3 4 5 6 7 8 9</code>
51.118 + * </pre></blockquote>
51.119 + * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
51.120 + *
51.121 + * <h4>Three-letter time zone IDs</h4>
51.122 + *
51.123 + * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
51.124 + * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
51.125 + * use is deprecated</strong> because the same abbreviation is often used
51.126 + * for multiple time zones (for example, "CST" could be U.S. "Central Standard
51.127 + * Time" and "China Standard Time"), and the Java platform can then only
51.128 + * recognize one of them.
51.129 + *
51.130 + *
51.131 + * @see Calendar
51.132 + * @see GregorianCalendar
51.133 + * @see SimpleTimeZone
51.134 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
51.135 + * @since JDK1.1
51.136 + */
51.137 +abstract public class TimeZone implements Serializable, Cloneable {
51.138 + /**
51.139 + * Sole constructor. (For invocation by subclass constructors, typically
51.140 + * implicit.)
51.141 + */
51.142 + public TimeZone() {
51.143 + }
51.144 +
51.145 + /**
51.146 + * A style specifier for <code>getDisplayName()</code> indicating
51.147 + * a short name, such as "PST."
51.148 + * @see #LONG
51.149 + * @since 1.2
51.150 + */
51.151 + public static final int SHORT = 0;
51.152 +
51.153 + /**
51.154 + * A style specifier for <code>getDisplayName()</code> indicating
51.155 + * a long name, such as "Pacific Standard Time."
51.156 + * @see #SHORT
51.157 + * @since 1.2
51.158 + */
51.159 + public static final int LONG = 1;
51.160 +
51.161 + // Constants used internally; unit is milliseconds
51.162 + private static final int ONE_MINUTE = 60*1000;
51.163 + private static final int ONE_HOUR = 60*ONE_MINUTE;
51.164 + private static final int ONE_DAY = 24*ONE_HOUR;
51.165 +
51.166 + // Proclaim serialization compatibility with JDK 1.1
51.167 + static final long serialVersionUID = 3581463369166924961L;
51.168 +
51.169 + /**
51.170 + * Gets the time zone offset, for current date, modified in case of
51.171 + * daylight savings. This is the offset to add to UTC to get local time.
51.172 + * <p>
51.173 + * This method returns a historically correct offset if an
51.174 + * underlying <code>TimeZone</code> implementation subclass
51.175 + * supports historical Daylight Saving Time schedule and GMT
51.176 + * offset changes.
51.177 + *
51.178 + * @param era the era of the given date.
51.179 + * @param year the year in the given date.
51.180 + * @param month the month in the given date.
51.181 + * Month is 0-based. e.g., 0 for January.
51.182 + * @param day the day-in-month of the given date.
51.183 + * @param dayOfWeek the day-of-week of the given date.
51.184 + * @param milliseconds the milliseconds in day in <em>standard</em>
51.185 + * local time.
51.186 + *
51.187 + * @return the offset in milliseconds to add to GMT to get local time.
51.188 + *
51.189 + * @see Calendar#ZONE_OFFSET
51.190 + * @see Calendar#DST_OFFSET
51.191 + */
51.192 + public abstract int getOffset(int era, int year, int month, int day,
51.193 + int dayOfWeek, int milliseconds);
51.194 +
51.195 + /**
51.196 + * Returns the offset of this time zone from UTC at the specified
51.197 + * date. If Daylight Saving Time is in effect at the specified
51.198 + * date, the offset value is adjusted with the amount of daylight
51.199 + * saving.
51.200 + * <p>
51.201 + * This method returns a historically correct offset value if an
51.202 + * underlying TimeZone implementation subclass supports historical
51.203 + * Daylight Saving Time schedule and GMT offset changes.
51.204 + *
51.205 + * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
51.206 + * @return the amount of time in milliseconds to add to UTC to get local time.
51.207 + *
51.208 + * @see Calendar#ZONE_OFFSET
51.209 + * @see Calendar#DST_OFFSET
51.210 + * @since 1.4
51.211 + */
51.212 + public int getOffset(long date) {
51.213 + if (inDaylightTime(new Date(date))) {
51.214 + return getRawOffset() + getDSTSavings();
51.215 + }
51.216 + return getRawOffset();
51.217 + }
51.218 +
51.219 + /**
51.220 + * Gets the raw GMT offset and the amount of daylight saving of this
51.221 + * time zone at the given time.
51.222 + * @param date the milliseconds (since January 1, 1970,
51.223 + * 00:00:00.000 GMT) at which the time zone offset and daylight
51.224 + * saving amount are found
51.225 + * @param offset an array of int where the raw GMT offset
51.226 + * (offset[0]) and daylight saving amount (offset[1]) are stored,
51.227 + * or null if those values are not needed. The method assumes that
51.228 + * the length of the given array is two or larger.
51.229 + * @return the total amount of the raw GMT offset and daylight
51.230 + * saving at the specified date.
51.231 + *
51.232 + * @see Calendar#ZONE_OFFSET
51.233 + * @see Calendar#DST_OFFSET
51.234 + */
51.235 + int getOffsets(long date, int[] offsets) {
51.236 + int rawoffset = getRawOffset();
51.237 + int dstoffset = 0;
51.238 + if (inDaylightTime(new Date(date))) {
51.239 + dstoffset = getDSTSavings();
51.240 + }
51.241 + if (offsets != null) {
51.242 + offsets[0] = rawoffset;
51.243 + offsets[1] = dstoffset;
51.244 + }
51.245 + return rawoffset + dstoffset;
51.246 + }
51.247 +
51.248 + /**
51.249 + * Sets the base time zone offset to GMT.
51.250 + * This is the offset to add to UTC to get local time.
51.251 + * <p>
51.252 + * If an underlying <code>TimeZone</code> implementation subclass
51.253 + * supports historical GMT offset changes, the specified GMT
51.254 + * offset is set as the latest GMT offset and the difference from
51.255 + * the known latest GMT offset value is used to adjust all
51.256 + * historical GMT offset values.
51.257 + *
51.258 + * @param offsetMillis the given base time zone offset to GMT.
51.259 + */
51.260 + abstract public void setRawOffset(int offsetMillis);
51.261 +
51.262 + /**
51.263 + * Returns the amount of time in milliseconds to add to UTC to get
51.264 + * standard time in this time zone. Because this value is not
51.265 + * affected by daylight saving time, it is called <I>raw
51.266 + * offset</I>.
51.267 + * <p>
51.268 + * If an underlying <code>TimeZone</code> implementation subclass
51.269 + * supports historical GMT offset changes, the method returns the
51.270 + * raw offset value of the current date. In Honolulu, for example,
51.271 + * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
51.272 + * this method always returns -36000000 milliseconds (i.e., -10
51.273 + * hours).
51.274 + *
51.275 + * @return the amount of raw offset time in milliseconds to add to UTC.
51.276 + * @see Calendar#ZONE_OFFSET
51.277 + */
51.278 + public abstract int getRawOffset();
51.279 +
51.280 + /**
51.281 + * Gets the ID of this time zone.
51.282 + * @return the ID of this time zone.
51.283 + */
51.284 + public String getID()
51.285 + {
51.286 + return ID;
51.287 + }
51.288 +
51.289 + /**
51.290 + * Sets the time zone ID. This does not change any other data in
51.291 + * the time zone object.
51.292 + * @param ID the new time zone ID.
51.293 + */
51.294 + public void setID(String ID)
51.295 + {
51.296 + if (ID == null) {
51.297 + throw new NullPointerException();
51.298 + }
51.299 + this.ID = ID;
51.300 + }
51.301 +
51.302 + /**
51.303 + * Returns a long standard time name of this {@code TimeZone} suitable for
51.304 + * presentation to the user in the default locale.
51.305 + *
51.306 + * <p>This method is equivalent to:
51.307 + * <pre><blockquote>
51.308 + * getDisplayName(false, {@link #LONG},
51.309 + * Locale.getDefault({@link Locale.Category#DISPLAY}))
51.310 + * </blockquote></pre>
51.311 + *
51.312 + * @return the human-readable name of this time zone in the default locale.
51.313 + * @since 1.2
51.314 + * @see #getDisplayName(boolean, int, Locale)
51.315 + * @see Locale#getDefault(Locale.Category)
51.316 + * @see Locale.Category
51.317 + */
51.318 + public final String getDisplayName() {
51.319 + return getDisplayName(false, LONG,
51.320 + Locale.getDefault(Locale.Category.DISPLAY));
51.321 + }
51.322 +
51.323 + /**
51.324 + * Returns a long standard time name of this {@code TimeZone} suitable for
51.325 + * presentation to the user in the specified {@code locale}.
51.326 + *
51.327 + * <p>This method is equivalent to:
51.328 + * <pre><blockquote>
51.329 + * getDisplayName(false, {@link #LONG}, locale)
51.330 + * </blockquote></pre>
51.331 + *
51.332 + * @param locale the locale in which to supply the display name.
51.333 + * @return the human-readable name of this time zone in the given locale.
51.334 + * @exception NullPointerException if {@code locale} is {@code null}.
51.335 + * @since 1.2
51.336 + * @see #getDisplayName(boolean, int, Locale)
51.337 + */
51.338 + public final String getDisplayName(Locale locale) {
51.339 + return getDisplayName(false, LONG, locale);
51.340 + }
51.341 +
51.342 + /**
51.343 + * Returns a name in the specified {@code style} of this {@code TimeZone}
51.344 + * suitable for presentation to the user in the default locale. If the
51.345 + * specified {@code daylight} is {@code true}, a Daylight Saving Time name
51.346 + * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
51.347 + * Time). Otherwise, a Standard Time name is returned.
51.348 + *
51.349 + * <p>This method is equivalent to:
51.350 + * <pre><blockquote>
51.351 + * getDisplayName(daylight, style,
51.352 + * Locale.getDefault({@link Locale.Category#DISPLAY}))
51.353 + * </blockquote></pre>
51.354 + *
51.355 + * @param daylight {@code true} specifying a Daylight Saving Time name, or
51.356 + * {@code false} specifying a Standard Time name
51.357 + * @param style either {@link #LONG} or {@link #SHORT}
51.358 + * @return the human-readable name of this time zone in the default locale.
51.359 + * @exception IllegalArgumentException if {@code style} is invalid.
51.360 + * @since 1.2
51.361 + * @see #getDisplayName(boolean, int, Locale)
51.362 + * @see Locale#getDefault(Locale.Category)
51.363 + * @see Locale.Category
51.364 + * @see java.text.DateFormatSymbols#getZoneStrings()
51.365 + */
51.366 + public final String getDisplayName(boolean daylight, int style) {
51.367 + return getDisplayName(daylight, style,
51.368 + Locale.getDefault(Locale.Category.DISPLAY));
51.369 + }
51.370 +
51.371 + /**
51.372 + * Returns a name in the specified {@code style} of this {@code TimeZone}
51.373 + * suitable for presentation to the user in the specified {@code
51.374 + * locale}. If the specified {@code daylight} is {@code true}, a Daylight
51.375 + * Saving Time name is returned (even if this {@code TimeZone} doesn't
51.376 + * observe Daylight Saving Time). Otherwise, a Standard Time name is
51.377 + * returned.
51.378 + *
51.379 + * <p>When looking up a time zone name, the {@linkplain
51.380 + * ResourceBundle.Control#getCandidateLocales(String,Locale) default
51.381 + * <code>Locale</code> search path of <code>ResourceBundle</code>} derived
51.382 + * from the specified {@code locale} is used. (No {@linkplain
51.383 + * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
51.384 + * <code>Locale</code>} search is performed.) If a time zone name in any
51.385 + * {@code Locale} of the search path, including {@link Locale#ROOT}, is
51.386 + * found, the name is returned. Otherwise, a string in the
51.387 + * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned.
51.388 + *
51.389 + * @param daylight {@code true} specifying a Daylight Saving Time name, or
51.390 + * {@code false} specifying a Standard Time name
51.391 + * @param style either {@link #LONG} or {@link #SHORT}
51.392 + * @param locale the locale in which to supply the display name.
51.393 + * @return the human-readable name of this time zone in the given locale.
51.394 + * @exception IllegalArgumentException if {@code style} is invalid.
51.395 + * @exception NullPointerException if {@code locale} is {@code null}.
51.396 + * @since 1.2
51.397 + * @see java.text.DateFormatSymbols#getZoneStrings()
51.398 + */
51.399 + public String getDisplayName(boolean daylight, int style, Locale locale) {
51.400 + if (style != SHORT && style != LONG) {
51.401 + throw new IllegalArgumentException("Illegal style: " + style);
51.402 + }
51.403 +
51.404 + String id = getID();
51.405 + String[] names = getDisplayNames(id, locale);
51.406 + if (names == null) {
51.407 + if (id.startsWith("GMT")) {
51.408 + char sign = id.charAt(3);
51.409 + if (sign == '+' || sign == '-') {
51.410 + return id;
51.411 + }
51.412 + }
51.413 + int offset = getRawOffset();
51.414 + if (daylight) {
51.415 + offset += getDSTSavings();
51.416 + }
51.417 + return ZoneInfoFile.toCustomID(offset);
51.418 + }
51.419 +
51.420 + int index = daylight ? 3 : 1;
51.421 + if (style == SHORT) {
51.422 + index++;
51.423 + }
51.424 + return names[index];
51.425 + }
51.426 +
51.427 + private static class DisplayNames {
51.428 + // Cache for managing display names per timezone per locale
51.429 + // The structure is:
51.430 + // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
51.431 + private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
51.432 + new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
51.433 + }
51.434 +
51.435 + private static final String[] getDisplayNames(String id, Locale locale) {
51.436 + Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
51.437 +
51.438 + SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
51.439 + if (ref != null) {
51.440 + Map<Locale, String[]> perLocale = ref.get();
51.441 + if (perLocale != null) {
51.442 + String[] names = perLocale.get(locale);
51.443 + if (names != null) {
51.444 + return names;
51.445 + }
51.446 + names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
51.447 + if (names != null) {
51.448 + perLocale.put(locale, names);
51.449 + }
51.450 + return names;
51.451 + }
51.452 + }
51.453 +
51.454 + String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
51.455 + if (names != null) {
51.456 + Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
51.457 + perLocale.put(locale, names);
51.458 + ref = new SoftReference<Map<Locale, String[]>>(perLocale);
51.459 + displayNames.put(id, ref);
51.460 + }
51.461 + return names;
51.462 + }
51.463 +
51.464 + /**
51.465 + * Returns the amount of time to be added to local standard time
51.466 + * to get local wall clock time.
51.467 + *
51.468 + * <p>The default implementation returns 3600000 milliseconds
51.469 + * (i.e., one hour) if a call to {@link #useDaylightTime()}
51.470 + * returns {@code true}. Otherwise, 0 (zero) is returned.
51.471 + *
51.472 + * <p>If an underlying {@code TimeZone} implementation subclass
51.473 + * supports historical and future Daylight Saving Time schedule
51.474 + * changes, this method returns the amount of saving time of the
51.475 + * last known Daylight Saving Time rule that can be a future
51.476 + * prediction.
51.477 + *
51.478 + * <p>If the amount of saving time at any given time stamp is
51.479 + * required, construct a {@link Calendar} with this {@code
51.480 + * TimeZone} and the time stamp, and call {@link Calendar#get(int)
51.481 + * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
51.482 + *
51.483 + * @return the amount of saving time in milliseconds
51.484 + * @since 1.4
51.485 + * @see #inDaylightTime(Date)
51.486 + * @see #getOffset(long)
51.487 + * @see #getOffset(int,int,int,int,int,int)
51.488 + * @see Calendar#ZONE_OFFSET
51.489 + */
51.490 + public int getDSTSavings() {
51.491 + if (useDaylightTime()) {
51.492 + return 3600000;
51.493 + }
51.494 + return 0;
51.495 + }
51.496 +
51.497 + /**
51.498 + * Queries if this {@code TimeZone} uses Daylight Saving Time.
51.499 + *
51.500 + * <p>If an underlying {@code TimeZone} implementation subclass
51.501 + * supports historical and future Daylight Saving Time schedule
51.502 + * changes, this method refers to the last known Daylight Saving Time
51.503 + * rule that can be a future prediction and may not be the same as
51.504 + * the current rule. Consider calling {@link #observesDaylightTime()}
51.505 + * if the current rule should also be taken into account.
51.506 + *
51.507 + * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
51.508 + * {@code false}, otherwise.
51.509 + * @see #inDaylightTime(Date)
51.510 + * @see Calendar#DST_OFFSET
51.511 + */
51.512 + public abstract boolean useDaylightTime();
51.513 +
51.514 + /**
51.515 + * Returns {@code true} if this {@code TimeZone} is currently in
51.516 + * Daylight Saving Time, or if a transition from Standard Time to
51.517 + * Daylight Saving Time occurs at any future time.
51.518 + *
51.519 + * <p>The default implementation returns {@code true} if
51.520 + * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
51.521 + * returns {@code true}.
51.522 + *
51.523 + * @return {@code true} if this {@code TimeZone} is currently in
51.524 + * Daylight Saving Time, or if a transition from Standard Time to
51.525 + * Daylight Saving Time occurs at any future time; {@code false}
51.526 + * otherwise.
51.527 + * @since 1.7
51.528 + * @see #useDaylightTime()
51.529 + * @see #inDaylightTime(Date)
51.530 + * @see Calendar#DST_OFFSET
51.531 + */
51.532 + public boolean observesDaylightTime() {
51.533 + return useDaylightTime() || inDaylightTime(new Date());
51.534 + }
51.535 +
51.536 + /**
51.537 + * Queries if the given {@code date} is in Daylight Saving Time in
51.538 + * this time zone.
51.539 + *
51.540 + * @param date the given Date.
51.541 + * @return {@code true} if the given date is in Daylight Saving Time,
51.542 + * {@code false}, otherwise.
51.543 + */
51.544 + abstract public boolean inDaylightTime(Date date);
51.545 +
51.546 + /**
51.547 + * Gets the <code>TimeZone</code> for the given ID.
51.548 + *
51.549 + * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
51.550 + * such as "PST", a full name such as "America/Los_Angeles", or a custom
51.551 + * ID such as "GMT-8:00". Note that the support of abbreviations is
51.552 + * for JDK 1.1.x compatibility only and full names should be used.
51.553 + *
51.554 + * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
51.555 + * cannot be understood.
51.556 + */
51.557 + public static synchronized TimeZone getTimeZone(String ID) {
51.558 + return getTimeZone(ID, true);
51.559 + }
51.560 +
51.561 + private static TimeZone getTimeZone(String ID, boolean fallback) {
51.562 + TimeZone tz = ZoneInfo.getTimeZone(ID);
51.563 + if (tz == null) {
51.564 + tz = parseCustomTimeZone(ID);
51.565 + if (tz == null && fallback) {
51.566 + tz = new ZoneInfo(GMT_ID, 0);
51.567 + }
51.568 + }
51.569 + return tz;
51.570 + }
51.571 +
51.572 + /**
51.573 + * Gets the available IDs according to the given time zone offset in milliseconds.
51.574 + *
51.575 + * @param rawOffset the given time zone GMT offset in milliseconds.
51.576 + * @return an array of IDs, where the time zone for that ID has
51.577 + * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
51.578 + * both have GMT-07:00, but differ in daylight saving behavior.
51.579 + * @see #getRawOffset()
51.580 + */
51.581 + public static synchronized String[] getAvailableIDs(int rawOffset) {
51.582 + return ZoneInfo.getAvailableIDs(rawOffset);
51.583 + }
51.584 +
51.585 + /**
51.586 + * Gets all the available IDs supported.
51.587 + * @return an array of IDs.
51.588 + */
51.589 + public static synchronized String[] getAvailableIDs() {
51.590 + return ZoneInfo.getAvailableIDs();
51.591 + }
51.592 +
51.593 + /**
51.594 + * Gets the platform defined TimeZone ID.
51.595 + **/
51.596 + private static native String getSystemTimeZoneID(String javaHome,
51.597 + String country);
51.598 +
51.599 + /**
51.600 + * Gets the custom time zone ID based on the GMT offset of the
51.601 + * platform. (e.g., "GMT+08:00")
51.602 + */
51.603 + private static native String getSystemGMTOffsetID();
51.604 +
51.605 + /**
51.606 + * Gets the default <code>TimeZone</code> for this host.
51.607 + * The source of the default <code>TimeZone</code>
51.608 + * may vary with implementation.
51.609 + * @return a default <code>TimeZone</code>.
51.610 + * @see #setDefault
51.611 + */
51.612 + public static TimeZone getDefault() {
51.613 + return (TimeZone) getDefaultRef().clone();
51.614 + }
51.615 +
51.616 + /**
51.617 + * Returns the reference to the default TimeZone object. This
51.618 + * method doesn't create a clone.
51.619 + */
51.620 + static TimeZone getDefaultRef() {
51.621 + TimeZone defaultZone = defaultZoneTL.get();
51.622 + if (defaultZone == null) {
51.623 + defaultZone = defaultTimeZone;
51.624 + if (defaultZone == null) {
51.625 + // Need to initialize the default time zone.
51.626 + defaultZone = setDefaultZone();
51.627 + assert defaultZone != null;
51.628 + }
51.629 + }
51.630 + // Don't clone here.
51.631 + return defaultZone;
51.632 + }
51.633 +
51.634 + private static synchronized TimeZone setDefaultZone() {
51.635 + TimeZone tz = null;
51.636 + // get the time zone ID from the system properties
51.637 + String zoneID = AccessController.doPrivileged(
51.638 + new GetPropertyAction("user.timezone"));
51.639 +
51.640 + // if the time zone ID is not set (yet), perform the
51.641 + // platform to Java time zone ID mapping.
51.642 + if (zoneID == null || zoneID.equals("")) {
51.643 + String country = AccessController.doPrivileged(
51.644 + new GetPropertyAction("user.country"));
51.645 + String javaHome = AccessController.doPrivileged(
51.646 + new GetPropertyAction("java.home"));
51.647 + try {
51.648 + zoneID = getSystemTimeZoneID(javaHome, country);
51.649 + if (zoneID == null) {
51.650 + zoneID = GMT_ID;
51.651 + }
51.652 + } catch (NullPointerException e) {
51.653 + zoneID = GMT_ID;
51.654 + }
51.655 + }
51.656 +
51.657 + // Get the time zone for zoneID. But not fall back to
51.658 + // "GMT" here.
51.659 + tz = getTimeZone(zoneID, false);
51.660 +
51.661 + if (tz == null) {
51.662 + // If the given zone ID is unknown in Java, try to
51.663 + // get the GMT-offset-based time zone ID,
51.664 + // a.k.a. custom time zone ID (e.g., "GMT-08:00").
51.665 + String gmtOffsetID = getSystemGMTOffsetID();
51.666 + if (gmtOffsetID != null) {
51.667 + zoneID = gmtOffsetID;
51.668 + }
51.669 + tz = getTimeZone(zoneID, true);
51.670 + }
51.671 + assert tz != null;
51.672 +
51.673 + final String id = zoneID;
51.674 + AccessController.doPrivileged(new PrivilegedAction<Object>() {
51.675 + public Object run() {
51.676 + System.setProperty("user.timezone", id);
51.677 + return null;
51.678 + }
51.679 + });
51.680 +
51.681 + defaultTimeZone = tz;
51.682 + return tz;
51.683 + }
51.684 +
51.685 + private static boolean hasPermission() {
51.686 + boolean hasPermission = true;
51.687 + SecurityManager sm = System.getSecurityManager();
51.688 + if (sm != null) {
51.689 + try {
51.690 + sm.checkPermission(new PropertyPermission
51.691 + ("user.timezone", "write"));
51.692 + } catch (SecurityException e) {
51.693 + hasPermission = false;
51.694 + }
51.695 + }
51.696 + return hasPermission;
51.697 + }
51.698 +
51.699 + /**
51.700 + * Sets the <code>TimeZone</code> that is
51.701 + * returned by the <code>getDefault</code> method. If <code>zone</code>
51.702 + * is null, reset the default to the value it had originally when the
51.703 + * VM first started.
51.704 + * @param zone the new default time zone
51.705 + * @see #getDefault
51.706 + */
51.707 + public static void setDefault(TimeZone zone)
51.708 + {
51.709 + if (hasPermission()) {
51.710 + synchronized (TimeZone.class) {
51.711 + defaultTimeZone = zone;
51.712 + defaultZoneTL.set(null);
51.713 + }
51.714 + } else {
51.715 + defaultZoneTL.set(zone);
51.716 + }
51.717 + }
51.718 +
51.719 + /**
51.720 + * Returns true if this zone has the same rule and offset as another zone.
51.721 + * That is, if this zone differs only in ID, if at all. Returns false
51.722 + * if the other zone is null.
51.723 + * @param other the <code>TimeZone</code> object to be compared with
51.724 + * @return true if the other zone is not null and is the same as this one,
51.725 + * with the possible exception of the ID
51.726 + * @since 1.2
51.727 + */
51.728 + public boolean hasSameRules(TimeZone other) {
51.729 + return other != null && getRawOffset() == other.getRawOffset() &&
51.730 + useDaylightTime() == other.useDaylightTime();
51.731 + }
51.732 +
51.733 + /**
51.734 + * Creates a copy of this <code>TimeZone</code>.
51.735 + *
51.736 + * @return a clone of this <code>TimeZone</code>
51.737 + */
51.738 + public Object clone()
51.739 + {
51.740 + try {
51.741 + TimeZone other = (TimeZone) super.clone();
51.742 + other.ID = ID;
51.743 + return other;
51.744 + } catch (CloneNotSupportedException e) {
51.745 + throw new InternalError();
51.746 + }
51.747 + }
51.748 +
51.749 + /**
51.750 + * The null constant as a TimeZone.
51.751 + */
51.752 + static final TimeZone NO_TIMEZONE = null;
51.753 +
51.754 + // =======================privates===============================
51.755 +
51.756 + /**
51.757 + * The string identifier of this <code>TimeZone</code>. This is a
51.758 + * programmatic identifier used internally to look up <code>TimeZone</code>
51.759 + * objects from the system table and also to map them to their localized
51.760 + * display names. <code>ID</code> values are unique in the system
51.761 + * table but may not be for dynamically created zones.
51.762 + * @serial
51.763 + */
51.764 + private String ID;
51.765 + private static volatile TimeZone defaultTimeZone;
51.766 + private static final InheritableThreadLocal<TimeZone> defaultZoneTL
51.767 + = new InheritableThreadLocal<TimeZone>();
51.768 +
51.769 + static final String GMT_ID = "GMT";
51.770 + private static final int GMT_ID_LENGTH = 3;
51.771 +
51.772 + /**
51.773 + * Parses a custom time zone identifier and returns a corresponding zone.
51.774 + * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
51.775 + *
51.776 + * @param id a string of the <a href="#CustomID">custom ID form</a>.
51.777 + * @return a newly created TimeZone with the given offset and
51.778 + * no daylight saving time, or null if the id cannot be parsed.
51.779 + */
51.780 + private static final TimeZone parseCustomTimeZone(String id) {
51.781 + int length;
51.782 +
51.783 + // Error if the length of id isn't long enough or id doesn't
51.784 + // start with "GMT".
51.785 + if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
51.786 + id.indexOf(GMT_ID) != 0) {
51.787 + return null;
51.788 + }
51.789 +
51.790 + ZoneInfo zi;
51.791 +
51.792 + // First, we try to find it in the cache with the given
51.793 + // id. Even the id is not normalized, the returned ZoneInfo
51.794 + // should have its normalized id.
51.795 + zi = ZoneInfoFile.getZoneInfo(id);
51.796 + if (zi != null) {
51.797 + return zi;
51.798 + }
51.799 +
51.800 + int index = GMT_ID_LENGTH;
51.801 + boolean negative = false;
51.802 + char c = id.charAt(index++);
51.803 + if (c == '-') {
51.804 + negative = true;
51.805 + } else if (c != '+') {
51.806 + return null;
51.807 + }
51.808 +
51.809 + int hours = 0;
51.810 + int num = 0;
51.811 + int countDelim = 0;
51.812 + int len = 0;
51.813 + while (index < length) {
51.814 + c = id.charAt(index++);
51.815 + if (c == ':') {
51.816 + if (countDelim > 0) {
51.817 + return null;
51.818 + }
51.819 + if (len > 2) {
51.820 + return null;
51.821 + }
51.822 + hours = num;
51.823 + countDelim++;
51.824 + num = 0;
51.825 + len = 0;
51.826 + continue;
51.827 + }
51.828 + if (c < '0' || c > '9') {
51.829 + return null;
51.830 + }
51.831 + num = num * 10 + (c - '0');
51.832 + len++;
51.833 + }
51.834 + if (index != length) {
51.835 + return null;
51.836 + }
51.837 + if (countDelim == 0) {
51.838 + if (len <= 2) {
51.839 + hours = num;
51.840 + num = 0;
51.841 + } else {
51.842 + hours = num / 100;
51.843 + num %= 100;
51.844 + }
51.845 + } else {
51.846 + if (len != 2) {
51.847 + return null;
51.848 + }
51.849 + }
51.850 + if (hours > 23 || num > 59) {
51.851 + return null;
51.852 + }
51.853 + int gmtOffset = (hours * 60 + num) * 60 * 1000;
51.854 +
51.855 + if (gmtOffset == 0) {
51.856 + zi = ZoneInfoFile.getZoneInfo(GMT_ID);
51.857 + if (negative) {
51.858 + zi.setID("GMT-00:00");
51.859 + } else {
51.860 + zi.setID("GMT+00:00");
51.861 + }
51.862 + } else {
51.863 + zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);
51.864 + }
51.865 + return zi;
51.866 + }
51.867 +}
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
52.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java Thu Oct 03 15:43:10 2013 +0200
52.3 @@ -0,0 +1,1522 @@
52.4 +/*
52.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
52.6 + *
52.7 + * This code is free software; you can redistribute it and/or modify it
52.8 + * under the terms of the GNU General Public License version 2 only, as
52.9 + * published by the Free Software Foundation. Oracle designates this
52.10 + * particular file as subject to the "Classpath" exception as provided
52.11 + * by Oracle in the LICENSE file that accompanied this code.
52.12 + *
52.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
52.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
52.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
52.16 + * version 2 for more details (a copy is included in the LICENSE file that
52.17 + * accompanied this code).
52.18 + *
52.19 + * You should have received a copy of the GNU General Public License version
52.20 + * 2 along with this work; if not, write to the Free Software Foundation,
52.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
52.22 + *
52.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
52.24 + * or visit www.oracle.com if you need additional information or have any
52.25 + * questions.
52.26 + */
52.27 +
52.28 +/*
52.29 + * This file is available under and governed by the GNU General Public
52.30 + * License version 2 only, as published by the Free Software Foundation.
52.31 + * However, the following notice accompanied the original version of this
52.32 + * file:
52.33 + *
52.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
52.35 + * Expert Group and released to the public domain, as explained at
52.36 + * http://creativecommons.org/publicdomain/zero/1.0/
52.37 + */
52.38 +
52.39 +package java.util.concurrent;
52.40 +import java.util.concurrent.locks.*;
52.41 +import java.util.*;
52.42 +import java.io.Serializable;
52.43 +import java.io.IOException;
52.44 +import java.io.ObjectInputStream;
52.45 +import java.io.ObjectOutputStream;
52.46 +
52.47 +/**
52.48 + * A hash table supporting full concurrency of retrievals and
52.49 + * adjustable expected concurrency for updates. This class obeys the
52.50 + * same functional specification as {@link java.util.Hashtable}, and
52.51 + * includes versions of methods corresponding to each method of
52.52 + * <tt>Hashtable</tt>. However, even though all operations are
52.53 + * thread-safe, retrieval operations do <em>not</em> entail locking,
52.54 + * and there is <em>not</em> any support for locking the entire table
52.55 + * in a way that prevents all access. This class is fully
52.56 + * interoperable with <tt>Hashtable</tt> in programs that rely on its
52.57 + * thread safety but not on its synchronization details.
52.58 + *
52.59 + * <p> Retrieval operations (including <tt>get</tt>) generally do not
52.60 + * block, so may overlap with update operations (including
52.61 + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results
52.62 + * of the most recently <em>completed</em> update operations holding
52.63 + * upon their onset. For aggregate operations such as <tt>putAll</tt>
52.64 + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or
52.65 + * removal of only some entries. Similarly, Iterators and
52.66 + * Enumerations return elements reflecting the state of the hash table
52.67 + * at some point at or since the creation of the iterator/enumeration.
52.68 + * They do <em>not</em> throw {@link ConcurrentModificationException}.
52.69 + * However, iterators are designed to be used by only one thread at a time.
52.70 + *
52.71 + * <p> The allowed concurrency among update operations is guided by
52.72 + * the optional <tt>concurrencyLevel</tt> constructor argument
52.73 + * (default <tt>16</tt>), which is used as a hint for internal sizing. The
52.74 + * table is internally partitioned to try to permit the indicated
52.75 + * number of concurrent updates without contention. Because placement
52.76 + * in hash tables is essentially random, the actual concurrency will
52.77 + * vary. Ideally, you should choose a value to accommodate as many
52.78 + * threads as will ever concurrently modify the table. Using a
52.79 + * significantly higher value than you need can waste space and time,
52.80 + * and a significantly lower value can lead to thread contention. But
52.81 + * overestimates and underestimates within an order of magnitude do
52.82 + * not usually have much noticeable impact. A value of one is
52.83 + * appropriate when it is known that only one thread will modify and
52.84 + * all others will only read. Also, resizing this or any other kind of
52.85 + * hash table is a relatively slow operation, so, when possible, it is
52.86 + * a good idea to provide estimates of expected table sizes in
52.87 + * constructors.
52.88 + *
52.89 + * <p>This class and its views and iterators implement all of the
52.90 + * <em>optional</em> methods of the {@link Map} and {@link Iterator}
52.91 + * interfaces.
52.92 + *
52.93 + * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
52.94 + * does <em>not</em> allow <tt>null</tt> to be used as a key or value.
52.95 + *
52.96 + * <p>This class is a member of the
52.97 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
52.98 + * Java Collections Framework</a>.
52.99 + *
52.100 + * @since 1.5
52.101 + * @author Doug Lea
52.102 + * @param <K> the type of keys maintained by this map
52.103 + * @param <V> the type of mapped values
52.104 + */
52.105 +public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
52.106 + implements ConcurrentMap<K, V>, Serializable {
52.107 + private static final long serialVersionUID = 7249069246763182397L;
52.108 +
52.109 + /*
52.110 + * The basic strategy is to subdivide the table among Segments,
52.111 + * each of which itself is a concurrently readable hash table. To
52.112 + * reduce footprint, all but one segments are constructed only
52.113 + * when first needed (see ensureSegment). To maintain visibility
52.114 + * in the presence of lazy construction, accesses to segments as
52.115 + * well as elements of segment's table must use volatile access,
52.116 + * which is done via Unsafe within methods segmentAt etc
52.117 + * below. These provide the functionality of AtomicReferenceArrays
52.118 + * but reduce the levels of indirection. Additionally,
52.119 + * volatile-writes of table elements and entry "next" fields
52.120 + * within locked operations use the cheaper "lazySet" forms of
52.121 + * writes (via putOrderedObject) because these writes are always
52.122 + * followed by lock releases that maintain sequential consistency
52.123 + * of table updates.
52.124 + *
52.125 + * Historical note: The previous version of this class relied
52.126 + * heavily on "final" fields, which avoided some volatile reads at
52.127 + * the expense of a large initial footprint. Some remnants of
52.128 + * that design (including forced construction of segment 0) exist
52.129 + * to ensure serialization compatibility.
52.130 + */
52.131 +
52.132 + /* ---------------- Constants -------------- */
52.133 +
52.134 + /**
52.135 + * The default initial capacity for this table,
52.136 + * used when not otherwise specified in a constructor.
52.137 + */
52.138 + static final int DEFAULT_INITIAL_CAPACITY = 16;
52.139 +
52.140 + /**
52.141 + * The default load factor for this table, used when not
52.142 + * otherwise specified in a constructor.
52.143 + */
52.144 + static final float DEFAULT_LOAD_FACTOR = 0.75f;
52.145 +
52.146 + /**
52.147 + * The default concurrency level for this table, used when not
52.148 + * otherwise specified in a constructor.
52.149 + */
52.150 + static final int DEFAULT_CONCURRENCY_LEVEL = 16;
52.151 +
52.152 + /**
52.153 + * The maximum capacity, used if a higher value is implicitly
52.154 + * specified by either of the constructors with arguments. MUST
52.155 + * be a power of two <= 1<<30 to ensure that entries are indexable
52.156 + * using ints.
52.157 + */
52.158 + static final int MAXIMUM_CAPACITY = 1 << 30;
52.159 +
52.160 + /**
52.161 + * The minimum capacity for per-segment tables. Must be a power
52.162 + * of two, at least two to avoid immediate resizing on next use
52.163 + * after lazy construction.
52.164 + */
52.165 + static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
52.166 +
52.167 + /**
52.168 + * The maximum number of segments to allow; used to bound
52.169 + * constructor arguments. Must be power of two less than 1 << 24.
52.170 + */
52.171 + static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
52.172 +
52.173 + /**
52.174 + * Number of unsynchronized retries in size and containsValue
52.175 + * methods before resorting to locking. This is used to avoid
52.176 + * unbounded retries if tables undergo continuous modification
52.177 + * which would make it impossible to obtain an accurate result.
52.178 + */
52.179 + static final int RETRIES_BEFORE_LOCK = 2;
52.180 +
52.181 + /* ---------------- Fields -------------- */
52.182 +
52.183 + /**
52.184 + * Mask value for indexing into segments. The upper bits of a
52.185 + * key's hash code are used to choose the segment.
52.186 + */
52.187 + final int segmentMask;
52.188 +
52.189 + /**
52.190 + * Shift value for indexing within segments.
52.191 + */
52.192 + final int segmentShift;
52.193 +
52.194 + /**
52.195 + * The segments, each of which is a specialized hash table.
52.196 + */
52.197 + final Segment<K,V>[] segments;
52.198 +
52.199 + transient Set<K> keySet;
52.200 + transient Set<Map.Entry<K,V>> entrySet;
52.201 + transient Collection<V> values;
52.202 +
52.203 + /**
52.204 + * ConcurrentHashMap list entry. Note that this is never exported
52.205 + * out as a user-visible Map.Entry.
52.206 + */
52.207 + static final class HashEntry<K,V> {
52.208 + final int hash;
52.209 + final K key;
52.210 + volatile V value;
52.211 + volatile HashEntry<K,V> next;
52.212 +
52.213 + HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
52.214 + this.hash = hash;
52.215 + this.key = key;
52.216 + this.value = value;
52.217 + this.next = next;
52.218 + }
52.219 +
52.220 + /**
52.221 + * Sets next field with volatile write semantics. (See above
52.222 + * about use of putOrderedObject.)
52.223 + */
52.224 + final void setNext(HashEntry<K,V> n) {
52.225 + UNSAFE.putOrderedObject(this, nextOffset, n);
52.226 + }
52.227 +
52.228 + // Unsafe mechanics
52.229 + static final sun.misc.Unsafe UNSAFE;
52.230 + static final long nextOffset;
52.231 + static {
52.232 + try {
52.233 + UNSAFE = sun.misc.Unsafe.getUnsafe();
52.234 + Class k = HashEntry.class;
52.235 + nextOffset = UNSAFE.objectFieldOffset
52.236 + (k.getDeclaredField("next"));
52.237 + } catch (Exception e) {
52.238 + throw new Error(e);
52.239 + }
52.240 + }
52.241 + }
52.242 +
52.243 + /**
52.244 + * Gets the ith element of given table (if nonnull) with volatile
52.245 + * read semantics. Note: This is manually integrated into a few
52.246 + * performance-sensitive methods to reduce call overhead.
52.247 + */
52.248 + @SuppressWarnings("unchecked")
52.249 + static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {
52.250 + return (tab == null) ? null :
52.251 + (HashEntry<K,V>) UNSAFE.getObjectVolatile
52.252 + (tab, ((long)i << TSHIFT) + TBASE);
52.253 + }
52.254 +
52.255 + /**
52.256 + * Sets the ith element of given table, with volatile write
52.257 + * semantics. (See above about use of putOrderedObject.)
52.258 + */
52.259 + static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
52.260 + HashEntry<K,V> e) {
52.261 + UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
52.262 + }
52.263 +
52.264 + /**
52.265 + * Applies a supplemental hash function to a given hashCode, which
52.266 + * defends against poor quality hash functions. This is critical
52.267 + * because ConcurrentHashMap uses power-of-two length hash tables,
52.268 + * that otherwise encounter collisions for hashCodes that do not
52.269 + * differ in lower or upper bits.
52.270 + */
52.271 + private static int hash(int h) {
52.272 + // Spread bits to regularize both segment and index locations,
52.273 + // using variant of single-word Wang/Jenkins hash.
52.274 + h += (h << 15) ^ 0xffffcd7d;
52.275 + h ^= (h >>> 10);
52.276 + h += (h << 3);
52.277 + h ^= (h >>> 6);
52.278 + h += (h << 2) + (h << 14);
52.279 + return h ^ (h >>> 16);
52.280 + }
52.281 +
52.282 + /**
52.283 + * Segments are specialized versions of hash tables. This
52.284 + * subclasses from ReentrantLock opportunistically, just to
52.285 + * simplify some locking and avoid separate construction.
52.286 + */
52.287 + static final class Segment<K,V> extends ReentrantLock implements Serializable {
52.288 + /*
52.289 + * Segments maintain a table of entry lists that are always
52.290 + * kept in a consistent state, so can be read (via volatile
52.291 + * reads of segments and tables) without locking. This
52.292 + * requires replicating nodes when necessary during table
52.293 + * resizing, so the old lists can be traversed by readers
52.294 + * still using old version of table.
52.295 + *
52.296 + * This class defines only mutative methods requiring locking.
52.297 + * Except as noted, the methods of this class perform the
52.298 + * per-segment versions of ConcurrentHashMap methods. (Other
52.299 + * methods are integrated directly into ConcurrentHashMap
52.300 + * methods.) These mutative methods use a form of controlled
52.301 + * spinning on contention via methods scanAndLock and
52.302 + * scanAndLockForPut. These intersperse tryLocks with
52.303 + * traversals to locate nodes. The main benefit is to absorb
52.304 + * cache misses (which are very common for hash tables) while
52.305 + * obtaining locks so that traversal is faster once
52.306 + * acquired. We do not actually use the found nodes since they
52.307 + * must be re-acquired under lock anyway to ensure sequential
52.308 + * consistency of updates (and in any case may be undetectably
52.309 + * stale), but they will normally be much faster to re-locate.
52.310 + * Also, scanAndLockForPut speculatively creates a fresh node
52.311 + * to use in put if no node is found.
52.312 + */
52.313 +
52.314 + private static final long serialVersionUID = 2249069246763182397L;
52.315 +
52.316 + /**
52.317 + * The maximum number of times to tryLock in a prescan before
52.318 + * possibly blocking on acquire in preparation for a locked
52.319 + * segment operation. On multiprocessors, using a bounded
52.320 + * number of retries maintains cache acquired while locating
52.321 + * nodes.
52.322 + */
52.323 + static final int MAX_SCAN_RETRIES =
52.324 + Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
52.325 +
52.326 + /**
52.327 + * The per-segment table. Elements are accessed via
52.328 + * entryAt/setEntryAt providing volatile semantics.
52.329 + */
52.330 + transient volatile HashEntry<K,V>[] table;
52.331 +
52.332 + /**
52.333 + * The number of elements. Accessed only either within locks
52.334 + * or among other volatile reads that maintain visibility.
52.335 + */
52.336 + transient int count;
52.337 +
52.338 + /**
52.339 + * The total number of mutative operations in this segment.
52.340 + * Even though this may overflows 32 bits, it provides
52.341 + * sufficient accuracy for stability checks in CHM isEmpty()
52.342 + * and size() methods. Accessed only either within locks or
52.343 + * among other volatile reads that maintain visibility.
52.344 + */
52.345 + transient int modCount;
52.346 +
52.347 + /**
52.348 + * The table is rehashed when its size exceeds this threshold.
52.349 + * (The value of this field is always <tt>(int)(capacity *
52.350 + * loadFactor)</tt>.)
52.351 + */
52.352 + transient int threshold;
52.353 +
52.354 + /**
52.355 + * The load factor for the hash table. Even though this value
52.356 + * is same for all segments, it is replicated to avoid needing
52.357 + * links to outer object.
52.358 + * @serial
52.359 + */
52.360 + final float loadFactor;
52.361 +
52.362 + Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
52.363 + this.loadFactor = lf;
52.364 + this.threshold = threshold;
52.365 + this.table = tab;
52.366 + }
52.367 +
52.368 + final V put(K key, int hash, V value, boolean onlyIfAbsent) {
52.369 + HashEntry<K,V> node = tryLock() ? null :
52.370 + scanAndLockForPut(key, hash, value);
52.371 + V oldValue;
52.372 + try {
52.373 + HashEntry<K,V>[] tab = table;
52.374 + int index = (tab.length - 1) & hash;
52.375 + HashEntry<K,V> first = entryAt(tab, index);
52.376 + for (HashEntry<K,V> e = first;;) {
52.377 + if (e != null) {
52.378 + K k;
52.379 + if ((k = e.key) == key ||
52.380 + (e.hash == hash && key.equals(k))) {
52.381 + oldValue = e.value;
52.382 + if (!onlyIfAbsent) {
52.383 + e.value = value;
52.384 + ++modCount;
52.385 + }
52.386 + break;
52.387 + }
52.388 + e = e.next;
52.389 + }
52.390 + else {
52.391 + if (node != null)
52.392 + node.setNext(first);
52.393 + else
52.394 + node = new HashEntry<K,V>(hash, key, value, first);
52.395 + int c = count + 1;
52.396 + if (c > threshold && tab.length < MAXIMUM_CAPACITY)
52.397 + rehash(node);
52.398 + else
52.399 + setEntryAt(tab, index, node);
52.400 + ++modCount;
52.401 + count = c;
52.402 + oldValue = null;
52.403 + break;
52.404 + }
52.405 + }
52.406 + } finally {
52.407 + unlock();
52.408 + }
52.409 + return oldValue;
52.410 + }
52.411 +
52.412 + /**
52.413 + * Doubles size of table and repacks entries, also adding the
52.414 + * given node to new table
52.415 + */
52.416 + @SuppressWarnings("unchecked")
52.417 + private void rehash(HashEntry<K,V> node) {
52.418 + /*
52.419 + * Reclassify nodes in each list to new table. Because we
52.420 + * are using power-of-two expansion, the elements from
52.421 + * each bin must either stay at same index, or move with a
52.422 + * power of two offset. We eliminate unnecessary node
52.423 + * creation by catching cases where old nodes can be
52.424 + * reused because their next fields won't change.
52.425 + * Statistically, at the default threshold, only about
52.426 + * one-sixth of them need cloning when a table
52.427 + * doubles. The nodes they replace will be garbage
52.428 + * collectable as soon as they are no longer referenced by
52.429 + * any reader thread that may be in the midst of
52.430 + * concurrently traversing table. Entry accesses use plain
52.431 + * array indexing because they are followed by volatile
52.432 + * table write.
52.433 + */
52.434 + HashEntry<K,V>[] oldTable = table;
52.435 + int oldCapacity = oldTable.length;
52.436 + int newCapacity = oldCapacity << 1;
52.437 + threshold = (int)(newCapacity * loadFactor);
52.438 + HashEntry<K,V>[] newTable =
52.439 + (HashEntry<K,V>[]) new HashEntry[newCapacity];
52.440 + int sizeMask = newCapacity - 1;
52.441 + for (int i = 0; i < oldCapacity ; i++) {
52.442 + HashEntry<K,V> e = oldTable[i];
52.443 + if (e != null) {
52.444 + HashEntry<K,V> next = e.next;
52.445 + int idx = e.hash & sizeMask;
52.446 + if (next == null) // Single node on list
52.447 + newTable[idx] = e;
52.448 + else { // Reuse consecutive sequence at same slot
52.449 + HashEntry<K,V> lastRun = e;
52.450 + int lastIdx = idx;
52.451 + for (HashEntry<K,V> last = next;
52.452 + last != null;
52.453 + last = last.next) {
52.454 + int k = last.hash & sizeMask;
52.455 + if (k != lastIdx) {
52.456 + lastIdx = k;
52.457 + lastRun = last;
52.458 + }
52.459 + }
52.460 + newTable[lastIdx] = lastRun;
52.461 + // Clone remaining nodes
52.462 + for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
52.463 + V v = p.value;
52.464 + int h = p.hash;
52.465 + int k = h & sizeMask;
52.466 + HashEntry<K,V> n = newTable[k];
52.467 + newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
52.468 + }
52.469 + }
52.470 + }
52.471 + }
52.472 + int nodeIndex = node.hash & sizeMask; // add the new node
52.473 + node.setNext(newTable[nodeIndex]);
52.474 + newTable[nodeIndex] = node;
52.475 + table = newTable;
52.476 + }
52.477 +
52.478 + /**
52.479 + * Scans for a node containing given key while trying to
52.480 + * acquire lock, creating and returning one if not found. Upon
52.481 + * return, guarantees that lock is held. UNlike in most
52.482 + * methods, calls to method equals are not screened: Since
52.483 + * traversal speed doesn't matter, we might as well help warm
52.484 + * up the associated code and accesses as well.
52.485 + *
52.486 + * @return a new node if key not found, else null
52.487 + */
52.488 + private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
52.489 + HashEntry<K,V> first = entryForHash(this, hash);
52.490 + HashEntry<K,V> e = first;
52.491 + HashEntry<K,V> node = null;
52.492 + int retries = -1; // negative while locating node
52.493 + while (!tryLock()) {
52.494 + HashEntry<K,V> f; // to recheck first below
52.495 + if (retries < 0) {
52.496 + if (e == null) {
52.497 + if (node == null) // speculatively create node
52.498 + node = new HashEntry<K,V>(hash, key, value, null);
52.499 + retries = 0;
52.500 + }
52.501 + else if (key.equals(e.key))
52.502 + retries = 0;
52.503 + else
52.504 + e = e.next;
52.505 + }
52.506 + else if (++retries > MAX_SCAN_RETRIES) {
52.507 + lock();
52.508 + break;
52.509 + }
52.510 + else if ((retries & 1) == 0 &&
52.511 + (f = entryForHash(this, hash)) != first) {
52.512 + e = first = f; // re-traverse if entry changed
52.513 + retries = -1;
52.514 + }
52.515 + }
52.516 + return node;
52.517 + }
52.518 +
52.519 + /**
52.520 + * Scans for a node containing the given key while trying to
52.521 + * acquire lock for a remove or replace operation. Upon
52.522 + * return, guarantees that lock is held. Note that we must
52.523 + * lock even if the key is not found, to ensure sequential
52.524 + * consistency of updates.
52.525 + */
52.526 + private void scanAndLock(Object key, int hash) {
52.527 + // similar to but simpler than scanAndLockForPut
52.528 + HashEntry<K,V> first = entryForHash(this, hash);
52.529 + HashEntry<K,V> e = first;
52.530 + int retries = -1;
52.531 + while (!tryLock()) {
52.532 + HashEntry<K,V> f;
52.533 + if (retries < 0) {
52.534 + if (e == null || key.equals(e.key))
52.535 + retries = 0;
52.536 + else
52.537 + e = e.next;
52.538 + }
52.539 + else if (++retries > MAX_SCAN_RETRIES) {
52.540 + lock();
52.541 + break;
52.542 + }
52.543 + else if ((retries & 1) == 0 &&
52.544 + (f = entryForHash(this, hash)) != first) {
52.545 + e = first = f;
52.546 + retries = -1;
52.547 + }
52.548 + }
52.549 + }
52.550 +
52.551 + /**
52.552 + * Remove; match on key only if value null, else match both.
52.553 + */
52.554 + final V remove(Object key, int hash, Object value) {
52.555 + if (!tryLock())
52.556 + scanAndLock(key, hash);
52.557 + V oldValue = null;
52.558 + try {
52.559 + HashEntry<K,V>[] tab = table;
52.560 + int index = (tab.length - 1) & hash;
52.561 + HashEntry<K,V> e = entryAt(tab, index);
52.562 + HashEntry<K,V> pred = null;
52.563 + while (e != null) {
52.564 + K k;
52.565 + HashEntry<K,V> next = e.next;
52.566 + if ((k = e.key) == key ||
52.567 + (e.hash == hash && key.equals(k))) {
52.568 + V v = e.value;
52.569 + if (value == null || value == v || value.equals(v)) {
52.570 + if (pred == null)
52.571 + setEntryAt(tab, index, next);
52.572 + else
52.573 + pred.setNext(next);
52.574 + ++modCount;
52.575 + --count;
52.576 + oldValue = v;
52.577 + }
52.578 + break;
52.579 + }
52.580 + pred = e;
52.581 + e = next;
52.582 + }
52.583 + } finally {
52.584 + unlock();
52.585 + }
52.586 + return oldValue;
52.587 + }
52.588 +
52.589 + final boolean replace(K key, int hash, V oldValue, V newValue) {
52.590 + if (!tryLock())
52.591 + scanAndLock(key, hash);
52.592 + boolean replaced = false;
52.593 + try {
52.594 + HashEntry<K,V> e;
52.595 + for (e = entryForHash(this, hash); e != null; e = e.next) {
52.596 + K k;
52.597 + if ((k = e.key) == key ||
52.598 + (e.hash == hash && key.equals(k))) {
52.599 + if (oldValue.equals(e.value)) {
52.600 + e.value = newValue;
52.601 + ++modCount;
52.602 + replaced = true;
52.603 + }
52.604 + break;
52.605 + }
52.606 + }
52.607 + } finally {
52.608 + unlock();
52.609 + }
52.610 + return replaced;
52.611 + }
52.612 +
52.613 + final V replace(K key, int hash, V value) {
52.614 + if (!tryLock())
52.615 + scanAndLock(key, hash);
52.616 + V oldValue = null;
52.617 + try {
52.618 + HashEntry<K,V> e;
52.619 + for (e = entryForHash(this, hash); e != null; e = e.next) {
52.620 + K k;
52.621 + if ((k = e.key) == key ||
52.622 + (e.hash == hash && key.equals(k))) {
52.623 + oldValue = e.value;
52.624 + e.value = value;
52.625 + ++modCount;
52.626 + break;
52.627 + }
52.628 + }
52.629 + } finally {
52.630 + unlock();
52.631 + }
52.632 + return oldValue;
52.633 + }
52.634 +
52.635 + final void clear() {
52.636 + lock();
52.637 + try {
52.638 + HashEntry<K,V>[] tab = table;
52.639 + for (int i = 0; i < tab.length ; i++)
52.640 + setEntryAt(tab, i, null);
52.641 + ++modCount;
52.642 + count = 0;
52.643 + } finally {
52.644 + unlock();
52.645 + }
52.646 + }
52.647 + }
52.648 +
52.649 + // Accessing segments
52.650 +
52.651 + /**
52.652 + * Gets the jth element of given segment array (if nonnull) with
52.653 + * volatile element access semantics via Unsafe. (The null check
52.654 + * can trigger harmlessly only during deserialization.) Note:
52.655 + * because each element of segments array is set only once (using
52.656 + * fully ordered writes), some performance-sensitive methods rely
52.657 + * on this method only as a recheck upon null reads.
52.658 + */
52.659 + @SuppressWarnings("unchecked")
52.660 + static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {
52.661 + long u = (j << SSHIFT) + SBASE;
52.662 + return ss == null ? null :
52.663 + (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);
52.664 + }
52.665 +
52.666 + /**
52.667 + * Returns the segment for the given index, creating it and
52.668 + * recording in segment table (via CAS) if not already present.
52.669 + *
52.670 + * @param k the index
52.671 + * @return the segment
52.672 + */
52.673 + @SuppressWarnings("unchecked")
52.674 + private Segment<K,V> ensureSegment(int k) {
52.675 + final Segment<K,V>[] ss = this.segments;
52.676 + long u = (k << SSHIFT) + SBASE; // raw offset
52.677 + Segment<K,V> seg;
52.678 + if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
52.679 + Segment<K,V> proto = ss[0]; // use segment 0 as prototype
52.680 + int cap = proto.table.length;
52.681 + float lf = proto.loadFactor;
52.682 + int threshold = (int)(cap * lf);
52.683 + HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
52.684 + if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
52.685 + == null) { // recheck
52.686 + Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
52.687 + while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
52.688 + == null) {
52.689 + if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
52.690 + break;
52.691 + }
52.692 + }
52.693 + }
52.694 + return seg;
52.695 + }
52.696 +
52.697 + // Hash-based segment and entry accesses
52.698 +
52.699 + /**
52.700 + * Get the segment for the given hash
52.701 + */
52.702 + @SuppressWarnings("unchecked")
52.703 + private Segment<K,V> segmentForHash(int h) {
52.704 + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
52.705 + return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u);
52.706 + }
52.707 +
52.708 + /**
52.709 + * Gets the table entry for the given segment and hash
52.710 + */
52.711 + @SuppressWarnings("unchecked")
52.712 + static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {
52.713 + HashEntry<K,V>[] tab;
52.714 + return (seg == null || (tab = seg.table) == null) ? null :
52.715 + (HashEntry<K,V>) UNSAFE.getObjectVolatile
52.716 + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
52.717 + }
52.718 +
52.719 + /* ---------------- Public operations -------------- */
52.720 +
52.721 + /**
52.722 + * Creates a new, empty map with the specified initial
52.723 + * capacity, load factor and concurrency level.
52.724 + *
52.725 + * @param initialCapacity the initial capacity. The implementation
52.726 + * performs internal sizing to accommodate this many elements.
52.727 + * @param loadFactor the load factor threshold, used to control resizing.
52.728 + * Resizing may be performed when the average number of elements per
52.729 + * bin exceeds this threshold.
52.730 + * @param concurrencyLevel the estimated number of concurrently
52.731 + * updating threads. The implementation performs internal sizing
52.732 + * to try to accommodate this many threads.
52.733 + * @throws IllegalArgumentException if the initial capacity is
52.734 + * negative or the load factor or concurrencyLevel are
52.735 + * nonpositive.
52.736 + */
52.737 + @SuppressWarnings("unchecked")
52.738 + public ConcurrentHashMap(int initialCapacity,
52.739 + float loadFactor, int concurrencyLevel) {
52.740 + if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
52.741 + throw new IllegalArgumentException();
52.742 + if (concurrencyLevel > MAX_SEGMENTS)
52.743 + concurrencyLevel = MAX_SEGMENTS;
52.744 + // Find power-of-two sizes best matching arguments
52.745 + int sshift = 0;
52.746 + int ssize = 1;
52.747 + while (ssize < concurrencyLevel) {
52.748 + ++sshift;
52.749 + ssize <<= 1;
52.750 + }
52.751 + this.segmentShift = 32 - sshift;
52.752 + this.segmentMask = ssize - 1;
52.753 + if (initialCapacity > MAXIMUM_CAPACITY)
52.754 + initialCapacity = MAXIMUM_CAPACITY;
52.755 + int c = initialCapacity / ssize;
52.756 + if (c * ssize < initialCapacity)
52.757 + ++c;
52.758 + int cap = MIN_SEGMENT_TABLE_CAPACITY;
52.759 + while (cap < c)
52.760 + cap <<= 1;
52.761 + // create segments and segments[0]
52.762 + Segment<K,V> s0 =
52.763 + new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
52.764 + (HashEntry<K,V>[])new HashEntry[cap]);
52.765 + Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
52.766 + UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
52.767 + this.segments = ss;
52.768 + }
52.769 +
52.770 + /**
52.771 + * Creates a new, empty map with the specified initial capacity
52.772 + * and load factor and with the default concurrencyLevel (16).
52.773 + *
52.774 + * @param initialCapacity The implementation performs internal
52.775 + * sizing to accommodate this many elements.
52.776 + * @param loadFactor the load factor threshold, used to control resizing.
52.777 + * Resizing may be performed when the average number of elements per
52.778 + * bin exceeds this threshold.
52.779 + * @throws IllegalArgumentException if the initial capacity of
52.780 + * elements is negative or the load factor is nonpositive
52.781 + *
52.782 + * @since 1.6
52.783 + */
52.784 + public ConcurrentHashMap(int initialCapacity, float loadFactor) {
52.785 + this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
52.786 + }
52.787 +
52.788 + /**
52.789 + * Creates a new, empty map with the specified initial capacity,
52.790 + * and with default load factor (0.75) and concurrencyLevel (16).
52.791 + *
52.792 + * @param initialCapacity the initial capacity. The implementation
52.793 + * performs internal sizing to accommodate this many elements.
52.794 + * @throws IllegalArgumentException if the initial capacity of
52.795 + * elements is negative.
52.796 + */
52.797 + public ConcurrentHashMap(int initialCapacity) {
52.798 + this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
52.799 + }
52.800 +
52.801 + /**
52.802 + * Creates a new, empty map with a default initial capacity (16),
52.803 + * load factor (0.75) and concurrencyLevel (16).
52.804 + */
52.805 + public ConcurrentHashMap() {
52.806 + this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
52.807 + }
52.808 +
52.809 + /**
52.810 + * Creates a new map with the same mappings as the given map.
52.811 + * The map is created with a capacity of 1.5 times the number
52.812 + * of mappings in the given map or 16 (whichever is greater),
52.813 + * and a default load factor (0.75) and concurrencyLevel (16).
52.814 + *
52.815 + * @param m the map
52.816 + */
52.817 + public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
52.818 + this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
52.819 + DEFAULT_INITIAL_CAPACITY),
52.820 + DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
52.821 + putAll(m);
52.822 + }
52.823 +
52.824 + /**
52.825 + * Returns <tt>true</tt> if this map contains no key-value mappings.
52.826 + *
52.827 + * @return <tt>true</tt> if this map contains no key-value mappings
52.828 + */
52.829 + public boolean isEmpty() {
52.830 + /*
52.831 + * Sum per-segment modCounts to avoid mis-reporting when
52.832 + * elements are concurrently added and removed in one segment
52.833 + * while checking another, in which case the table was never
52.834 + * actually empty at any point. (The sum ensures accuracy up
52.835 + * through at least 1<<31 per-segment modifications before
52.836 + * recheck.) Methods size() and containsValue() use similar
52.837 + * constructions for stability checks.
52.838 + */
52.839 + long sum = 0L;
52.840 + final Segment<K,V>[] segments = this.segments;
52.841 + for (int j = 0; j < segments.length; ++j) {
52.842 + Segment<K,V> seg = segmentAt(segments, j);
52.843 + if (seg != null) {
52.844 + if (seg.count != 0)
52.845 + return false;
52.846 + sum += seg.modCount;
52.847 + }
52.848 + }
52.849 + if (sum != 0L) { // recheck unless no modifications
52.850 + for (int j = 0; j < segments.length; ++j) {
52.851 + Segment<K,V> seg = segmentAt(segments, j);
52.852 + if (seg != null) {
52.853 + if (seg.count != 0)
52.854 + return false;
52.855 + sum -= seg.modCount;
52.856 + }
52.857 + }
52.858 + if (sum != 0L)
52.859 + return false;
52.860 + }
52.861 + return true;
52.862 + }
52.863 +
52.864 + /**
52.865 + * Returns the number of key-value mappings in this map. If the
52.866 + * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
52.867 + * <tt>Integer.MAX_VALUE</tt>.
52.868 + *
52.869 + * @return the number of key-value mappings in this map
52.870 + */
52.871 + public int size() {
52.872 + // Try a few times to get accurate count. On failure due to
52.873 + // continuous async changes in table, resort to locking.
52.874 + final Segment<K,V>[] segments = this.segments;
52.875 + int size;
52.876 + boolean overflow; // true if size overflows 32 bits
52.877 + long sum; // sum of modCounts
52.878 + long last = 0L; // previous sum
52.879 + int retries = -1; // first iteration isn't retry
52.880 + try {
52.881 + for (;;) {
52.882 + if (retries++ == RETRIES_BEFORE_LOCK) {
52.883 + for (int j = 0; j < segments.length; ++j)
52.884 + ensureSegment(j).lock(); // force creation
52.885 + }
52.886 + sum = 0L;
52.887 + size = 0;
52.888 + overflow = false;
52.889 + for (int j = 0; j < segments.length; ++j) {
52.890 + Segment<K,V> seg = segmentAt(segments, j);
52.891 + if (seg != null) {
52.892 + sum += seg.modCount;
52.893 + int c = seg.count;
52.894 + if (c < 0 || (size += c) < 0)
52.895 + overflow = true;
52.896 + }
52.897 + }
52.898 + if (sum == last)
52.899 + break;
52.900 + last = sum;
52.901 + }
52.902 + } finally {
52.903 + if (retries > RETRIES_BEFORE_LOCK) {
52.904 + for (int j = 0; j < segments.length; ++j)
52.905 + segmentAt(segments, j).unlock();
52.906 + }
52.907 + }
52.908 + return overflow ? Integer.MAX_VALUE : size;
52.909 + }
52.910 +
52.911 + /**
52.912 + * Returns the value to which the specified key is mapped,
52.913 + * or {@code null} if this map contains no mapping for the key.
52.914 + *
52.915 + * <p>More formally, if this map contains a mapping from a key
52.916 + * {@code k} to a value {@code v} such that {@code key.equals(k)},
52.917 + * then this method returns {@code v}; otherwise it returns
52.918 + * {@code null}. (There can be at most one such mapping.)
52.919 + *
52.920 + * @throws NullPointerException if the specified key is null
52.921 + */
52.922 + public V get(Object key) {
52.923 + Segment<K,V> s; // manually integrate access methods to reduce overhead
52.924 + HashEntry<K,V>[] tab;
52.925 + int h = hash(key.hashCode());
52.926 + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
52.927 + if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
52.928 + (tab = s.table) != null) {
52.929 + for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
52.930 + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
52.931 + e != null; e = e.next) {
52.932 + K k;
52.933 + if ((k = e.key) == key || (e.hash == h && key.equals(k)))
52.934 + return e.value;
52.935 + }
52.936 + }
52.937 + return null;
52.938 + }
52.939 +
52.940 + /**
52.941 + * Tests if the specified object is a key in this table.
52.942 + *
52.943 + * @param key possible key
52.944 + * @return <tt>true</tt> if and only if the specified object
52.945 + * is a key in this table, as determined by the
52.946 + * <tt>equals</tt> method; <tt>false</tt> otherwise.
52.947 + * @throws NullPointerException if the specified key is null
52.948 + */
52.949 + @SuppressWarnings("unchecked")
52.950 + public boolean containsKey(Object key) {
52.951 + Segment<K,V> s; // same as get() except no need for volatile value read
52.952 + HashEntry<K,V>[] tab;
52.953 + int h = hash(key.hashCode());
52.954 + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
52.955 + if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
52.956 + (tab = s.table) != null) {
52.957 + for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
52.958 + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
52.959 + e != null; e = e.next) {
52.960 + K k;
52.961 + if ((k = e.key) == key || (e.hash == h && key.equals(k)))
52.962 + return true;
52.963 + }
52.964 + }
52.965 + return false;
52.966 + }
52.967 +
52.968 + /**
52.969 + * Returns <tt>true</tt> if this map maps one or more keys to the
52.970 + * specified value. Note: This method requires a full internal
52.971 + * traversal of the hash table, and so is much slower than
52.972 + * method <tt>containsKey</tt>.
52.973 + *
52.974 + * @param value value whose presence in this map is to be tested
52.975 + * @return <tt>true</tt> if this map maps one or more keys to the
52.976 + * specified value
52.977 + * @throws NullPointerException if the specified value is null
52.978 + */
52.979 + public boolean containsValue(Object value) {
52.980 + // Same idea as size()
52.981 + if (value == null)
52.982 + throw new NullPointerException();
52.983 + final Segment<K,V>[] segments = this.segments;
52.984 + boolean found = false;
52.985 + long last = 0;
52.986 + int retries = -1;
52.987 + try {
52.988 + outer: for (;;) {
52.989 + if (retries++ == RETRIES_BEFORE_LOCK) {
52.990 + for (int j = 0; j < segments.length; ++j)
52.991 + ensureSegment(j).lock(); // force creation
52.992 + }
52.993 + long hashSum = 0L;
52.994 + int sum = 0;
52.995 + for (int j = 0; j < segments.length; ++j) {
52.996 + HashEntry<K,V>[] tab;
52.997 + Segment<K,V> seg = segmentAt(segments, j);
52.998 + if (seg != null && (tab = seg.table) != null) {
52.999 + for (int i = 0 ; i < tab.length; i++) {
52.1000 + HashEntry<K,V> e;
52.1001 + for (e = entryAt(tab, i); e != null; e = e.next) {
52.1002 + V v = e.value;
52.1003 + if (v != null && value.equals(v)) {
52.1004 + found = true;
52.1005 + break outer;
52.1006 + }
52.1007 + }
52.1008 + }
52.1009 + sum += seg.modCount;
52.1010 + }
52.1011 + }
52.1012 + if (retries > 0 && sum == last)
52.1013 + break;
52.1014 + last = sum;
52.1015 + }
52.1016 + } finally {
52.1017 + if (retries > RETRIES_BEFORE_LOCK) {
52.1018 + for (int j = 0; j < segments.length; ++j)
52.1019 + segmentAt(segments, j).unlock();
52.1020 + }
52.1021 + }
52.1022 + return found;
52.1023 + }
52.1024 +
52.1025 + /**
52.1026 + * Legacy method testing if some key maps into the specified value
52.1027 + * in this table. This method is identical in functionality to
52.1028 + * {@link #containsValue}, and exists solely to ensure
52.1029 + * full compatibility with class {@link java.util.Hashtable},
52.1030 + * which supported this method prior to introduction of the
52.1031 + * Java Collections framework.
52.1032 +
52.1033 + * @param value a value to search for
52.1034 + * @return <tt>true</tt> if and only if some key maps to the
52.1035 + * <tt>value</tt> argument in this table as
52.1036 + * determined by the <tt>equals</tt> method;
52.1037 + * <tt>false</tt> otherwise
52.1038 + * @throws NullPointerException if the specified value is null
52.1039 + */
52.1040 + public boolean contains(Object value) {
52.1041 + return containsValue(value);
52.1042 + }
52.1043 +
52.1044 + /**
52.1045 + * Maps the specified key to the specified value in this table.
52.1046 + * Neither the key nor the value can be null.
52.1047 + *
52.1048 + * <p> The value can be retrieved by calling the <tt>get</tt> method
52.1049 + * with a key that is equal to the original key.
52.1050 + *
52.1051 + * @param key key with which the specified value is to be associated
52.1052 + * @param value value to be associated with the specified key
52.1053 + * @return the previous value associated with <tt>key</tt>, or
52.1054 + * <tt>null</tt> if there was no mapping for <tt>key</tt>
52.1055 + * @throws NullPointerException if the specified key or value is null
52.1056 + */
52.1057 + @SuppressWarnings("unchecked")
52.1058 + public V put(K key, V value) {
52.1059 + Segment<K,V> s;
52.1060 + if (value == null)
52.1061 + throw new NullPointerException();
52.1062 + int hash = hash(key.hashCode());
52.1063 + int j = (hash >>> segmentShift) & segmentMask;
52.1064 + if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
52.1065 + (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
52.1066 + s = ensureSegment(j);
52.1067 + return s.put(key, hash, value, false);
52.1068 + }
52.1069 +
52.1070 + /**
52.1071 + * {@inheritDoc}
52.1072 + *
52.1073 + * @return the previous value associated with the specified key,
52.1074 + * or <tt>null</tt> if there was no mapping for the key
52.1075 + * @throws NullPointerException if the specified key or value is null
52.1076 + */
52.1077 + @SuppressWarnings("unchecked")
52.1078 + public V putIfAbsent(K key, V value) {
52.1079 + Segment<K,V> s;
52.1080 + if (value == null)
52.1081 + throw new NullPointerException();
52.1082 + int hash = hash(key.hashCode());
52.1083 + int j = (hash >>> segmentShift) & segmentMask;
52.1084 + if ((s = (Segment<K,V>)UNSAFE.getObject
52.1085 + (segments, (j << SSHIFT) + SBASE)) == null)
52.1086 + s = ensureSegment(j);
52.1087 + return s.put(key, hash, value, true);
52.1088 + }
52.1089 +
52.1090 + /**
52.1091 + * Copies all of the mappings from the specified map to this one.
52.1092 + * These mappings replace any mappings that this map had for any of the
52.1093 + * keys currently in the specified map.
52.1094 + *
52.1095 + * @param m mappings to be stored in this map
52.1096 + */
52.1097 + public void putAll(Map<? extends K, ? extends V> m) {
52.1098 + for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
52.1099 + put(e.getKey(), e.getValue());
52.1100 + }
52.1101 +
52.1102 + /**
52.1103 + * Removes the key (and its corresponding value) from this map.
52.1104 + * This method does nothing if the key is not in the map.
52.1105 + *
52.1106 + * @param key the key that needs to be removed
52.1107 + * @return the previous value associated with <tt>key</tt>, or
52.1108 + * <tt>null</tt> if there was no mapping for <tt>key</tt>
52.1109 + * @throws NullPointerException if the specified key is null
52.1110 + */
52.1111 + public V remove(Object key) {
52.1112 + int hash = hash(key.hashCode());
52.1113 + Segment<K,V> s = segmentForHash(hash);
52.1114 + return s == null ? null : s.remove(key, hash, null);
52.1115 + }
52.1116 +
52.1117 + /**
52.1118 + * {@inheritDoc}
52.1119 + *
52.1120 + * @throws NullPointerException if the specified key is null
52.1121 + */
52.1122 + public boolean remove(Object key, Object value) {
52.1123 + int hash = hash(key.hashCode());
52.1124 + Segment<K,V> s;
52.1125 + return value != null && (s = segmentForHash(hash)) != null &&
52.1126 + s.remove(key, hash, value) != null;
52.1127 + }
52.1128 +
52.1129 + /**
52.1130 + * {@inheritDoc}
52.1131 + *
52.1132 + * @throws NullPointerException if any of the arguments are null
52.1133 + */
52.1134 + public boolean replace(K key, V oldValue, V newValue) {
52.1135 + int hash = hash(key.hashCode());
52.1136 + if (oldValue == null || newValue == null)
52.1137 + throw new NullPointerException();
52.1138 + Segment<K,V> s = segmentForHash(hash);
52.1139 + return s != null && s.replace(key, hash, oldValue, newValue);
52.1140 + }
52.1141 +
52.1142 + /**
52.1143 + * {@inheritDoc}
52.1144 + *
52.1145 + * @return the previous value associated with the specified key,
52.1146 + * or <tt>null</tt> if there was no mapping for the key
52.1147 + * @throws NullPointerException if the specified key or value is null
52.1148 + */
52.1149 + public V replace(K key, V value) {
52.1150 + int hash = hash(key.hashCode());
52.1151 + if (value == null)
52.1152 + throw new NullPointerException();
52.1153 + Segment<K,V> s = segmentForHash(hash);
52.1154 + return s == null ? null : s.replace(key, hash, value);
52.1155 + }
52.1156 +
52.1157 + /**
52.1158 + * Removes all of the mappings from this map.
52.1159 + */
52.1160 + public void clear() {
52.1161 + final Segment<K,V>[] segments = this.segments;
52.1162 + for (int j = 0; j < segments.length; ++j) {
52.1163 + Segment<K,V> s = segmentAt(segments, j);
52.1164 + if (s != null)
52.1165 + s.clear();
52.1166 + }
52.1167 + }
52.1168 +
52.1169 + /**
52.1170 + * Returns a {@link Set} view of the keys contained in this map.
52.1171 + * The set is backed by the map, so changes to the map are
52.1172 + * reflected in the set, and vice-versa. The set supports element
52.1173 + * removal, which removes the corresponding mapping from this map,
52.1174 + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
52.1175 + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
52.1176 + * operations. It does not support the <tt>add</tt> or
52.1177 + * <tt>addAll</tt> operations.
52.1178 + *
52.1179 + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
52.1180 + * that will never throw {@link ConcurrentModificationException},
52.1181 + * and guarantees to traverse elements as they existed upon
52.1182 + * construction of the iterator, and may (but is not guaranteed to)
52.1183 + * reflect any modifications subsequent to construction.
52.1184 + */
52.1185 + public Set<K> keySet() {
52.1186 + Set<K> ks = keySet;
52.1187 + return (ks != null) ? ks : (keySet = new KeySet());
52.1188 + }
52.1189 +
52.1190 + /**
52.1191 + * Returns a {@link Collection} view of the values contained in this map.
52.1192 + * The collection is backed by the map, so changes to the map are
52.1193 + * reflected in the collection, and vice-versa. The collection
52.1194 + * supports element removal, which removes the corresponding
52.1195 + * mapping from this map, via the <tt>Iterator.remove</tt>,
52.1196 + * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
52.1197 + * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not
52.1198 + * support the <tt>add</tt> or <tt>addAll</tt> operations.
52.1199 + *
52.1200 + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
52.1201 + * that will never throw {@link ConcurrentModificationException},
52.1202 + * and guarantees to traverse elements as they existed upon
52.1203 + * construction of the iterator, and may (but is not guaranteed to)
52.1204 + * reflect any modifications subsequent to construction.
52.1205 + */
52.1206 + public Collection<V> values() {
52.1207 + Collection<V> vs = values;
52.1208 + return (vs != null) ? vs : (values = new Values());
52.1209 + }
52.1210 +
52.1211 + /**
52.1212 + * Returns a {@link Set} view of the mappings contained in this map.
52.1213 + * The set is backed by the map, so changes to the map are
52.1214 + * reflected in the set, and vice-versa. The set supports element
52.1215 + * removal, which removes the corresponding mapping from the map,
52.1216 + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
52.1217 + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
52.1218 + * operations. It does not support the <tt>add</tt> or
52.1219 + * <tt>addAll</tt> operations.
52.1220 + *
52.1221 + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
52.1222 + * that will never throw {@link ConcurrentModificationException},
52.1223 + * and guarantees to traverse elements as they existed upon
52.1224 + * construction of the iterator, and may (but is not guaranteed to)
52.1225 + * reflect any modifications subsequent to construction.
52.1226 + */
52.1227 + public Set<Map.Entry<K,V>> entrySet() {
52.1228 + Set<Map.Entry<K,V>> es = entrySet;
52.1229 + return (es != null) ? es : (entrySet = new EntrySet());
52.1230 + }
52.1231 +
52.1232 + /**
52.1233 + * Returns an enumeration of the keys in this table.
52.1234 + *
52.1235 + * @return an enumeration of the keys in this table
52.1236 + * @see #keySet()
52.1237 + */
52.1238 + public Enumeration<K> keys() {
52.1239 + return new KeyIterator();
52.1240 + }
52.1241 +
52.1242 + /**
52.1243 + * Returns an enumeration of the values in this table.
52.1244 + *
52.1245 + * @return an enumeration of the values in this table
52.1246 + * @see #values()
52.1247 + */
52.1248 + public Enumeration<V> elements() {
52.1249 + return new ValueIterator();
52.1250 + }
52.1251 +
52.1252 + /* ---------------- Iterator Support -------------- */
52.1253 +
52.1254 + abstract class HashIterator {
52.1255 + int nextSegmentIndex;
52.1256 + int nextTableIndex;
52.1257 + HashEntry<K,V>[] currentTable;
52.1258 + HashEntry<K, V> nextEntry;
52.1259 + HashEntry<K, V> lastReturned;
52.1260 +
52.1261 + HashIterator() {
52.1262 + nextSegmentIndex = segments.length - 1;
52.1263 + nextTableIndex = -1;
52.1264 + advance();
52.1265 + }
52.1266 +
52.1267 + /**
52.1268 + * Set nextEntry to first node of next non-empty table
52.1269 + * (in backwards order, to simplify checks).
52.1270 + */
52.1271 + final void advance() {
52.1272 + for (;;) {
52.1273 + if (nextTableIndex >= 0) {
52.1274 + if ((nextEntry = entryAt(currentTable,
52.1275 + nextTableIndex--)) != null)
52.1276 + break;
52.1277 + }
52.1278 + else if (nextSegmentIndex >= 0) {
52.1279 + Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);
52.1280 + if (seg != null && (currentTable = seg.table) != null)
52.1281 + nextTableIndex = currentTable.length - 1;
52.1282 + }
52.1283 + else
52.1284 + break;
52.1285 + }
52.1286 + }
52.1287 +
52.1288 + final HashEntry<K,V> nextEntry() {
52.1289 + HashEntry<K,V> e = nextEntry;
52.1290 + if (e == null)
52.1291 + throw new NoSuchElementException();
52.1292 + lastReturned = e; // cannot assign until after null check
52.1293 + if ((nextEntry = e.next) == null)
52.1294 + advance();
52.1295 + return e;
52.1296 + }
52.1297 +
52.1298 + public final boolean hasNext() { return nextEntry != null; }
52.1299 + public final boolean hasMoreElements() { return nextEntry != null; }
52.1300 +
52.1301 + public final void remove() {
52.1302 + if (lastReturned == null)
52.1303 + throw new IllegalStateException();
52.1304 + ConcurrentHashMap.this.remove(lastReturned.key);
52.1305 + lastReturned = null;
52.1306 + }
52.1307 + }
52.1308 +
52.1309 + final class KeyIterator
52.1310 + extends HashIterator
52.1311 + implements Iterator<K>, Enumeration<K>
52.1312 + {
52.1313 + public final K next() { return super.nextEntry().key; }
52.1314 + public final K nextElement() { return super.nextEntry().key; }
52.1315 + }
52.1316 +
52.1317 + final class ValueIterator
52.1318 + extends HashIterator
52.1319 + implements Iterator<V>, Enumeration<V>
52.1320 + {
52.1321 + public final V next() { return super.nextEntry().value; }
52.1322 + public final V nextElement() { return super.nextEntry().value; }
52.1323 + }
52.1324 +
52.1325 + /**
52.1326 + * Custom Entry class used by EntryIterator.next(), that relays
52.1327 + * setValue changes to the underlying map.
52.1328 + */
52.1329 + final class WriteThroughEntry
52.1330 + extends AbstractMap.SimpleEntry<K,V>
52.1331 + {
52.1332 + WriteThroughEntry(K k, V v) {
52.1333 + super(k,v);
52.1334 + }
52.1335 +
52.1336 + /**
52.1337 + * Set our entry's value and write through to the map. The
52.1338 + * value to return is somewhat arbitrary here. Since a
52.1339 + * WriteThroughEntry does not necessarily track asynchronous
52.1340 + * changes, the most recent "previous" value could be
52.1341 + * different from what we return (or could even have been
52.1342 + * removed in which case the put will re-establish). We do not
52.1343 + * and cannot guarantee more.
52.1344 + */
52.1345 + public V setValue(V value) {
52.1346 + if (value == null) throw new NullPointerException();
52.1347 + V v = super.setValue(value);
52.1348 + ConcurrentHashMap.this.put(getKey(), value);
52.1349 + return v;
52.1350 + }
52.1351 + }
52.1352 +
52.1353 + final class EntryIterator
52.1354 + extends HashIterator
52.1355 + implements Iterator<Entry<K,V>>
52.1356 + {
52.1357 + public Map.Entry<K,V> next() {
52.1358 + HashEntry<K,V> e = super.nextEntry();
52.1359 + return new WriteThroughEntry(e.key, e.value);
52.1360 + }
52.1361 + }
52.1362 +
52.1363 + final class KeySet extends AbstractSet<K> {
52.1364 + public Iterator<K> iterator() {
52.1365 + return new KeyIterator();
52.1366 + }
52.1367 + public int size() {
52.1368 + return ConcurrentHashMap.this.size();
52.1369 + }
52.1370 + public boolean isEmpty() {
52.1371 + return ConcurrentHashMap.this.isEmpty();
52.1372 + }
52.1373 + public boolean contains(Object o) {
52.1374 + return ConcurrentHashMap.this.containsKey(o);
52.1375 + }
52.1376 + public boolean remove(Object o) {
52.1377 + return ConcurrentHashMap.this.remove(o) != null;
52.1378 + }
52.1379 + public void clear() {
52.1380 + ConcurrentHashMap.this.clear();
52.1381 + }
52.1382 + }
52.1383 +
52.1384 + final class Values extends AbstractCollection<V> {
52.1385 + public Iterator<V> iterator() {
52.1386 + return new ValueIterator();
52.1387 + }
52.1388 + public int size() {
52.1389 + return ConcurrentHashMap.this.size();
52.1390 + }
52.1391 + public boolean isEmpty() {
52.1392 + return ConcurrentHashMap.this.isEmpty();
52.1393 + }
52.1394 + public boolean contains(Object o) {
52.1395 + return ConcurrentHashMap.this.containsValue(o);
52.1396 + }
52.1397 + public void clear() {
52.1398 + ConcurrentHashMap.this.clear();
52.1399 + }
52.1400 + }
52.1401 +
52.1402 + final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
52.1403 + public Iterator<Map.Entry<K,V>> iterator() {
52.1404 + return new EntryIterator();
52.1405 + }
52.1406 + public boolean contains(Object o) {
52.1407 + if (!(o instanceof Map.Entry))
52.1408 + return false;
52.1409 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
52.1410 + V v = ConcurrentHashMap.this.get(e.getKey());
52.1411 + return v != null && v.equals(e.getValue());
52.1412 + }
52.1413 + public boolean remove(Object o) {
52.1414 + if (!(o instanceof Map.Entry))
52.1415 + return false;
52.1416 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
52.1417 + return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
52.1418 + }
52.1419 + public int size() {
52.1420 + return ConcurrentHashMap.this.size();
52.1421 + }
52.1422 + public boolean isEmpty() {
52.1423 + return ConcurrentHashMap.this.isEmpty();
52.1424 + }
52.1425 + public void clear() {
52.1426 + ConcurrentHashMap.this.clear();
52.1427 + }
52.1428 + }
52.1429 +
52.1430 + /* ---------------- Serialization Support -------------- */
52.1431 +
52.1432 + /**
52.1433 + * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
52.1434 + * stream (i.e., serialize it).
52.1435 + * @param s the stream
52.1436 + * @serialData
52.1437 + * the key (Object) and value (Object)
52.1438 + * for each key-value mapping, followed by a null pair.
52.1439 + * The key-value mappings are emitted in no particular order.
52.1440 + */
52.1441 + private void writeObject(java.io.ObjectOutputStream s) throws IOException {
52.1442 + // force all segments for serialization compatibility
52.1443 + for (int k = 0; k < segments.length; ++k)
52.1444 + ensureSegment(k);
52.1445 + s.defaultWriteObject();
52.1446 +
52.1447 + final Segment<K,V>[] segments = this.segments;
52.1448 + for (int k = 0; k < segments.length; ++k) {
52.1449 + Segment<K,V> seg = segmentAt(segments, k);
52.1450 + seg.lock();
52.1451 + try {
52.1452 + HashEntry<K,V>[] tab = seg.table;
52.1453 + for (int i = 0; i < tab.length; ++i) {
52.1454 + HashEntry<K,V> e;
52.1455 + for (e = entryAt(tab, i); e != null; e = e.next) {
52.1456 + s.writeObject(e.key);
52.1457 + s.writeObject(e.value);
52.1458 + }
52.1459 + }
52.1460 + } finally {
52.1461 + seg.unlock();
52.1462 + }
52.1463 + }
52.1464 + s.writeObject(null);
52.1465 + s.writeObject(null);
52.1466 + }
52.1467 +
52.1468 + /**
52.1469 + * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
52.1470 + * stream (i.e., deserialize it).
52.1471 + * @param s the stream
52.1472 + */
52.1473 + @SuppressWarnings("unchecked")
52.1474 + private void readObject(java.io.ObjectInputStream s)
52.1475 + throws IOException, ClassNotFoundException {
52.1476 + s.defaultReadObject();
52.1477 +
52.1478 + // Re-initialize segments to be minimally sized, and let grow.
52.1479 + int cap = MIN_SEGMENT_TABLE_CAPACITY;
52.1480 + final Segment<K,V>[] segments = this.segments;
52.1481 + for (int k = 0; k < segments.length; ++k) {
52.1482 + Segment<K,V> seg = segments[k];
52.1483 + if (seg != null) {
52.1484 + seg.threshold = (int)(cap * seg.loadFactor);
52.1485 + seg.table = (HashEntry<K,V>[]) new HashEntry[cap];
52.1486 + }
52.1487 + }
52.1488 +
52.1489 + // Read the keys and values, and put the mappings in the table
52.1490 + for (;;) {
52.1491 + K key = (K) s.readObject();
52.1492 + V value = (V) s.readObject();
52.1493 + if (key == null)
52.1494 + break;
52.1495 + put(key, value);
52.1496 + }
52.1497 + }
52.1498 +
52.1499 + // Unsafe mechanics
52.1500 + private static final sun.misc.Unsafe UNSAFE;
52.1501 + private static final long SBASE;
52.1502 + private static final int SSHIFT;
52.1503 + private static final long TBASE;
52.1504 + private static final int TSHIFT;
52.1505 +
52.1506 + static {
52.1507 + int ss, ts;
52.1508 + try {
52.1509 + UNSAFE = sun.misc.Unsafe.getUnsafe();
52.1510 + Class tc = HashEntry[].class;
52.1511 + Class sc = Segment[].class;
52.1512 + TBASE = UNSAFE.arrayBaseOffset(tc);
52.1513 + SBASE = UNSAFE.arrayBaseOffset(sc);
52.1514 + ts = UNSAFE.arrayIndexScale(tc);
52.1515 + ss = UNSAFE.arrayIndexScale(sc);
52.1516 + } catch (Exception e) {
52.1517 + throw new Error(e);
52.1518 + }
52.1519 + if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
52.1520 + throw new Error("data type scale not a power of two");
52.1521 + SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
52.1522 + TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
52.1523 + }
52.1524 +
52.1525 +}
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
53.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentMap.java Thu Oct 03 15:43:10 2013 +0200
53.3 @@ -0,0 +1,165 @@
53.4 +/*
53.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
53.6 + *
53.7 + * This code is free software; you can redistribute it and/or modify it
53.8 + * under the terms of the GNU General Public License version 2 only, as
53.9 + * published by the Free Software Foundation. Oracle designates this
53.10 + * particular file as subject to the "Classpath" exception as provided
53.11 + * by Oracle in the LICENSE file that accompanied this code.
53.12 + *
53.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
53.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
53.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
53.16 + * version 2 for more details (a copy is included in the LICENSE file that
53.17 + * accompanied this code).
53.18 + *
53.19 + * You should have received a copy of the GNU General Public License version
53.20 + * 2 along with this work; if not, write to the Free Software Foundation,
53.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
53.22 + *
53.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
53.24 + * or visit www.oracle.com if you need additional information or have any
53.25 + * questions.
53.26 + */
53.27 +
53.28 +/*
53.29 + * This file is available under and governed by the GNU General Public
53.30 + * License version 2 only, as published by the Free Software Foundation.
53.31 + * However, the following notice accompanied the original version of this
53.32 + * file:
53.33 + *
53.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
53.35 + * Expert Group and released to the public domain, as explained at
53.36 + * http://creativecommons.org/publicdomain/zero/1.0/
53.37 + */
53.38 +
53.39 +package java.util.concurrent;
53.40 +import java.util.Map;
53.41 +
53.42 +/**
53.43 + * A {@link java.util.Map} providing additional atomic
53.44 + * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods.
53.45 + *
53.46 + * <p>Memory consistency effects: As with other concurrent
53.47 + * collections, actions in a thread prior to placing an object into a
53.48 + * {@code ConcurrentMap} as a key or value
53.49 + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
53.50 + * actions subsequent to the access or removal of that object from
53.51 + * the {@code ConcurrentMap} in another thread.
53.52 + *
53.53 + * <p>This interface is a member of the
53.54 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
53.55 + * Java Collections Framework</a>.
53.56 + *
53.57 + * @since 1.5
53.58 + * @author Doug Lea
53.59 + * @param <K> the type of keys maintained by this map
53.60 + * @param <V> the type of mapped values
53.61 + */
53.62 +public interface ConcurrentMap<K, V> extends Map<K, V> {
53.63 + /**
53.64 + * If the specified key is not already associated
53.65 + * with a value, associate it with the given value.
53.66 + * This is equivalent to
53.67 + * <pre>
53.68 + * if (!map.containsKey(key))
53.69 + * return map.put(key, value);
53.70 + * else
53.71 + * return map.get(key);</pre>
53.72 + * except that the action is performed atomically.
53.73 + *
53.74 + * @param key key with which the specified value is to be associated
53.75 + * @param value value to be associated with the specified key
53.76 + * @return the previous value associated with the specified key, or
53.77 + * <tt>null</tt> if there was no mapping for the key.
53.78 + * (A <tt>null</tt> return can also indicate that the map
53.79 + * previously associated <tt>null</tt> with the key,
53.80 + * if the implementation supports null values.)
53.81 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
53.82 + * is not supported by this map
53.83 + * @throws ClassCastException if the class of the specified key or value
53.84 + * prevents it from being stored in this map
53.85 + * @throws NullPointerException if the specified key or value is null,
53.86 + * and this map does not permit null keys or values
53.87 + * @throws IllegalArgumentException if some property of the specified key
53.88 + * or value prevents it from being stored in this map
53.89 + *
53.90 + */
53.91 + V putIfAbsent(K key, V value);
53.92 +
53.93 + /**
53.94 + * Removes the entry for a key only if currently mapped to a given value.
53.95 + * This is equivalent to
53.96 + * <pre>
53.97 + * if (map.containsKey(key) && map.get(key).equals(value)) {
53.98 + * map.remove(key);
53.99 + * return true;
53.100 + * } else return false;</pre>
53.101 + * except that the action is performed atomically.
53.102 + *
53.103 + * @param key key with which the specified value is associated
53.104 + * @param value value expected to be associated with the specified key
53.105 + * @return <tt>true</tt> if the value was removed
53.106 + * @throws UnsupportedOperationException if the <tt>remove</tt> operation
53.107 + * is not supported by this map
53.108 + * @throws ClassCastException if the key or value is of an inappropriate
53.109 + * type for this map
53.110 + * (<a href="../Collection.html#optional-restrictions">optional</a>)
53.111 + * @throws NullPointerException if the specified key or value is null,
53.112 + * and this map does not permit null keys or values
53.113 + * (<a href="../Collection.html#optional-restrictions">optional</a>)
53.114 + */
53.115 + boolean remove(Object key, Object value);
53.116 +
53.117 + /**
53.118 + * Replaces the entry for a key only if currently mapped to a given value.
53.119 + * This is equivalent to
53.120 + * <pre>
53.121 + * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
53.122 + * map.put(key, newValue);
53.123 + * return true;
53.124 + * } else return false;</pre>
53.125 + * except that the action is performed atomically.
53.126 + *
53.127 + * @param key key with which the specified value is associated
53.128 + * @param oldValue value expected to be associated with the specified key
53.129 + * @param newValue value to be associated with the specified key
53.130 + * @return <tt>true</tt> if the value was replaced
53.131 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
53.132 + * is not supported by this map
53.133 + * @throws ClassCastException if the class of a specified key or value
53.134 + * prevents it from being stored in this map
53.135 + * @throws NullPointerException if a specified key or value is null,
53.136 + * and this map does not permit null keys or values
53.137 + * @throws IllegalArgumentException if some property of a specified key
53.138 + * or value prevents it from being stored in this map
53.139 + */
53.140 + boolean replace(K key, V oldValue, V newValue);
53.141 +
53.142 + /**
53.143 + * Replaces the entry for a key only if currently mapped to some value.
53.144 + * This is equivalent to
53.145 + * <pre>
53.146 + * if (map.containsKey(key)) {
53.147 + * return map.put(key, value);
53.148 + * } else return null;</pre>
53.149 + * except that the action is performed atomically.
53.150 + *
53.151 + * @param key key with which the specified value is associated
53.152 + * @param value value to be associated with the specified key
53.153 + * @return the previous value associated with the specified key, or
53.154 + * <tt>null</tt> if there was no mapping for the key.
53.155 + * (A <tt>null</tt> return can also indicate that the map
53.156 + * previously associated <tt>null</tt> with the key,
53.157 + * if the implementation supports null values.)
53.158 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
53.159 + * is not supported by this map
53.160 + * @throws ClassCastException if the class of the specified key or value
53.161 + * prevents it from being stored in this map
53.162 + * @throws NullPointerException if the specified key or value is null,
53.163 + * and this map does not permit null keys or values
53.164 + * @throws IllegalArgumentException if some property of the specified key
53.165 + * or value prevents it from being stored in this map
53.166 + */
53.167 + V replace(K key, V value);
53.168 +}
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
54.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java Thu Oct 03 15:43:10 2013 +0200
54.3 @@ -0,0 +1,164 @@
54.4 +/*
54.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
54.6 + *
54.7 + * This code is free software; you can redistribute it and/or modify it
54.8 + * under the terms of the GNU General Public License version 2 only, as
54.9 + * published by the Free Software Foundation. Oracle designates this
54.10 + * particular file as subject to the "Classpath" exception as provided
54.11 + * by Oracle in the LICENSE file that accompanied this code.
54.12 + *
54.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
54.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
54.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
54.16 + * version 2 for more details (a copy is included in the LICENSE file that
54.17 + * accompanied this code).
54.18 + *
54.19 + * You should have received a copy of the GNU General Public License version
54.20 + * 2 along with this work; if not, write to the Free Software Foundation,
54.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
54.22 + *
54.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
54.24 + * or visit www.oracle.com if you need additional information or have any
54.25 + * questions.
54.26 + */
54.27 +
54.28 +/*
54.29 + * This file is available under and governed by the GNU General Public
54.30 + * License version 2 only, as published by the Free Software Foundation.
54.31 + * However, the following notice accompanied the original version of this
54.32 + * file:
54.33 + *
54.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
54.35 + * Expert Group and released to the public domain, as explained at
54.36 + * http://creativecommons.org/publicdomain/zero/1.0/
54.37 + */
54.38 +
54.39 +package java.util.concurrent.atomic;
54.40 +import sun.misc.Unsafe;
54.41 +
54.42 +/**
54.43 + * A {@code boolean} value that may be updated atomically. See the
54.44 + * {@link java.util.concurrent.atomic} package specification for
54.45 + * description of the properties of atomic variables. An
54.46 + * {@code AtomicBoolean} is used in applications such as atomically
54.47 + * updated flags, and cannot be used as a replacement for a
54.48 + * {@link java.lang.Boolean}.
54.49 + *
54.50 + * @since 1.5
54.51 + * @author Doug Lea
54.52 + */
54.53 +public class AtomicBoolean implements java.io.Serializable {
54.54 + private static final long serialVersionUID = 4654671469794556979L;
54.55 + // setup to use Unsafe.compareAndSwapInt for updates
54.56 + private static final Unsafe unsafe = Unsafe.getUnsafe();
54.57 + private static final long valueOffset;
54.58 +
54.59 + static {
54.60 + try {
54.61 + valueOffset = unsafe.objectFieldOffset
54.62 + (AtomicBoolean.class.getDeclaredField("value"));
54.63 + } catch (Exception ex) { throw new Error(ex); }
54.64 + }
54.65 +
54.66 + private volatile int value;
54.67 +
54.68 + /**
54.69 + * Creates a new {@code AtomicBoolean} with the given initial value.
54.70 + *
54.71 + * @param initialValue the initial value
54.72 + */
54.73 + public AtomicBoolean(boolean initialValue) {
54.74 + value = initialValue ? 1 : 0;
54.75 + }
54.76 +
54.77 + /**
54.78 + * Creates a new {@code AtomicBoolean} with initial value {@code false}.
54.79 + */
54.80 + public AtomicBoolean() {
54.81 + }
54.82 +
54.83 + /**
54.84 + * Returns the current value.
54.85 + *
54.86 + * @return the current value
54.87 + */
54.88 + public final boolean get() {
54.89 + return value != 0;
54.90 + }
54.91 +
54.92 + /**
54.93 + * Atomically sets the value to the given updated value
54.94 + * if the current value {@code ==} the expected value.
54.95 + *
54.96 + * @param expect the expected value
54.97 + * @param update the new value
54.98 + * @return true if successful. False return indicates that
54.99 + * the actual value was not equal to the expected value.
54.100 + */
54.101 + public final boolean compareAndSet(boolean expect, boolean update) {
54.102 + int e = expect ? 1 : 0;
54.103 + int u = update ? 1 : 0;
54.104 + return unsafe.compareAndSwapInt(this, valueOffset, e, u);
54.105 + }
54.106 +
54.107 + /**
54.108 + * Atomically sets the value to the given updated value
54.109 + * if the current value {@code ==} the expected value.
54.110 + *
54.111 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
54.112 + * and does not provide ordering guarantees, so is only rarely an
54.113 + * appropriate alternative to {@code compareAndSet}.
54.114 + *
54.115 + * @param expect the expected value
54.116 + * @param update the new value
54.117 + * @return true if successful.
54.118 + */
54.119 + public boolean weakCompareAndSet(boolean expect, boolean update) {
54.120 + int e = expect ? 1 : 0;
54.121 + int u = update ? 1 : 0;
54.122 + return unsafe.compareAndSwapInt(this, valueOffset, e, u);
54.123 + }
54.124 +
54.125 + /**
54.126 + * Unconditionally sets to the given value.
54.127 + *
54.128 + * @param newValue the new value
54.129 + */
54.130 + public final void set(boolean newValue) {
54.131 + value = newValue ? 1 : 0;
54.132 + }
54.133 +
54.134 + /**
54.135 + * Eventually sets to the given value.
54.136 + *
54.137 + * @param newValue the new value
54.138 + * @since 1.6
54.139 + */
54.140 + public final void lazySet(boolean newValue) {
54.141 + int v = newValue ? 1 : 0;
54.142 + unsafe.putOrderedInt(this, valueOffset, v);
54.143 + }
54.144 +
54.145 + /**
54.146 + * Atomically sets to the given value and returns the previous value.
54.147 + *
54.148 + * @param newValue the new value
54.149 + * @return the previous value
54.150 + */
54.151 + public final boolean getAndSet(boolean newValue) {
54.152 + for (;;) {
54.153 + boolean current = get();
54.154 + if (compareAndSet(current, newValue))
54.155 + return current;
54.156 + }
54.157 + }
54.158 +
54.159 + /**
54.160 + * Returns the String representation of the current value.
54.161 + * @return the String representation of the current value.
54.162 + */
54.163 + public String toString() {
54.164 + return Boolean.toString(get());
54.165 + }
54.166 +
54.167 +}
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
55.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java Thu Oct 03 15:43:10 2013 +0200
55.3 @@ -0,0 +1,265 @@
55.4 +/*
55.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55.6 + *
55.7 + * This code is free software; you can redistribute it and/or modify it
55.8 + * under the terms of the GNU General Public License version 2 only, as
55.9 + * published by the Free Software Foundation. Oracle designates this
55.10 + * particular file as subject to the "Classpath" exception as provided
55.11 + * by Oracle in the LICENSE file that accompanied this code.
55.12 + *
55.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
55.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
55.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
55.16 + * version 2 for more details (a copy is included in the LICENSE file that
55.17 + * accompanied this code).
55.18 + *
55.19 + * You should have received a copy of the GNU General Public License version
55.20 + * 2 along with this work; if not, write to the Free Software Foundation,
55.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
55.22 + *
55.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
55.24 + * or visit www.oracle.com if you need additional information or have any
55.25 + * questions.
55.26 + */
55.27 +
55.28 +/*
55.29 + * This file is available under and governed by the GNU General Public
55.30 + * License version 2 only, as published by the Free Software Foundation.
55.31 + * However, the following notice accompanied the original version of this
55.32 + * file:
55.33 + *
55.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
55.35 + * Expert Group and released to the public domain, as explained at
55.36 + * http://creativecommons.org/publicdomain/zero/1.0/
55.37 + */
55.38 +
55.39 +package java.util.concurrent.atomic;
55.40 +import sun.misc.Unsafe;
55.41 +
55.42 +/**
55.43 + * An {@code int} value that may be updated atomically. See the
55.44 + * {@link java.util.concurrent.atomic} package specification for
55.45 + * description of the properties of atomic variables. An
55.46 + * {@code AtomicInteger} is used in applications such as atomically
55.47 + * incremented counters, and cannot be used as a replacement for an
55.48 + * {@link java.lang.Integer}. However, this class does extend
55.49 + * {@code Number} to allow uniform access by tools and utilities that
55.50 + * deal with numerically-based classes.
55.51 + *
55.52 + * @since 1.5
55.53 + * @author Doug Lea
55.54 +*/
55.55 +public class AtomicInteger extends Number implements java.io.Serializable {
55.56 + private static final long serialVersionUID = 6214790243416807050L;
55.57 +
55.58 + // setup to use Unsafe.compareAndSwapInt for updates
55.59 + private static final Unsafe unsafe = Unsafe.getUnsafe();
55.60 + private static final long valueOffset;
55.61 +
55.62 + static {
55.63 + try {
55.64 + valueOffset = unsafe.objectFieldOffset
55.65 + (AtomicInteger.class.getDeclaredField("value"));
55.66 + } catch (Exception ex) { throw new Error(ex); }
55.67 + }
55.68 +
55.69 + private volatile int value;
55.70 +
55.71 + /**
55.72 + * Creates a new AtomicInteger with the given initial value.
55.73 + *
55.74 + * @param initialValue the initial value
55.75 + */
55.76 + public AtomicInteger(int initialValue) {
55.77 + value = initialValue;
55.78 + }
55.79 +
55.80 + /**
55.81 + * Creates a new AtomicInteger with initial value {@code 0}.
55.82 + */
55.83 + public AtomicInteger() {
55.84 + }
55.85 +
55.86 + /**
55.87 + * Gets the current value.
55.88 + *
55.89 + * @return the current value
55.90 + */
55.91 + public final int get() {
55.92 + return value;
55.93 + }
55.94 +
55.95 + /**
55.96 + * Sets to the given value.
55.97 + *
55.98 + * @param newValue the new value
55.99 + */
55.100 + public final void set(int newValue) {
55.101 + value = newValue;
55.102 + }
55.103 +
55.104 + /**
55.105 + * Eventually sets to the given value.
55.106 + *
55.107 + * @param newValue the new value
55.108 + * @since 1.6
55.109 + */
55.110 + public final void lazySet(int newValue) {
55.111 + unsafe.putOrderedInt(this, valueOffset, newValue);
55.112 + }
55.113 +
55.114 + /**
55.115 + * Atomically sets to the given value and returns the old value.
55.116 + *
55.117 + * @param newValue the new value
55.118 + * @return the previous value
55.119 + */
55.120 + public final int getAndSet(int newValue) {
55.121 + for (;;) {
55.122 + int current = get();
55.123 + if (compareAndSet(current, newValue))
55.124 + return current;
55.125 + }
55.126 + }
55.127 +
55.128 + /**
55.129 + * Atomically sets the value to the given updated value
55.130 + * if the current value {@code ==} the expected value.
55.131 + *
55.132 + * @param expect the expected value
55.133 + * @param update the new value
55.134 + * @return true if successful. False return indicates that
55.135 + * the actual value was not equal to the expected value.
55.136 + */
55.137 + public final boolean compareAndSet(int expect, int update) {
55.138 + return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
55.139 + }
55.140 +
55.141 + /**
55.142 + * Atomically sets the value to the given updated value
55.143 + * if the current value {@code ==} the expected value.
55.144 + *
55.145 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
55.146 + * and does not provide ordering guarantees, so is only rarely an
55.147 + * appropriate alternative to {@code compareAndSet}.
55.148 + *
55.149 + * @param expect the expected value
55.150 + * @param update the new value
55.151 + * @return true if successful.
55.152 + */
55.153 + public final boolean weakCompareAndSet(int expect, int update) {
55.154 + return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
55.155 + }
55.156 +
55.157 + /**
55.158 + * Atomically increments by one the current value.
55.159 + *
55.160 + * @return the previous value
55.161 + */
55.162 + public final int getAndIncrement() {
55.163 + for (;;) {
55.164 + int current = get();
55.165 + int next = current + 1;
55.166 + if (compareAndSet(current, next))
55.167 + return current;
55.168 + }
55.169 + }
55.170 +
55.171 + /**
55.172 + * Atomically decrements by one the current value.
55.173 + *
55.174 + * @return the previous value
55.175 + */
55.176 + public final int getAndDecrement() {
55.177 + for (;;) {
55.178 + int current = get();
55.179 + int next = current - 1;
55.180 + if (compareAndSet(current, next))
55.181 + return current;
55.182 + }
55.183 + }
55.184 +
55.185 + /**
55.186 + * Atomically adds the given value to the current value.
55.187 + *
55.188 + * @param delta the value to add
55.189 + * @return the previous value
55.190 + */
55.191 + public final int getAndAdd(int delta) {
55.192 + for (;;) {
55.193 + int current = get();
55.194 + int next = current + delta;
55.195 + if (compareAndSet(current, next))
55.196 + return current;
55.197 + }
55.198 + }
55.199 +
55.200 + /**
55.201 + * Atomically increments by one the current value.
55.202 + *
55.203 + * @return the updated value
55.204 + */
55.205 + public final int incrementAndGet() {
55.206 + for (;;) {
55.207 + int current = get();
55.208 + int next = current + 1;
55.209 + if (compareAndSet(current, next))
55.210 + return next;
55.211 + }
55.212 + }
55.213 +
55.214 + /**
55.215 + * Atomically decrements by one the current value.
55.216 + *
55.217 + * @return the updated value
55.218 + */
55.219 + public final int decrementAndGet() {
55.220 + for (;;) {
55.221 + int current = get();
55.222 + int next = current - 1;
55.223 + if (compareAndSet(current, next))
55.224 + return next;
55.225 + }
55.226 + }
55.227 +
55.228 + /**
55.229 + * Atomically adds the given value to the current value.
55.230 + *
55.231 + * @param delta the value to add
55.232 + * @return the updated value
55.233 + */
55.234 + public final int addAndGet(int delta) {
55.235 + for (;;) {
55.236 + int current = get();
55.237 + int next = current + delta;
55.238 + if (compareAndSet(current, next))
55.239 + return next;
55.240 + }
55.241 + }
55.242 +
55.243 + /**
55.244 + * Returns the String representation of the current value.
55.245 + * @return the String representation of the current value.
55.246 + */
55.247 + public String toString() {
55.248 + return Integer.toString(get());
55.249 + }
55.250 +
55.251 +
55.252 + public int intValue() {
55.253 + return get();
55.254 + }
55.255 +
55.256 + public long longValue() {
55.257 + return (long)get();
55.258 + }
55.259 +
55.260 + public float floatValue() {
55.261 + return (float)get();
55.262 + }
55.263 +
55.264 + public double doubleValue() {
55.265 + return (double)get();
55.266 + }
55.267 +
55.268 +}
56.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
56.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java Thu Oct 03 15:43:10 2013 +0200
56.3 @@ -0,0 +1,284 @@
56.4 +/*
56.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
56.6 + *
56.7 + * This code is free software; you can redistribute it and/or modify it
56.8 + * under the terms of the GNU General Public License version 2 only, as
56.9 + * published by the Free Software Foundation. Oracle designates this
56.10 + * particular file as subject to the "Classpath" exception as provided
56.11 + * by Oracle in the LICENSE file that accompanied this code.
56.12 + *
56.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
56.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
56.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
56.16 + * version 2 for more details (a copy is included in the LICENSE file that
56.17 + * accompanied this code).
56.18 + *
56.19 + * You should have received a copy of the GNU General Public License version
56.20 + * 2 along with this work; if not, write to the Free Software Foundation,
56.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
56.22 + *
56.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
56.24 + * or visit www.oracle.com if you need additional information or have any
56.25 + * questions.
56.26 + */
56.27 +
56.28 +/*
56.29 + * This file is available under and governed by the GNU General Public
56.30 + * License version 2 only, as published by the Free Software Foundation.
56.31 + * However, the following notice accompanied the original version of this
56.32 + * file:
56.33 + *
56.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
56.35 + * Expert Group and released to the public domain, as explained at
56.36 + * http://creativecommons.org/publicdomain/zero/1.0/
56.37 + */
56.38 +
56.39 +package java.util.concurrent.atomic;
56.40 +import sun.misc.Unsafe;
56.41 +import java.util.*;
56.42 +
56.43 +/**
56.44 + * An {@code int} array in which elements may be updated atomically.
56.45 + * See the {@link java.util.concurrent.atomic} package
56.46 + * specification for description of the properties of atomic
56.47 + * variables.
56.48 + * @since 1.5
56.49 + * @author Doug Lea
56.50 + */
56.51 +public class AtomicIntegerArray implements java.io.Serializable {
56.52 + private static final long serialVersionUID = 2862133569453604235L;
56.53 +
56.54 + private static final Unsafe unsafe = Unsafe.getUnsafe();
56.55 + private static final int base = unsafe.arrayBaseOffset(int[].class);
56.56 + private static final int shift;
56.57 + private final int[] array;
56.58 +
56.59 + static {
56.60 + int scale = unsafe.arrayIndexScale(int[].class);
56.61 + if ((scale & (scale - 1)) != 0)
56.62 + throw new Error("data type scale not a power of two");
56.63 + shift = 31 - Integer.numberOfLeadingZeros(scale);
56.64 + }
56.65 +
56.66 + private long checkedByteOffset(int i) {
56.67 + if (i < 0 || i >= array.length)
56.68 + throw new IndexOutOfBoundsException("index " + i);
56.69 +
56.70 + return byteOffset(i);
56.71 + }
56.72 +
56.73 + private static long byteOffset(int i) {
56.74 + return ((long) i << shift) + base;
56.75 + }
56.76 +
56.77 + /**
56.78 + * Creates a new AtomicIntegerArray of the given length, with all
56.79 + * elements initially zero.
56.80 + *
56.81 + * @param length the length of the array
56.82 + */
56.83 + public AtomicIntegerArray(int length) {
56.84 + array = new int[length];
56.85 + }
56.86 +
56.87 + /**
56.88 + * Creates a new AtomicIntegerArray with the same length as, and
56.89 + * all elements copied from, the given array.
56.90 + *
56.91 + * @param array the array to copy elements from
56.92 + * @throws NullPointerException if array is null
56.93 + */
56.94 + public AtomicIntegerArray(int[] array) {
56.95 + // Visibility guaranteed by final field guarantees
56.96 + this.array = array.clone();
56.97 + }
56.98 +
56.99 + /**
56.100 + * Returns the length of the array.
56.101 + *
56.102 + * @return the length of the array
56.103 + */
56.104 + public final int length() {
56.105 + return array.length;
56.106 + }
56.107 +
56.108 + /**
56.109 + * Gets the current value at position {@code i}.
56.110 + *
56.111 + * @param i the index
56.112 + * @return the current value
56.113 + */
56.114 + public final int get(int i) {
56.115 + return getRaw(checkedByteOffset(i));
56.116 + }
56.117 +
56.118 + private int getRaw(long offset) {
56.119 + return unsafe.getIntVolatile(array, offset);
56.120 + }
56.121 +
56.122 + /**
56.123 + * Sets the element at position {@code i} to the given value.
56.124 + *
56.125 + * @param i the index
56.126 + * @param newValue the new value
56.127 + */
56.128 + public final void set(int i, int newValue) {
56.129 + unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
56.130 + }
56.131 +
56.132 + /**
56.133 + * Eventually sets the element at position {@code i} to the given value.
56.134 + *
56.135 + * @param i the index
56.136 + * @param newValue the new value
56.137 + * @since 1.6
56.138 + */
56.139 + public final void lazySet(int i, int newValue) {
56.140 + unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
56.141 + }
56.142 +
56.143 + /**
56.144 + * Atomically sets the element at position {@code i} to the given
56.145 + * value and returns the old value.
56.146 + *
56.147 + * @param i the index
56.148 + * @param newValue the new value
56.149 + * @return the previous value
56.150 + */
56.151 + public final int getAndSet(int i, int newValue) {
56.152 + long offset = checkedByteOffset(i);
56.153 + while (true) {
56.154 + int current = getRaw(offset);
56.155 + if (compareAndSetRaw(offset, current, newValue))
56.156 + return current;
56.157 + }
56.158 + }
56.159 +
56.160 + /**
56.161 + * Atomically sets the element at position {@code i} to the given
56.162 + * updated value if the current value {@code ==} the expected value.
56.163 + *
56.164 + * @param i the index
56.165 + * @param expect the expected value
56.166 + * @param update the new value
56.167 + * @return true if successful. False return indicates that
56.168 + * the actual value was not equal to the expected value.
56.169 + */
56.170 + public final boolean compareAndSet(int i, int expect, int update) {
56.171 + return compareAndSetRaw(checkedByteOffset(i), expect, update);
56.172 + }
56.173 +
56.174 + private boolean compareAndSetRaw(long offset, int expect, int update) {
56.175 + return unsafe.compareAndSwapInt(array, offset, expect, update);
56.176 + }
56.177 +
56.178 + /**
56.179 + * Atomically sets the element at position {@code i} to the given
56.180 + * updated value if the current value {@code ==} the expected value.
56.181 + *
56.182 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
56.183 + * and does not provide ordering guarantees, so is only rarely an
56.184 + * appropriate alternative to {@code compareAndSet}.
56.185 + *
56.186 + * @param i the index
56.187 + * @param expect the expected value
56.188 + * @param update the new value
56.189 + * @return true if successful.
56.190 + */
56.191 + public final boolean weakCompareAndSet(int i, int expect, int update) {
56.192 + return compareAndSet(i, expect, update);
56.193 + }
56.194 +
56.195 + /**
56.196 + * Atomically increments by one the element at index {@code i}.
56.197 + *
56.198 + * @param i the index
56.199 + * @return the previous value
56.200 + */
56.201 + public final int getAndIncrement(int i) {
56.202 + return getAndAdd(i, 1);
56.203 + }
56.204 +
56.205 + /**
56.206 + * Atomically decrements by one the element at index {@code i}.
56.207 + *
56.208 + * @param i the index
56.209 + * @return the previous value
56.210 + */
56.211 + public final int getAndDecrement(int i) {
56.212 + return getAndAdd(i, -1);
56.213 + }
56.214 +
56.215 + /**
56.216 + * Atomically adds the given value to the element at index {@code i}.
56.217 + *
56.218 + * @param i the index
56.219 + * @param delta the value to add
56.220 + * @return the previous value
56.221 + */
56.222 + public final int getAndAdd(int i, int delta) {
56.223 + long offset = checkedByteOffset(i);
56.224 + while (true) {
56.225 + int current = getRaw(offset);
56.226 + if (compareAndSetRaw(offset, current, current + delta))
56.227 + return current;
56.228 + }
56.229 + }
56.230 +
56.231 + /**
56.232 + * Atomically increments by one the element at index {@code i}.
56.233 + *
56.234 + * @param i the index
56.235 + * @return the updated value
56.236 + */
56.237 + public final int incrementAndGet(int i) {
56.238 + return addAndGet(i, 1);
56.239 + }
56.240 +
56.241 + /**
56.242 + * Atomically decrements by one the element at index {@code i}.
56.243 + *
56.244 + * @param i the index
56.245 + * @return the updated value
56.246 + */
56.247 + public final int decrementAndGet(int i) {
56.248 + return addAndGet(i, -1);
56.249 + }
56.250 +
56.251 + /**
56.252 + * Atomically adds the given value to the element at index {@code i}.
56.253 + *
56.254 + * @param i the index
56.255 + * @param delta the value to add
56.256 + * @return the updated value
56.257 + */
56.258 + public final int addAndGet(int i, int delta) {
56.259 + long offset = checkedByteOffset(i);
56.260 + while (true) {
56.261 + int current = getRaw(offset);
56.262 + int next = current + delta;
56.263 + if (compareAndSetRaw(offset, current, next))
56.264 + return next;
56.265 + }
56.266 + }
56.267 +
56.268 + /**
56.269 + * Returns the String representation of the current values of array.
56.270 + * @return the String representation of the current values of array
56.271 + */
56.272 + public String toString() {
56.273 + int iMax = array.length - 1;
56.274 + if (iMax == -1)
56.275 + return "[]";
56.276 +
56.277 + StringBuilder b = new StringBuilder();
56.278 + b.append('[');
56.279 + for (int i = 0; ; i++) {
56.280 + b.append(getRaw(byteOffset(i)));
56.281 + if (i == iMax)
56.282 + return b.append(']').toString();
56.283 + b.append(',').append(' ');
56.284 + }
56.285 + }
56.286 +
56.287 +}
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLong.java Thu Oct 03 15:43:10 2013 +0200
57.3 @@ -0,0 +1,279 @@
57.4 +/*
57.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
57.6 + *
57.7 + * This code is free software; you can redistribute it and/or modify it
57.8 + * under the terms of the GNU General Public License version 2 only, as
57.9 + * published by the Free Software Foundation. Oracle designates this
57.10 + * particular file as subject to the "Classpath" exception as provided
57.11 + * by Oracle in the LICENSE file that accompanied this code.
57.12 + *
57.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
57.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
57.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
57.16 + * version 2 for more details (a copy is included in the LICENSE file that
57.17 + * accompanied this code).
57.18 + *
57.19 + * You should have received a copy of the GNU General Public License version
57.20 + * 2 along with this work; if not, write to the Free Software Foundation,
57.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
57.22 + *
57.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
57.24 + * or visit www.oracle.com if you need additional information or have any
57.25 + * questions.
57.26 + */
57.27 +
57.28 +/*
57.29 + * This file is available under and governed by the GNU General Public
57.30 + * License version 2 only, as published by the Free Software Foundation.
57.31 + * However, the following notice accompanied the original version of this
57.32 + * file:
57.33 + *
57.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
57.35 + * Expert Group and released to the public domain, as explained at
57.36 + * http://creativecommons.org/publicdomain/zero/1.0/
57.37 + */
57.38 +
57.39 +package java.util.concurrent.atomic;
57.40 +import sun.misc.Unsafe;
57.41 +
57.42 +/**
57.43 + * A {@code long} value that may be updated atomically. See the
57.44 + * {@link java.util.concurrent.atomic} package specification for
57.45 + * description of the properties of atomic variables. An
57.46 + * {@code AtomicLong} is used in applications such as atomically
57.47 + * incremented sequence numbers, and cannot be used as a replacement
57.48 + * for a {@link java.lang.Long}. However, this class does extend
57.49 + * {@code Number} to allow uniform access by tools and utilities that
57.50 + * deal with numerically-based classes.
57.51 + *
57.52 + * @since 1.5
57.53 + * @author Doug Lea
57.54 + */
57.55 +public class AtomicLong extends Number implements java.io.Serializable {
57.56 + private static final long serialVersionUID = 1927816293512124184L;
57.57 +
57.58 + // setup to use Unsafe.compareAndSwapLong for updates
57.59 + private static final Unsafe unsafe = Unsafe.getUnsafe();
57.60 + private static final long valueOffset;
57.61 +
57.62 + /**
57.63 + * Records whether the underlying JVM supports lockless
57.64 + * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
57.65 + * method works in either case, some constructions should be
57.66 + * handled at Java level to avoid locking user-visible locks.
57.67 + */
57.68 + static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
57.69 +
57.70 + /**
57.71 + * Returns whether underlying JVM supports lockless CompareAndSet
57.72 + * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
57.73 + */
57.74 + private static native boolean VMSupportsCS8();
57.75 +
57.76 + static {
57.77 + try {
57.78 + valueOffset = unsafe.objectFieldOffset
57.79 + (AtomicLong.class.getDeclaredField("value"));
57.80 + } catch (Exception ex) { throw new Error(ex); }
57.81 + }
57.82 +
57.83 + private volatile long value;
57.84 +
57.85 + /**
57.86 + * Creates a new AtomicLong with the given initial value.
57.87 + *
57.88 + * @param initialValue the initial value
57.89 + */
57.90 + public AtomicLong(long initialValue) {
57.91 + value = initialValue;
57.92 + }
57.93 +
57.94 + /**
57.95 + * Creates a new AtomicLong with initial value {@code 0}.
57.96 + */
57.97 + public AtomicLong() {
57.98 + }
57.99 +
57.100 + /**
57.101 + * Gets the current value.
57.102 + *
57.103 + * @return the current value
57.104 + */
57.105 + public final long get() {
57.106 + return value;
57.107 + }
57.108 +
57.109 + /**
57.110 + * Sets to the given value.
57.111 + *
57.112 + * @param newValue the new value
57.113 + */
57.114 + public final void set(long newValue) {
57.115 + value = newValue;
57.116 + }
57.117 +
57.118 + /**
57.119 + * Eventually sets to the given value.
57.120 + *
57.121 + * @param newValue the new value
57.122 + * @since 1.6
57.123 + */
57.124 + public final void lazySet(long newValue) {
57.125 + unsafe.putOrderedLong(this, valueOffset, newValue);
57.126 + }
57.127 +
57.128 + /**
57.129 + * Atomically sets to the given value and returns the old value.
57.130 + *
57.131 + * @param newValue the new value
57.132 + * @return the previous value
57.133 + */
57.134 + public final long getAndSet(long newValue) {
57.135 + while (true) {
57.136 + long current = get();
57.137 + if (compareAndSet(current, newValue))
57.138 + return current;
57.139 + }
57.140 + }
57.141 +
57.142 + /**
57.143 + * Atomically sets the value to the given updated value
57.144 + * if the current value {@code ==} the expected value.
57.145 + *
57.146 + * @param expect the expected value
57.147 + * @param update the new value
57.148 + * @return true if successful. False return indicates that
57.149 + * the actual value was not equal to the expected value.
57.150 + */
57.151 + public final boolean compareAndSet(long expect, long update) {
57.152 + return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
57.153 + }
57.154 +
57.155 + /**
57.156 + * Atomically sets the value to the given updated value
57.157 + * if the current value {@code ==} the expected value.
57.158 + *
57.159 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
57.160 + * and does not provide ordering guarantees, so is only rarely an
57.161 + * appropriate alternative to {@code compareAndSet}.
57.162 + *
57.163 + * @param expect the expected value
57.164 + * @param update the new value
57.165 + * @return true if successful.
57.166 + */
57.167 + public final boolean weakCompareAndSet(long expect, long update) {
57.168 + return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
57.169 + }
57.170 +
57.171 + /**
57.172 + * Atomically increments by one the current value.
57.173 + *
57.174 + * @return the previous value
57.175 + */
57.176 + public final long getAndIncrement() {
57.177 + while (true) {
57.178 + long current = get();
57.179 + long next = current + 1;
57.180 + if (compareAndSet(current, next))
57.181 + return current;
57.182 + }
57.183 + }
57.184 +
57.185 + /**
57.186 + * Atomically decrements by one the current value.
57.187 + *
57.188 + * @return the previous value
57.189 + */
57.190 + public final long getAndDecrement() {
57.191 + while (true) {
57.192 + long current = get();
57.193 + long next = current - 1;
57.194 + if (compareAndSet(current, next))
57.195 + return current;
57.196 + }
57.197 + }
57.198 +
57.199 + /**
57.200 + * Atomically adds the given value to the current value.
57.201 + *
57.202 + * @param delta the value to add
57.203 + * @return the previous value
57.204 + */
57.205 + public final long getAndAdd(long delta) {
57.206 + while (true) {
57.207 + long current = get();
57.208 + long next = current + delta;
57.209 + if (compareAndSet(current, next))
57.210 + return current;
57.211 + }
57.212 + }
57.213 +
57.214 + /**
57.215 + * Atomically increments by one the current value.
57.216 + *
57.217 + * @return the updated value
57.218 + */
57.219 + public final long incrementAndGet() {
57.220 + for (;;) {
57.221 + long current = get();
57.222 + long next = current + 1;
57.223 + if (compareAndSet(current, next))
57.224 + return next;
57.225 + }
57.226 + }
57.227 +
57.228 + /**
57.229 + * Atomically decrements by one the current value.
57.230 + *
57.231 + * @return the updated value
57.232 + */
57.233 + public final long decrementAndGet() {
57.234 + for (;;) {
57.235 + long current = get();
57.236 + long next = current - 1;
57.237 + if (compareAndSet(current, next))
57.238 + return next;
57.239 + }
57.240 + }
57.241 +
57.242 + /**
57.243 + * Atomically adds the given value to the current value.
57.244 + *
57.245 + * @param delta the value to add
57.246 + * @return the updated value
57.247 + */
57.248 + public final long addAndGet(long delta) {
57.249 + for (;;) {
57.250 + long current = get();
57.251 + long next = current + delta;
57.252 + if (compareAndSet(current, next))
57.253 + return next;
57.254 + }
57.255 + }
57.256 +
57.257 + /**
57.258 + * Returns the String representation of the current value.
57.259 + * @return the String representation of the current value.
57.260 + */
57.261 + public String toString() {
57.262 + return Long.toString(get());
57.263 + }
57.264 +
57.265 +
57.266 + public int intValue() {
57.267 + return (int)get();
57.268 + }
57.269 +
57.270 + public long longValue() {
57.271 + return get();
57.272 + }
57.273 +
57.274 + public float floatValue() {
57.275 + return (float)get();
57.276 + }
57.277 +
57.278 + public double doubleValue() {
57.279 + return (double)get();
57.280 + }
57.281 +
57.282 +}
58.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java Thu Oct 03 15:43:10 2013 +0200
58.3 @@ -0,0 +1,284 @@
58.4 +/*
58.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
58.6 + *
58.7 + * This code is free software; you can redistribute it and/or modify it
58.8 + * under the terms of the GNU General Public License version 2 only, as
58.9 + * published by the Free Software Foundation. Oracle designates this
58.10 + * particular file as subject to the "Classpath" exception as provided
58.11 + * by Oracle in the LICENSE file that accompanied this code.
58.12 + *
58.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
58.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
58.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
58.16 + * version 2 for more details (a copy is included in the LICENSE file that
58.17 + * accompanied this code).
58.18 + *
58.19 + * You should have received a copy of the GNU General Public License version
58.20 + * 2 along with this work; if not, write to the Free Software Foundation,
58.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
58.22 + *
58.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
58.24 + * or visit www.oracle.com if you need additional information or have any
58.25 + * questions.
58.26 + */
58.27 +
58.28 +/*
58.29 + * This file is available under and governed by the GNU General Public
58.30 + * License version 2 only, as published by the Free Software Foundation.
58.31 + * However, the following notice accompanied the original version of this
58.32 + * file:
58.33 + *
58.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
58.35 + * Expert Group and released to the public domain, as explained at
58.36 + * http://creativecommons.org/publicdomain/zero/1.0/
58.37 + */
58.38 +
58.39 +package java.util.concurrent.atomic;
58.40 +import sun.misc.Unsafe;
58.41 +import java.util.*;
58.42 +
58.43 +/**
58.44 + * A {@code long} array in which elements may be updated atomically.
58.45 + * See the {@link java.util.concurrent.atomic} package specification
58.46 + * for description of the properties of atomic variables.
58.47 + * @since 1.5
58.48 + * @author Doug Lea
58.49 + */
58.50 +public class AtomicLongArray implements java.io.Serializable {
58.51 + private static final long serialVersionUID = -2308431214976778248L;
58.52 +
58.53 + private static final Unsafe unsafe = Unsafe.getUnsafe();
58.54 + private static final int base = unsafe.arrayBaseOffset(long[].class);
58.55 + private static final int shift;
58.56 + private final long[] array;
58.57 +
58.58 + static {
58.59 + int scale = unsafe.arrayIndexScale(long[].class);
58.60 + if ((scale & (scale - 1)) != 0)
58.61 + throw new Error("data type scale not a power of two");
58.62 + shift = 31 - Integer.numberOfLeadingZeros(scale);
58.63 + }
58.64 +
58.65 + private long checkedByteOffset(int i) {
58.66 + if (i < 0 || i >= array.length)
58.67 + throw new IndexOutOfBoundsException("index " + i);
58.68 +
58.69 + return byteOffset(i);
58.70 + }
58.71 +
58.72 + private static long byteOffset(int i) {
58.73 + return ((long) i << shift) + base;
58.74 + }
58.75 +
58.76 + /**
58.77 + * Creates a new AtomicLongArray of the given length, with all
58.78 + * elements initially zero.
58.79 + *
58.80 + * @param length the length of the array
58.81 + */
58.82 + public AtomicLongArray(int length) {
58.83 + array = new long[length];
58.84 + }
58.85 +
58.86 + /**
58.87 + * Creates a new AtomicLongArray with the same length as, and
58.88 + * all elements copied from, the given array.
58.89 + *
58.90 + * @param array the array to copy elements from
58.91 + * @throws NullPointerException if array is null
58.92 + */
58.93 + public AtomicLongArray(long[] array) {
58.94 + // Visibility guaranteed by final field guarantees
58.95 + this.array = array.clone();
58.96 + }
58.97 +
58.98 + /**
58.99 + * Returns the length of the array.
58.100 + *
58.101 + * @return the length of the array
58.102 + */
58.103 + public final int length() {
58.104 + return array.length;
58.105 + }
58.106 +
58.107 + /**
58.108 + * Gets the current value at position {@code i}.
58.109 + *
58.110 + * @param i the index
58.111 + * @return the current value
58.112 + */
58.113 + public final long get(int i) {
58.114 + return getRaw(checkedByteOffset(i));
58.115 + }
58.116 +
58.117 + private long getRaw(long offset) {
58.118 + return unsafe.getLongVolatile(array, offset);
58.119 + }
58.120 +
58.121 + /**
58.122 + * Sets the element at position {@code i} to the given value.
58.123 + *
58.124 + * @param i the index
58.125 + * @param newValue the new value
58.126 + */
58.127 + public final void set(int i, long newValue) {
58.128 + unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
58.129 + }
58.130 +
58.131 + /**
58.132 + * Eventually sets the element at position {@code i} to the given value.
58.133 + *
58.134 + * @param i the index
58.135 + * @param newValue the new value
58.136 + * @since 1.6
58.137 + */
58.138 + public final void lazySet(int i, long newValue) {
58.139 + unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
58.140 + }
58.141 +
58.142 +
58.143 + /**
58.144 + * Atomically sets the element at position {@code i} to the given value
58.145 + * and returns the old value.
58.146 + *
58.147 + * @param i the index
58.148 + * @param newValue the new value
58.149 + * @return the previous value
58.150 + */
58.151 + public final long getAndSet(int i, long newValue) {
58.152 + long offset = checkedByteOffset(i);
58.153 + while (true) {
58.154 + long current = getRaw(offset);
58.155 + if (compareAndSetRaw(offset, current, newValue))
58.156 + return current;
58.157 + }
58.158 + }
58.159 +
58.160 + /**
58.161 + * Atomically sets the element at position {@code i} to the given
58.162 + * updated value if the current value {@code ==} the expected value.
58.163 + *
58.164 + * @param i the index
58.165 + * @param expect the expected value
58.166 + * @param update the new value
58.167 + * @return true if successful. False return indicates that
58.168 + * the actual value was not equal to the expected value.
58.169 + */
58.170 + public final boolean compareAndSet(int i, long expect, long update) {
58.171 + return compareAndSetRaw(checkedByteOffset(i), expect, update);
58.172 + }
58.173 +
58.174 + private boolean compareAndSetRaw(long offset, long expect, long update) {
58.175 + return unsafe.compareAndSwapLong(array, offset, expect, update);
58.176 + }
58.177 +
58.178 + /**
58.179 + * Atomically sets the element at position {@code i} to the given
58.180 + * updated value if the current value {@code ==} the expected value.
58.181 + *
58.182 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
58.183 + * and does not provide ordering guarantees, so is only rarely an
58.184 + * appropriate alternative to {@code compareAndSet}.
58.185 + *
58.186 + * @param i the index
58.187 + * @param expect the expected value
58.188 + * @param update the new value
58.189 + * @return true if successful.
58.190 + */
58.191 + public final boolean weakCompareAndSet(int i, long expect, long update) {
58.192 + return compareAndSet(i, expect, update);
58.193 + }
58.194 +
58.195 + /**
58.196 + * Atomically increments by one the element at index {@code i}.
58.197 + *
58.198 + * @param i the index
58.199 + * @return the previous value
58.200 + */
58.201 + public final long getAndIncrement(int i) {
58.202 + return getAndAdd(i, 1);
58.203 + }
58.204 +
58.205 + /**
58.206 + * Atomically decrements by one the element at index {@code i}.
58.207 + *
58.208 + * @param i the index
58.209 + * @return the previous value
58.210 + */
58.211 + public final long getAndDecrement(int i) {
58.212 + return getAndAdd(i, -1);
58.213 + }
58.214 +
58.215 + /**
58.216 + * Atomically adds the given value to the element at index {@code i}.
58.217 + *
58.218 + * @param i the index
58.219 + * @param delta the value to add
58.220 + * @return the previous value
58.221 + */
58.222 + public final long getAndAdd(int i, long delta) {
58.223 + long offset = checkedByteOffset(i);
58.224 + while (true) {
58.225 + long current = getRaw(offset);
58.226 + if (compareAndSetRaw(offset, current, current + delta))
58.227 + return current;
58.228 + }
58.229 + }
58.230 +
58.231 + /**
58.232 + * Atomically increments by one the element at index {@code i}.
58.233 + *
58.234 + * @param i the index
58.235 + * @return the updated value
58.236 + */
58.237 + public final long incrementAndGet(int i) {
58.238 + return addAndGet(i, 1);
58.239 + }
58.240 +
58.241 + /**
58.242 + * Atomically decrements by one the element at index {@code i}.
58.243 + *
58.244 + * @param i the index
58.245 + * @return the updated value
58.246 + */
58.247 + public final long decrementAndGet(int i) {
58.248 + return addAndGet(i, -1);
58.249 + }
58.250 +
58.251 + /**
58.252 + * Atomically adds the given value to the element at index {@code i}.
58.253 + *
58.254 + * @param i the index
58.255 + * @param delta the value to add
58.256 + * @return the updated value
58.257 + */
58.258 + public long addAndGet(int i, long delta) {
58.259 + long offset = checkedByteOffset(i);
58.260 + while (true) {
58.261 + long current = getRaw(offset);
58.262 + long next = current + delta;
58.263 + if (compareAndSetRaw(offset, current, next))
58.264 + return next;
58.265 + }
58.266 + }
58.267 +
58.268 + /**
58.269 + * Returns the String representation of the current values of array.
58.270 + * @return the String representation of the current values of array
58.271 + */
58.272 + public String toString() {
58.273 + int iMax = array.length - 1;
58.274 + if (iMax == -1)
58.275 + return "[]";
58.276 +
58.277 + StringBuilder b = new StringBuilder();
58.278 + b.append('[');
58.279 + for (int i = 0; ; i++) {
58.280 + b.append(getRaw(byteOffset(i)));
58.281 + if (i == iMax)
58.282 + return b.append(']').toString();
58.283 + b.append(',').append(' ');
58.284 + }
58.285 + }
58.286 +
58.287 +}
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
59.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReference.java Thu Oct 03 15:43:10 2013 +0200
59.3 @@ -0,0 +1,155 @@
59.4 +/*
59.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
59.6 + *
59.7 + * This code is free software; you can redistribute it and/or modify it
59.8 + * under the terms of the GNU General Public License version 2 only, as
59.9 + * published by the Free Software Foundation. Oracle designates this
59.10 + * particular file as subject to the "Classpath" exception as provided
59.11 + * by Oracle in the LICENSE file that accompanied this code.
59.12 + *
59.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
59.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
59.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
59.16 + * version 2 for more details (a copy is included in the LICENSE file that
59.17 + * accompanied this code).
59.18 + *
59.19 + * You should have received a copy of the GNU General Public License version
59.20 + * 2 along with this work; if not, write to the Free Software Foundation,
59.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
59.22 + *
59.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
59.24 + * or visit www.oracle.com if you need additional information or have any
59.25 + * questions.
59.26 + */
59.27 +
59.28 +/*
59.29 + * This file is available under and governed by the GNU General Public
59.30 + * License version 2 only, as published by the Free Software Foundation.
59.31 + * However, the following notice accompanied the original version of this
59.32 + * file:
59.33 + *
59.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
59.35 + * Expert Group and released to the public domain, as explained at
59.36 + * http://creativecommons.org/publicdomain/zero/1.0/
59.37 + */
59.38 +
59.39 +package java.util.concurrent.atomic;
59.40 +import sun.misc.Unsafe;
59.41 +
59.42 +/**
59.43 + * An object reference that may be updated atomically. See the {@link
59.44 + * java.util.concurrent.atomic} package specification for description
59.45 + * of the properties of atomic variables.
59.46 + * @since 1.5
59.47 + * @author Doug Lea
59.48 + * @param <V> The type of object referred to by this reference
59.49 + */
59.50 +public class AtomicReference<V> implements java.io.Serializable {
59.51 + private static final long serialVersionUID = -1848883965231344442L;
59.52 +
59.53 + private static final Unsafe unsafe = Unsafe.getUnsafe();
59.54 + private static final long valueOffset;
59.55 +
59.56 + static {
59.57 + try {
59.58 + valueOffset = unsafe.objectFieldOffset
59.59 + (AtomicReference.class.getDeclaredField("value"));
59.60 + } catch (Exception ex) { throw new Error(ex); }
59.61 + }
59.62 +
59.63 + private volatile V value;
59.64 +
59.65 + /**
59.66 + * Creates a new AtomicReference with the given initial value.
59.67 + *
59.68 + * @param initialValue the initial value
59.69 + */
59.70 + public AtomicReference(V initialValue) {
59.71 + value = initialValue;
59.72 + }
59.73 +
59.74 + /**
59.75 + * Creates a new AtomicReference with null initial value.
59.76 + */
59.77 + public AtomicReference() {
59.78 + }
59.79 +
59.80 + /**
59.81 + * Gets the current value.
59.82 + *
59.83 + * @return the current value
59.84 + */
59.85 + public final V get() {
59.86 + return value;
59.87 + }
59.88 +
59.89 + /**
59.90 + * Sets to the given value.
59.91 + *
59.92 + * @param newValue the new value
59.93 + */
59.94 + public final void set(V newValue) {
59.95 + value = newValue;
59.96 + }
59.97 +
59.98 + /**
59.99 + * Eventually sets to the given value.
59.100 + *
59.101 + * @param newValue the new value
59.102 + * @since 1.6
59.103 + */
59.104 + public final void lazySet(V newValue) {
59.105 + unsafe.putOrderedObject(this, valueOffset, newValue);
59.106 + }
59.107 +
59.108 + /**
59.109 + * Atomically sets the value to the given updated value
59.110 + * if the current value {@code ==} the expected value.
59.111 + * @param expect the expected value
59.112 + * @param update the new value
59.113 + * @return true if successful. False return indicates that
59.114 + * the actual value was not equal to the expected value.
59.115 + */
59.116 + public final boolean compareAndSet(V expect, V update) {
59.117 + return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
59.118 + }
59.119 +
59.120 + /**
59.121 + * Atomically sets the value to the given updated value
59.122 + * if the current value {@code ==} the expected value.
59.123 + *
59.124 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
59.125 + * and does not provide ordering guarantees, so is only rarely an
59.126 + * appropriate alternative to {@code compareAndSet}.
59.127 + *
59.128 + * @param expect the expected value
59.129 + * @param update the new value
59.130 + * @return true if successful.
59.131 + */
59.132 + public final boolean weakCompareAndSet(V expect, V update) {
59.133 + return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
59.134 + }
59.135 +
59.136 + /**
59.137 + * Atomically sets to the given value and returns the old value.
59.138 + *
59.139 + * @param newValue the new value
59.140 + * @return the previous value
59.141 + */
59.142 + public final V getAndSet(V newValue) {
59.143 + while (true) {
59.144 + V x = get();
59.145 + if (compareAndSet(x, newValue))
59.146 + return x;
59.147 + }
59.148 + }
59.149 +
59.150 + /**
59.151 + * Returns the String representation of the current value.
59.152 + * @return the String representation of the current value.
59.153 + */
59.154 + public String toString() {
59.155 + return String.valueOf(get());
59.156 + }
59.157 +
59.158 +}
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java Thu Oct 03 15:43:10 2013 +0200
60.3 @@ -0,0 +1,213 @@
60.4 +/*
60.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
60.6 + *
60.7 + * This code is free software; you can redistribute it and/or modify it
60.8 + * under the terms of the GNU General Public License version 2 only, as
60.9 + * published by the Free Software Foundation. Oracle designates this
60.10 + * particular file as subject to the "Classpath" exception as provided
60.11 + * by Oracle in the LICENSE file that accompanied this code.
60.12 + *
60.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
60.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
60.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
60.16 + * version 2 for more details (a copy is included in the LICENSE file that
60.17 + * accompanied this code).
60.18 + *
60.19 + * You should have received a copy of the GNU General Public License version
60.20 + * 2 along with this work; if not, write to the Free Software Foundation,
60.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
60.22 + *
60.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
60.24 + * or visit www.oracle.com if you need additional information or have any
60.25 + * questions.
60.26 + */
60.27 +
60.28 +/*
60.29 + * This file is available under and governed by the GNU General Public
60.30 + * License version 2 only, as published by the Free Software Foundation.
60.31 + * However, the following notice accompanied the original version of this
60.32 + * file:
60.33 + *
60.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
60.35 + * Expert Group and released to the public domain, as explained at
60.36 + * http://creativecommons.org/publicdomain/zero/1.0/
60.37 + */
60.38 +
60.39 +package java.util.concurrent.atomic;
60.40 +import sun.misc.Unsafe;
60.41 +import java.util.*;
60.42 +
60.43 +/**
60.44 + * An array of object references in which elements may be updated
60.45 + * atomically. See the {@link java.util.concurrent.atomic} package
60.46 + * specification for description of the properties of atomic
60.47 + * variables.
60.48 + * @since 1.5
60.49 + * @author Doug Lea
60.50 + * @param <E> The base class of elements held in this array
60.51 + */
60.52 +public class AtomicReferenceArray<E> implements java.io.Serializable {
60.53 + private static final long serialVersionUID = -6209656149925076980L;
60.54 +
60.55 + private static final Unsafe unsafe = Unsafe.getUnsafe();
60.56 + private static final int base = unsafe.arrayBaseOffset(Object[].class);
60.57 + private static final int shift;
60.58 + private final Object[] array;
60.59 +
60.60 + static {
60.61 + int scale = unsafe.arrayIndexScale(Object[].class);
60.62 + if ((scale & (scale - 1)) != 0)
60.63 + throw new Error("data type scale not a power of two");
60.64 + shift = 31 - Integer.numberOfLeadingZeros(scale);
60.65 + }
60.66 +
60.67 + private long checkedByteOffset(int i) {
60.68 + if (i < 0 || i >= array.length)
60.69 + throw new IndexOutOfBoundsException("index " + i);
60.70 +
60.71 + return byteOffset(i);
60.72 + }
60.73 +
60.74 + private static long byteOffset(int i) {
60.75 + return ((long) i << shift) + base;
60.76 + }
60.77 +
60.78 + /**
60.79 + * Creates a new AtomicReferenceArray of the given length, with all
60.80 + * elements initially null.
60.81 + *
60.82 + * @param length the length of the array
60.83 + */
60.84 + public AtomicReferenceArray(int length) {
60.85 + array = new Object[length];
60.86 + }
60.87 +
60.88 + /**
60.89 + * Creates a new AtomicReferenceArray with the same length as, and
60.90 + * all elements copied from, the given array.
60.91 + *
60.92 + * @param array the array to copy elements from
60.93 + * @throws NullPointerException if array is null
60.94 + */
60.95 + public AtomicReferenceArray(E[] array) {
60.96 + // Visibility guaranteed by final field guarantees
60.97 + this.array = array.clone();
60.98 + }
60.99 +
60.100 + /**
60.101 + * Returns the length of the array.
60.102 + *
60.103 + * @return the length of the array
60.104 + */
60.105 + public final int length() {
60.106 + return array.length;
60.107 + }
60.108 +
60.109 + /**
60.110 + * Gets the current value at position {@code i}.
60.111 + *
60.112 + * @param i the index
60.113 + * @return the current value
60.114 + */
60.115 + public final E get(int i) {
60.116 + return getRaw(checkedByteOffset(i));
60.117 + }
60.118 +
60.119 + private E getRaw(long offset) {
60.120 + return (E) unsafe.getObjectVolatile(array, offset);
60.121 + }
60.122 +
60.123 + /**
60.124 + * Sets the element at position {@code i} to the given value.
60.125 + *
60.126 + * @param i the index
60.127 + * @param newValue the new value
60.128 + */
60.129 + public final void set(int i, E newValue) {
60.130 + unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
60.131 + }
60.132 +
60.133 + /**
60.134 + * Eventually sets the element at position {@code i} to the given value.
60.135 + *
60.136 + * @param i the index
60.137 + * @param newValue the new value
60.138 + * @since 1.6
60.139 + */
60.140 + public final void lazySet(int i, E newValue) {
60.141 + unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
60.142 + }
60.143 +
60.144 +
60.145 + /**
60.146 + * Atomically sets the element at position {@code i} to the given
60.147 + * value and returns the old value.
60.148 + *
60.149 + * @param i the index
60.150 + * @param newValue the new value
60.151 + * @return the previous value
60.152 + */
60.153 + public final E getAndSet(int i, E newValue) {
60.154 + long offset = checkedByteOffset(i);
60.155 + while (true) {
60.156 + E current = (E) getRaw(offset);
60.157 + if (compareAndSetRaw(offset, current, newValue))
60.158 + return current;
60.159 + }
60.160 + }
60.161 +
60.162 + /**
60.163 + * Atomically sets the element at position {@code i} to the given
60.164 + * updated value if the current value {@code ==} the expected value.
60.165 + *
60.166 + * @param i the index
60.167 + * @param expect the expected value
60.168 + * @param update the new value
60.169 + * @return true if successful. False return indicates that
60.170 + * the actual value was not equal to the expected value.
60.171 + */
60.172 + public final boolean compareAndSet(int i, E expect, E update) {
60.173 + return compareAndSetRaw(checkedByteOffset(i), expect, update);
60.174 + }
60.175 +
60.176 + private boolean compareAndSetRaw(long offset, E expect, E update) {
60.177 + return unsafe.compareAndSwapObject(array, offset, expect, update);
60.178 + }
60.179 +
60.180 + /**
60.181 + * Atomically sets the element at position {@code i} to the given
60.182 + * updated value if the current value {@code ==} the expected value.
60.183 + *
60.184 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
60.185 + * and does not provide ordering guarantees, so is only rarely an
60.186 + * appropriate alternative to {@code compareAndSet}.
60.187 + *
60.188 + * @param i the index
60.189 + * @param expect the expected value
60.190 + * @param update the new value
60.191 + * @return true if successful.
60.192 + */
60.193 + public final boolean weakCompareAndSet(int i, E expect, E update) {
60.194 + return compareAndSet(i, expect, update);
60.195 + }
60.196 +
60.197 + /**
60.198 + * Returns the String representation of the current values of array.
60.199 + * @return the String representation of the current values of array
60.200 + */
60.201 + public String toString() {
60.202 + int iMax = array.length - 1;
60.203 + if (iMax == -1)
60.204 + return "[]";
60.205 +
60.206 + StringBuilder b = new StringBuilder();
60.207 + b.append('[');
60.208 + for (int i = 0; ; i++) {
60.209 + b.append(getRaw(byteOffset(i)));
60.210 + if (i == iMax)
60.211 + return b.append(']').toString();
60.212 + b.append(',').append(' ');
60.213 + }
60.214 + }
60.215 +
60.216 +}
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/package-info.java Thu Oct 03 15:43:10 2013 +0200
61.3 @@ -0,0 +1,199 @@
61.4 +/*
61.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
61.6 + *
61.7 + * This code is free software; you can redistribute it and/or modify it
61.8 + * under the terms of the GNU General Public License version 2 only, as
61.9 + * published by the Free Software Foundation. Oracle designates this
61.10 + * particular file as subject to the "Classpath" exception as provided
61.11 + * by Oracle in the LICENSE file that accompanied this code.
61.12 + *
61.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
61.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
61.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
61.16 + * version 2 for more details (a copy is included in the LICENSE file that
61.17 + * accompanied this code).
61.18 + *
61.19 + * You should have received a copy of the GNU General Public License version
61.20 + * 2 along with this work; if not, write to the Free Software Foundation,
61.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
61.22 + *
61.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
61.24 + * or visit www.oracle.com if you need additional information or have any
61.25 + * questions.
61.26 + */
61.27 +
61.28 +/*
61.29 + * This file is available under and governed by the GNU General Public
61.30 + * License version 2 only, as published by the Free Software Foundation.
61.31 + * However, the following notice accompanied the original version of this
61.32 + * file:
61.33 + *
61.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
61.35 + * Expert Group and released to the public domain, as explained at
61.36 + * http://creativecommons.org/publicdomain/zero/1.0/
61.37 + */
61.38 +
61.39 +/**
61.40 + * A small toolkit of classes that support lock-free thread-safe
61.41 + * programming on single variables. In essence, the classes in this
61.42 + * package extend the notion of {@code volatile} values, fields, and
61.43 + * array elements to those that also provide an atomic conditional update
61.44 + * operation of the form:
61.45 + *
61.46 + * <pre>
61.47 + * boolean compareAndSet(expectedValue, updateValue);
61.48 + * </pre>
61.49 + *
61.50 + * <p>This method (which varies in argument types across different
61.51 + * classes) atomically sets a variable to the {@code updateValue} if it
61.52 + * currently holds the {@code expectedValue}, reporting {@code true} on
61.53 + * success. The classes in this package also contain methods to get and
61.54 + * unconditionally set values, as well as a weaker conditional atomic
61.55 + * update operation {@code weakCompareAndSet} described below.
61.56 + *
61.57 + * <p>The specifications of these methods enable implementations to
61.58 + * employ efficient machine-level atomic instructions that are available
61.59 + * on contemporary processors. However on some platforms, support may
61.60 + * entail some form of internal locking. Thus the methods are not
61.61 + * strictly guaranteed to be non-blocking --
61.62 + * a thread may block transiently before performing the operation.
61.63 + *
61.64 + * <p>Instances of classes
61.65 + * {@link java.util.concurrent.atomic.AtomicBoolean},
61.66 + * {@link java.util.concurrent.atomic.AtomicInteger},
61.67 + * {@link java.util.concurrent.atomic.AtomicLong}, and
61.68 + * {@link java.util.concurrent.atomic.AtomicReference}
61.69 + * each provide access and updates to a single variable of the
61.70 + * corresponding type. Each class also provides appropriate utility
61.71 + * methods for that type. For example, classes {@code AtomicLong} and
61.72 + * {@code AtomicInteger} provide atomic increment methods. One
61.73 + * application is to generate sequence numbers, as in:
61.74 + *
61.75 + * <pre>
61.76 + * class Sequencer {
61.77 + * private final AtomicLong sequenceNumber
61.78 + * = new AtomicLong(0);
61.79 + * public long next() {
61.80 + * return sequenceNumber.getAndIncrement();
61.81 + * }
61.82 + * }
61.83 + * </pre>
61.84 + *
61.85 + * <p>The memory effects for accesses and updates of atomics generally
61.86 + * follow the rules for volatiles, as stated in section 17.4 of
61.87 + * <cite>The Java™ Language Specification</cite>.
61.88 + *
61.89 + * <ul>
61.90 + *
61.91 + * <li> {@code get} has the memory effects of reading a
61.92 + * {@code volatile} variable.
61.93 + *
61.94 + * <li> {@code set} has the memory effects of writing (assigning) a
61.95 + * {@code volatile} variable.
61.96 + *
61.97 + * <li> {@code lazySet} has the memory effects of writing (assigning)
61.98 + * a {@code volatile} variable except that it permits reorderings with
61.99 + * subsequent (but not previous) memory actions that do not themselves
61.100 + * impose reordering constraints with ordinary non-{@code volatile}
61.101 + * writes. Among other usage contexts, {@code lazySet} may apply when
61.102 + * nulling out, for the sake of garbage collection, a reference that is
61.103 + * never accessed again.
61.104 + *
61.105 + * <li>{@code weakCompareAndSet} atomically reads and conditionally
61.106 + * writes a variable but does <em>not</em>
61.107 + * create any happens-before orderings, so provides no guarantees
61.108 + * with respect to previous or subsequent reads and writes of any
61.109 + * variables other than the target of the {@code weakCompareAndSet}.
61.110 + *
61.111 + * <li> {@code compareAndSet}
61.112 + * and all other read-and-update operations such as {@code getAndIncrement}
61.113 + * have the memory effects of both reading and
61.114 + * writing {@code volatile} variables.
61.115 + * </ul>
61.116 + *
61.117 + * <p>In addition to classes representing single values, this package
61.118 + * contains <em>Updater</em> classes that can be used to obtain
61.119 + * {@code compareAndSet} operations on any selected {@code volatile}
61.120 + * field of any selected class.
61.121 + *
61.122 + * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
61.123 + * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
61.124 + * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
61.125 + * reflection-based utilities that provide access to the associated
61.126 + * field types. These are mainly of use in atomic data structures in
61.127 + * which several {@code volatile} fields of the same node (for
61.128 + * example, the links of a tree node) are independently subject to
61.129 + * atomic updates. These classes enable greater flexibility in how
61.130 + * and when to use atomic updates, at the expense of more awkward
61.131 + * reflection-based setup, less convenient usage, and weaker
61.132 + * guarantees.
61.133 + *
61.134 + * <p>The
61.135 + * {@link java.util.concurrent.atomic.AtomicIntegerArray},
61.136 + * {@link java.util.concurrent.atomic.AtomicLongArray}, and
61.137 + * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
61.138 + * further extend atomic operation support to arrays of these types.
61.139 + * These classes are also notable in providing {@code volatile} access
61.140 + * semantics for their array elements, which is not supported for
61.141 + * ordinary arrays.
61.142 + *
61.143 + * <a name="Spurious">
61.144 + * <p>The atomic classes also support method {@code weakCompareAndSet},
61.145 + * which has limited applicability. On some platforms, the weak version
61.146 + * may be more efficient than {@code compareAndSet} in the normal case,
61.147 + * but differs in that any given invocation of the
61.148 + * {@code weakCompareAndSet} method may return {@code false}
61.149 + * <em>spuriously</em> (that is, for no apparent reason)</a>. A
61.150 + * {@code false} return means only that the operation may be retried if
61.151 + * desired, relying on the guarantee that repeated invocation when the
61.152 + * variable holds {@code expectedValue} and no other thread is also
61.153 + * attempting to set the variable will eventually succeed. (Such
61.154 + * spurious failures may for example be due to memory contention effects
61.155 + * that are unrelated to whether the expected and current values are
61.156 + * equal.) Additionally {@code weakCompareAndSet} does not provide
61.157 + * ordering guarantees that are usually needed for synchronization
61.158 + * control. However, the method may be useful for updating counters and
61.159 + * statistics when such updates are unrelated to the other
61.160 + * happens-before orderings of a program. When a thread sees an update
61.161 + * to an atomic variable caused by a {@code weakCompareAndSet}, it does
61.162 + * not necessarily see updates to any <em>other</em> variables that
61.163 + * occurred before the {@code weakCompareAndSet}. This may be
61.164 + * acceptable when, for example, updating performance statistics, but
61.165 + * rarely otherwise.
61.166 + *
61.167 + * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
61.168 + * class associates a single boolean with a reference. For example, this
61.169 + * bit might be used inside a data structure to mean that the object
61.170 + * being referenced has logically been deleted.
61.171 + *
61.172 + * The {@link java.util.concurrent.atomic.AtomicStampedReference}
61.173 + * class associates an integer value with a reference. This may be
61.174 + * used for example, to represent version numbers corresponding to
61.175 + * series of updates.
61.176 + *
61.177 + * <p>Atomic classes are designed primarily as building blocks for
61.178 + * implementing non-blocking data structures and related infrastructure
61.179 + * classes. The {@code compareAndSet} method is not a general
61.180 + * replacement for locking. It applies only when critical updates for an
61.181 + * object are confined to a <em>single</em> variable.
61.182 + *
61.183 + * <p>Atomic classes are not general purpose replacements for
61.184 + * {@code java.lang.Integer} and related classes. They do <em>not</em>
61.185 + * define methods such as {@code hashCode} and
61.186 + * {@code compareTo}. (Because atomic variables are expected to be
61.187 + * mutated, they are poor choices for hash table keys.) Additionally,
61.188 + * classes are provided only for those types that are commonly useful in
61.189 + * intended applications. For example, there is no atomic class for
61.190 + * representing {@code byte}. In those infrequent cases where you would
61.191 + * like to do so, you can use an {@code AtomicInteger} to hold
61.192 + * {@code byte} values, and cast appropriately.
61.193 + *
61.194 + * You can also hold floats using
61.195 + * {@link java.lang.Float#floatToIntBits} and
61.196 + * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
61.197 + * {@link java.lang.Double#doubleToLongBits} and
61.198 + * {@link java.lang.Double#longBitsToDouble} conversions.
61.199 + *
61.200 + * @since 1.5
61.201 + */
61.202 +package java.util.concurrent.atomic;